diff options
author | Lukas Wunner <lukas@wunner.de> | 2016-10-23 07:55:34 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-11-07 07:06:59 -0500 |
commit | e8a6123e9ead1b0d40349809e51de9341312fe08 (patch) | |
tree | e47e737f5f2ade2f28c28db1a93bc90c47949cd2 | |
parent | bc33b0ca11e3df467777a4fa7639ba488c9d4911 (diff) |
x86/platform/intel-mid: Retrofit pci_platform_pm_ops ->get_state hook
Commit cc7cc02bada8 ("PCI: Query platform firmware for device power
state") augmented struct pci_platform_pm_ops with a ->get_state hook and
implemented it for acpi_pci_platform_pm, the only pci_platform_pm_ops
existing till v4.7.
However v4.8 introduced another pci_platform_pm_ops for Intel Mobile
Internet Devices with commit 5823d0893ec2 ("x86/platform/intel-mid: Add
Power Management Unit driver"). It is missing the ->get_state hook,
which is fatal since pci_set_platform_pm() enforces its presence. Andy
Shevchenko reports that without the present commit, such a device
"crashes without even a character printed out on serial console and
reboots (since watchdog)".
Retrofit mid_pci_platform_pm with the missing callback to fix the
breakage.
Acked-and-tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Fixes: cc7cc02bada8 ("PCI: Query platform firmware for device power state")
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-pci@vger.kernel.org
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: http://lkml.kernel.org/r/7c1567d4c49303a4aada94ba16275cbf56b8976b.1477221514.git.lukas@wunner.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/include/asm/intel-mid.h | 1 | ||||
-rw-r--r-- | arch/x86/platform/intel-mid/pwr.c | 19 | ||||
-rw-r--r-- | drivers/pci/pci-mid.c | 6 |
3 files changed, 26 insertions, 0 deletions
diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h index 5b6753d1f7f4..49da9f497b90 100644 --- a/arch/x86/include/asm/intel-mid.h +++ b/arch/x86/include/asm/intel-mid.h | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | extern int intel_mid_pci_init(void); | 18 | extern int intel_mid_pci_init(void); |
19 | extern int intel_mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state); | 19 | extern int intel_mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state); |
20 | extern pci_power_t intel_mid_pci_get_power_state(struct pci_dev *pdev); | ||
20 | 21 | ||
21 | extern void intel_mid_pwr_power_off(void); | 22 | extern void intel_mid_pwr_power_off(void); |
22 | 23 | ||
diff --git a/arch/x86/platform/intel-mid/pwr.c b/arch/x86/platform/intel-mid/pwr.c index 5d3b45ad1c03..67375dda451c 100644 --- a/arch/x86/platform/intel-mid/pwr.c +++ b/arch/x86/platform/intel-mid/pwr.c | |||
@@ -272,6 +272,25 @@ int intel_mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state) | |||
272 | } | 272 | } |
273 | EXPORT_SYMBOL_GPL(intel_mid_pci_set_power_state); | 273 | EXPORT_SYMBOL_GPL(intel_mid_pci_set_power_state); |
274 | 274 | ||
275 | pci_power_t intel_mid_pci_get_power_state(struct pci_dev *pdev) | ||
276 | { | ||
277 | struct mid_pwr *pwr = midpwr; | ||
278 | int id, reg, bit; | ||
279 | u32 power; | ||
280 | |||
281 | if (!pwr || !pwr->available) | ||
282 | return PCI_UNKNOWN; | ||
283 | |||
284 | id = intel_mid_pwr_get_lss_id(pdev); | ||
285 | if (id < 0) | ||
286 | return PCI_UNKNOWN; | ||
287 | |||
288 | reg = (id * LSS_PWS_BITS) / 32; | ||
289 | bit = (id * LSS_PWS_BITS) % 32; | ||
290 | power = mid_pwr_get_state(pwr, reg); | ||
291 | return (__force pci_power_t)((power >> bit) & 3); | ||
292 | } | ||
293 | |||
275 | void intel_mid_pwr_power_off(void) | 294 | void intel_mid_pwr_power_off(void) |
276 | { | 295 | { |
277 | struct mid_pwr *pwr = midpwr; | 296 | struct mid_pwr *pwr = midpwr; |
diff --git a/drivers/pci/pci-mid.c b/drivers/pci/pci-mid.c index 55f453de562e..c7f3408e3148 100644 --- a/drivers/pci/pci-mid.c +++ b/drivers/pci/pci-mid.c | |||
@@ -29,6 +29,11 @@ static int mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state) | |||
29 | return intel_mid_pci_set_power_state(pdev, state); | 29 | return intel_mid_pci_set_power_state(pdev, state); |
30 | } | 30 | } |
31 | 31 | ||
32 | static pci_power_t mid_pci_get_power_state(struct pci_dev *pdev) | ||
33 | { | ||
34 | return intel_mid_pci_get_power_state(pdev); | ||
35 | } | ||
36 | |||
32 | static pci_power_t mid_pci_choose_state(struct pci_dev *pdev) | 37 | static pci_power_t mid_pci_choose_state(struct pci_dev *pdev) |
33 | { | 38 | { |
34 | return PCI_D3hot; | 39 | return PCI_D3hot; |
@@ -52,6 +57,7 @@ static bool mid_pci_need_resume(struct pci_dev *dev) | |||
52 | static struct pci_platform_pm_ops mid_pci_platform_pm = { | 57 | static struct pci_platform_pm_ops mid_pci_platform_pm = { |
53 | .is_manageable = mid_pci_power_manageable, | 58 | .is_manageable = mid_pci_power_manageable, |
54 | .set_state = mid_pci_set_power_state, | 59 | .set_state = mid_pci_set_power_state, |
60 | .get_state = mid_pci_get_power_state, | ||
55 | .choose_state = mid_pci_choose_state, | 61 | .choose_state = mid_pci_choose_state, |
56 | .sleep_wake = mid_pci_sleep_wake, | 62 | .sleep_wake = mid_pci_sleep_wake, |
57 | .run_wake = mid_pci_run_wake, | 63 | .run_wake = mid_pci_run_wake, |