summaryrefslogtreecommitdiff
path: root/SOURCES/asus-linux.patch
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2023-03-08 12:34:14 +0100
committerJan200101 <sentrycraft123@gmail.com>2023-03-08 12:34:14 +0100
commit07e8ea2c4e1d6adbbaf50e057951b6d6bfea4520 (patch)
tree377a8b32250d5733f4725562d8c9068d778dcc09 /SOURCES/asus-linux.patch
parentee96a395d2478e48ebf47a6a9eb0540ffacd2264 (diff)
downloadkernel-fsync-07e8ea2c4e1d6adbbaf50e057951b6d6bfea4520.tar.gz
kernel-fsync-07e8ea2c4e1d6adbbaf50e057951b6d6bfea4520.zip
kernel 6.1.15 asus, lenovo patches
Diffstat (limited to 'SOURCES/asus-linux.patch')
-rw-r--r--SOURCES/asus-linux.patch438
1 files changed, 438 insertions, 0 deletions
diff --git a/SOURCES/asus-linux.patch b/SOURCES/asus-linux.patch
new file mode 100644
index 0000000..1580454
--- /dev/null
+++ b/SOURCES/asus-linux.patch
@@ -0,0 +1,438 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jan200101 <sentrycraft123@gmail.com>
+Date: Wed, 8 Mar 2023 08:26:17 +0100
+Subject: [PATCH] asus-linux This patch adds support for the tablet mode switch
+ sensors on convertible devices where that sensor is managed by AMD SFH, like
+ the Asus Flow X13 and the Lenovo ThinkPad L13 Yoga Gen2 (AMD).
+
+Co-developed-by: Ivan Dovgal <iv.dovg@gmail.com>
+Signed-off-by: Ivan Dovgal <iv.dovg@gmail.com>
+Co-developed-by: Luke D. Jones <luke@ljones.dev>
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Signed-off-by: Adrian Freund <adrian@freund.io>
+---
+v2:
+* Fixed build warning reported by kernel test robot <lkp@intel.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
+---
+ drivers/hid/amd-sfh-hid/amd_sfh_client.c | 2 +
+ drivers/hid/amd-sfh-hid/amd_sfh_hid.h | 2 +-
+ drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 4 +
+ drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 1 +
+ .../hid_descriptor/amd_sfh_hid_desc.c | 27 ++++++
+ .../hid_descriptor/amd_sfh_hid_desc.h | 7 ++
+ .../hid_descriptor/amd_sfh_hid_report_desc.h | 21 ++++
+ drivers/pci/controller/vmd.c | 96 ++++++++++++++-----
+ drivers/pci/pcie/aspm.c | 54 +++++++++++
+ include/linux/pci.h | 7 ++
+ 10 files changed, 194 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
+index c751d12f5..690be680e 100644
+--- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c
++++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
+@@ -146,6 +146,8 @@ static const char *get_sensor_name(int idx)
+ return "gyroscope";
+ case mag_idx:
+ return "magnetometer";
++ case tms_idx:
++ return "tablet-mode-switch";
+ case als_idx:
+ return "ALS";
+ case HPD_IDX:
+diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
+index 528036892..97296f587 100644
+--- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
++++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
+@@ -11,7 +11,7 @@
+ #ifndef AMDSFH_HID_H
+ #define AMDSFH_HID_H
+
+-#define MAX_HID_DEVICES 5
++#define MAX_HID_DEVICES 6
+ #define AMD_SFH_HID_VENDOR 0x1022
+ #define AMD_SFH_HID_PRODUCT 0x0001
+
+diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+index 47774b9ab..cfda797f0 100644
+--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
++++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+@@ -27,6 +27,7 @@
+ #define ACEL_EN BIT(0)
+ #define GYRO_EN BIT(1)
+ #define MAGNO_EN BIT(2)
++#define TMS_EN BIT(15)
+ #define HPD_EN BIT(16)
+ #define ALS_EN BIT(19)
+
+@@ -227,6 +228,9 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
+ if (MAGNO_EN & activestatus)
+ sensor_id[num_of_sensors++] = mag_idx;
+
++ if (TMS_EN & activestatus)
++ sensor_id[num_of_sensors++] = tms_idx;
++
+ if (ALS_EN & activestatus)
+ sensor_id[num_of_sensors++] = als_idx;
+
+diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+index dfb7cabd8..e18ceee9e 100644
+--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
++++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+@@ -78,6 +78,7 @@ enum sensor_idx {
+ accel_idx = 0,
+ gyro_idx = 1,
+ mag_idx = 2,
++ tms_idx = 15,
+ als_idx = 19
+ };
+
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
+index f9a8c02d5..181973f35 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
+@@ -47,6 +47,11 @@ static int get_report_descriptor(int sensor_idx, u8 *rep_desc)
+ memcpy(rep_desc, comp3_report_descriptor,
+ sizeof(comp3_report_descriptor));
+ break;
++ case tms_idx: /* tablet mode switch */
++ memset(rep_desc, 0, sizeof(tms_report_descriptor));
++ memcpy(rep_desc, tms_report_descriptor,
++ sizeof(tms_report_descriptor));
++ break;
+ case als_idx: /* ambient light sensor */
+ memset(rep_desc, 0, sizeof(als_report_descriptor));
+ memcpy(rep_desc, als_report_descriptor,
+@@ -96,6 +101,16 @@ static u32 get_descr_sz(int sensor_idx, int descriptor_name)
+ return sizeof(struct magno_feature_report);
+ }
+ break;
++ case tms_idx:
++ switch (descriptor_name) {
++ case descr_size:
++ return sizeof(tms_report_descriptor);
++ case input_size:
++ return sizeof(struct tms_input_report);
++ case feature_size:
++ return sizeof(struct tms_feature_report);
++ }
++ break;
+ case als_idx:
+ switch (descriptor_name) {
+ case descr_size:
+@@ -138,6 +153,7 @@ static u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
+ struct accel3_feature_report acc_feature;
+ struct gyro_feature_report gyro_feature;
+ struct magno_feature_report magno_feature;
++ struct tms_feature_report tms_feature;
+ struct hpd_feature_report hpd_feature;
+ struct als_feature_report als_feature;
+ u8 report_size = 0;
+@@ -173,6 +189,11 @@ static u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
+ memcpy(feature_report, &magno_feature, sizeof(magno_feature));
+ report_size = sizeof(magno_feature);
+ break;
++ case tms_idx: /* tablet mode switch */
++ get_common_features(&tms_feature.common_property, report_id);
++ memcpy(feature_report, &tms_feature, sizeof(tms_feature));
++ report_size = sizeof(tms_feature);
++ break;
+ case als_idx: /* ambient light sensor */
+ get_common_features(&als_feature.common_property, report_id);
+ als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
+@@ -211,6 +232,7 @@ static u8 get_input_report(u8 current_index, int sensor_idx, int report_id,
+ struct accel3_input_report acc_input;
+ struct gyro_input_report gyro_input;
+ struct hpd_input_report hpd_input;
++ struct tms_input_report tms_input;
+ struct als_input_report als_input;
+ struct hpd_status hpdstatus;
+ u8 report_size = 0;
+@@ -244,6 +266,11 @@ static u8 get_input_report(u8 current_index, int sensor_idx, int report_id,
+ memcpy(input_report, &magno_input, sizeof(magno_input));
+ report_size = sizeof(magno_input);
+ break;
++ case tms_idx: /* tablet mode switch */
++ get_common_inputs(&tms_input.common_property, report_id);
++ report_size = sizeof(tms_input);
++ memcpy(input_report, &tms_input, sizeof(tms_input));
++ break;
+ case als_idx: /* Als */
+ get_common_inputs(&als_input.common_property, report_id);
+ /* For ALS ,V2 Platforms uses C2P_MSG5 register instead of DRAM access method */
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
+index ebd55675e..b22068a47 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
+@@ -111,4 +111,11 @@ struct hpd_input_report {
+ u8 human_presence;
+ } __packed;
+
++struct tms_feature_report {
++ struct common_feature_property common_property;
++} __packed;
++
++struct tms_input_report {
++ struct common_input_property common_property;
++} __packed;
+ #endif
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
+index 697f2791e..96cbc1e5b 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
+@@ -644,6 +644,27 @@ static const u8 als_report_descriptor[] = {
+ 0xC0 /* HID end collection */
+ };
+
++
++/* TABLET MODE SWITCH */
++__maybe_unused // Used by sfh1.0, but not yet implemented in sfh1.1
++static const u8 tms_report_descriptor[] = {
++0x06, 0x43, 0xFF, // Usage Page (Vendor Defined 0xFF43)
++0x0A, 0x02, 0x02, // Usage (0x0202)
++0xA1, 0x01, // Collection (Application)
++0x85, 0x11, // Report ID (17)
++0x15, 0x00, // Logical Minimum (0)
++0x25, 0x01, // Logical Maximum (1)
++0x35, 0x00, // Physical Minimum (0)
++0x45, 0x01, // Physical Maximum (1)
++0x65, 0x00, // Unit (None)
++0x55, 0x00, // Unit Exponent (0)
++0x75, 0x01, // Report Size (1)
++0x95, 0x98, // Report Count (-104)
++0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
++0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
++0xC1, 0x00, // End Collection
++};
++
+ /* BIOMETRIC PRESENCE*/
+ static const u8 hpd_report_descriptor[] = {
+ 0x05, 0x20, /* Usage page */
+diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
+index 769eedeb8..900bf82dc 100644
+--- a/drivers/pci/controller/vmd.c
++++ b/drivers/pci/controller/vmd.c
+@@ -66,8 +66,22 @@ enum vmd_features {
+ * interrupt handling.
+ */
+ VMD_FEAT_CAN_BYPASS_MSI_REMAP = (1 << 4),
++
++ /*
++ * Enable ASPM on the PCIE root ports and set the default LTR of the
++ * storage devices on platforms where these values are not configured by
++ * BIOS. This is needed for laptops, which require these settings for
++ * proper power management of the SoC.
++ */
++ VMD_FEAT_BIOS_PM_QUIRK = (1 << 5),
+ };
+
++#define VMD_FEATS_CLIENT (VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | \
++ VMD_FEAT_HAS_BUS_RESTRICTIONS | \
++ VMD_FEAT_OFFSET_FIRST_VECTOR)
++
++#define VMD_BIOS_PM_QUIRK_LTR 0x1003 /* 3145728 ns */
++
+ static DEFINE_IDA(vmd_instance_ida);
+
+ /*
+@@ -709,6 +723,46 @@ static void vmd_copy_host_bridge_flags(struct pci_host_bridge *root_bridge,
+ vmd_bridge->native_dpc = root_bridge->native_dpc;
+ }
+
++/*
++ * Enable ASPM and LTR settings on devices that aren't configured by BIOS.
++ */
++static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
++{
++ unsigned long features = *(unsigned long *)userdata;
++ u16 ltr = VMD_BIOS_PM_QUIRK_LTR;
++ u32 ltr_reg;
++ int pos;
++
++ if (!(features & VMD_FEAT_BIOS_PM_QUIRK))
++ return 0;
++
++ pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
++
++ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR);
++ if (!pos)
++ return 0;
++
++ /*
++ * Skip if the max snoop LTR is non-zero, indicating BIOS has set it
++ * so the LTR quirk is not needed.
++ */
++ pci_read_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, &ltr_reg);
++ if (!!(ltr_reg & (PCI_LTR_VALUE_MASK | PCI_LTR_SCALE_MASK)))
++ return 0;
++
++ /*
++ * Set the default values to the maximum required by the platform to
++ * allow the deepest power management savings. Write as a DWORD where
++ * the lower word is the max snoop latency and the upper word is the
++ * max non-snoop latency.
++ */
++ ltr_reg = (ltr << 16) | ltr;
++ pci_write_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, ltr_reg);
++ pci_info(pdev, "VMD: Default LTR value set by driver\n");
++
++ return 0;
++}
++
+ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
+ {
+ struct pci_sysdata *sd = &vmd->sysdata;
+@@ -881,6 +935,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
+
+ pci_assign_unassigned_bus_resources(vmd->bus);
+
++ pci_walk_bus(vmd->bus, vmd_pm_enable_quirk, &features);
++
+ /*
+ * VMD root buses are virtual and don't return true on pci_is_pcie()
+ * and will fail pcie_bus_configure_settings() early. It can instead be
+@@ -1017,36 +1073,24 @@ static int vmd_resume(struct device *dev)
+ static SIMPLE_DEV_PM_OPS(vmd_dev_pm_ops, vmd_suspend, vmd_resume);
+
+ static const struct pci_device_id vmd_ids[] = {
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),
++ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),
+ .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP,},
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
++ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
+ .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
+ VMD_FEAT_HAS_BUS_RESTRICTIONS |
+ VMD_FEAT_CAN_BYPASS_MSI_REMAP,},
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
+- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+- VMD_FEAT_HAS_BUS_RESTRICTIONS |
+- VMD_FEAT_OFFSET_FIRST_VECTOR,},
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
+- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+- VMD_FEAT_HAS_BUS_RESTRICTIONS |
+- VMD_FEAT_OFFSET_FIRST_VECTOR,},
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa77f),
+- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+- VMD_FEAT_HAS_BUS_RESTRICTIONS |
+- VMD_FEAT_OFFSET_FIRST_VECTOR,},
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7d0b),
+- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+- VMD_FEAT_HAS_BUS_RESTRICTIONS |
+- VMD_FEAT_OFFSET_FIRST_VECTOR,},
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xad0b),
+- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+- VMD_FEAT_HAS_BUS_RESTRICTIONS |
+- VMD_FEAT_OFFSET_FIRST_VECTOR,},
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
+- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+- VMD_FEAT_HAS_BUS_RESTRICTIONS |
+- VMD_FEAT_OFFSET_FIRST_VECTOR,},
++ {PCI_VDEVICE(INTEL, 0x467f),
++ .driver_data = VMD_FEATS_CLIENT | VMD_FEAT_BIOS_PM_QUIRK,},
++ {PCI_VDEVICE(INTEL, 0x4c3d),
++ .driver_data = VMD_FEATS_CLIENT | VMD_FEAT_BIOS_PM_QUIRK,},
++ {PCI_VDEVICE(INTEL, 0xa77f),
++ .driver_data = VMD_FEATS_CLIENT | VMD_FEAT_BIOS_PM_QUIRK,},
++ {PCI_VDEVICE(INTEL, 0x7d0b),
++ .driver_data = VMD_FEATS_CLIENT | VMD_FEAT_BIOS_PM_QUIRK,},
++ {PCI_VDEVICE(INTEL, 0xad0b),
++ .driver_data = VMD_FEATS_CLIENT | VMD_FEAT_BIOS_PM_QUIRK,},
++ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
++ .driver_data = VMD_FEATS_CLIENT | VMD_FEAT_BIOS_PM_QUIRK,},
+ {0,}
+ };
+ MODULE_DEVICE_TABLE(pci, vmd_ids);
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index 4b4184563..66d7514ca 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -1138,6 +1138,60 @@ int pci_disable_link_state(struct pci_dev *pdev, int state)
+ }
+ EXPORT_SYMBOL(pci_disable_link_state);
+
++/**
++ * pci_enable_link_state - Clear and set the default device link state so that
++ * the link may be allowed to enter the specified states. Note that if the
++ * BIOS didn't grant ASPM control to the OS, this does nothing because we can't
++ * touch the LNKCTL register. Also note that this does not enable states
++ * disabled by pci_disable_link_state(). Return 0 or a negative errno.
++ *
++ * @pdev: PCI device
++ * @state: Mask of ASPM link states to enable
++ */
++int pci_enable_link_state(struct pci_dev *pdev, int state)
++{
++ struct pcie_link_state *link = pcie_aspm_get_link(pdev);
++
++ if (!link)
++ return -EINVAL;
++ /*
++ * A driver requested that ASPM be enabled on this device, but
++ * if we don't have permission to manage ASPM (e.g., on ACPI
++ * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and
++ * the _OSC method), we can't honor that request.
++ */
++ if (aspm_disabled) {
++ pci_warn(pdev, "can't override BIOS ASPM; OS doesn't have ASPM control\n");
++ return -EPERM;
++ }
++
++ down_read(&pci_bus_sem);
++ mutex_lock(&aspm_lock);
++ link->aspm_default = 0;
++ if (state & PCIE_LINK_STATE_L0S)
++ link->aspm_default |= ASPM_STATE_L0S;
++ if (state & PCIE_LINK_STATE_L1)
++ /* L1 PM substates require L1 */
++ link->aspm_default |= ASPM_STATE_L1 | ASPM_STATE_L1SS;
++ if (state & PCIE_LINK_STATE_L1_1)
++ link->aspm_default |= ASPM_STATE_L1_1;
++ if (state & PCIE_LINK_STATE_L1_2)
++ link->aspm_default |= ASPM_STATE_L1_2;
++ if (state & PCIE_LINK_STATE_L1_1_PCIPM)
++ link->aspm_default |= ASPM_STATE_L1_1_PCIPM;
++ if (state & PCIE_LINK_STATE_L1_2_PCIPM)
++ link->aspm_default |= ASPM_STATE_L1_2_PCIPM;
++ pcie_config_aspm_link(link, policy_to_aspm_state(link));
++
++ link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0;
++ pcie_set_clkpm(link, policy_to_clkpm_state(link));
++ mutex_unlock(&aspm_lock);
++ up_read(&pci_bus_sem);
++
++ return 0;
++}
++EXPORT_SYMBOL(pci_enable_link_state);
++
+ static int pcie_aspm_set_policy(const char *val,
+ const struct kernel_param *kp)
+ {
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 2bda4a4e4..8c35f15e6 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -1651,10 +1651,15 @@ extern bool pcie_ports_native;
+ #define PCIE_LINK_STATE_L1_2 BIT(4)
+ #define PCIE_LINK_STATE_L1_1_PCIPM BIT(5)
+ #define PCIE_LINK_STATE_L1_2_PCIPM BIT(6)
++#define PCIE_LINK_STATE_ALL (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |\
++ PCIE_LINK_STATE_CLKPM | PCIE_LINK_STATE_L1_1 |\
++ PCIE_LINK_STATE_L1_2 | PCIE_LINK_STATE_L1_1_PCIPM |\
++ PCIE_LINK_STATE_L1_2_PCIPM)
+
+ #ifdef CONFIG_PCIEASPM
+ int pci_disable_link_state(struct pci_dev *pdev, int state);
+ int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
++int pci_enable_link_state(struct pci_dev *pdev, int state);
+ void pcie_no_aspm(void);
+ bool pcie_aspm_support_enabled(void);
+ bool pcie_aspm_enabled(struct pci_dev *pdev);
+@@ -1663,6 +1668,8 @@ static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
+ { return 0; }
+ static inline int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
+ { return 0; }
++static inline int pci_enable_link_state(struct pci_dev *pdev, int state)
++{ return 0; }
+ static inline void pcie_no_aspm(void) { }
+ static inline bool pcie_aspm_support_enabled(void) { return false; }
+ static inline bool pcie_aspm_enabled(struct pci_dev *pdev) { return false; }