diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2017-07-02 18:48:49 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-07-02 18:48:49 -0500 |
commit | 2cf816a947e0f729825a1bb73d2eed6255c29f88 (patch) | |
tree | 68cd933694029bd2f4a47973038ce0662ae47828 /drivers/pci | |
parent | 6a1c1d553ebf4e4241c0b1e20517a67e36d46c12 (diff) | |
parent | 666ff6f83e1db6ed847abf44eb5e3402d82b9350 (diff) | |
download | lwn-2cf816a947e0f729825a1bb73d2eed6255c29f88.tar.gz lwn-2cf816a947e0f729825a1bb73d2eed6255c29f88.zip |
Merge branch 'pci/pm' into next
* pci/pm:
PCI/PM: Avoid using device_may_wakeup() for runtime PM
x86/PCI: Avoid AMD SB7xx EHCI USB wakeup defect
PCI/PM: Restore the status of PCI devices across hibernation
drm/radeon: make MacBook Pro d3_delay quirk more generic
drm/amdgpu: remove unnecessary save/restore of pdev->d3_delay
PCI/PM: Add needs_resume flag to avoid suspend complete optimization
PCI: imx6: Fix config read timeout handling
switchtec: Fix minor bug with partition ID register
switchtec: Use new cdev_device_add() helper function
PCI: endpoint: Make PCI_ENDPOINT depend on HAS_DMA
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/dwc/pci-imx6.c | 33 | ||||
-rw-r--r-- | drivers/pci/endpoint/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 1 | ||||
-rw-r--r-- | drivers/pci/pci.c | 25 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 13 | ||||
-rw-r--r-- | drivers/pci/switch/switchtec.c | 16 |
6 files changed, 66 insertions, 23 deletions
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c index a98cba55c7f0..19a289b8cc94 100644 --- a/drivers/pci/dwc/pci-imx6.c +++ b/drivers/pci/dwc/pci-imx6.c @@ -252,7 +252,34 @@ static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie) static int imx6q_pcie_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { - return 0; + unsigned long pc = instruction_pointer(regs); + unsigned long instr = *(unsigned long *)pc; + int reg = (instr >> 12) & 15; + + /* + * If the instruction being executed was a read, + * make it look like it read all-ones. + */ + if ((instr & 0x0c100000) == 0x04100000) { + unsigned long val; + + if (instr & 0x00400000) + val = 255; + else + val = -1; + + regs->uregs[reg] = val; + regs->ARM_pc += 4; + return 0; + } + + if ((instr & 0x0e100090) == 0x00100090) { + regs->uregs[reg] = -1; + regs->ARM_pc += 4; + return 0; + } + + return 1; } static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) @@ -819,8 +846,8 @@ static int __init imx6_pcie_init(void) * we can install the handler here without risking it * accessing some uninitialized driver state. */ - hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, - "imprecise external abort"); + hook_fault_code(8, imx6q_pcie_abort_handler, SIGBUS, 0, + "external abort on non-linefetch"); return platform_driver_register(&imx6_pcie_driver); } diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig index c23f146fb5a6..c09623ca8c3b 100644 --- a/drivers/pci/endpoint/Kconfig +++ b/drivers/pci/endpoint/Kconfig @@ -6,6 +6,7 @@ menu "PCI Endpoint" config PCI_ENDPOINT bool "PCI Endpoint Support" + depends on HAS_DMA help Enable this configuration option to support configurable PCI endpoint. This should be enabled if the platform has a PCI diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 192e7b681b96..b399fa31e0a2 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -964,6 +964,7 @@ static int pci_pm_thaw_noirq(struct device *dev) return pci_legacy_resume_early(dev); pci_update_current_state(pci_dev, PCI_D0); + pci_restore_state(pci_dev); if (drv && drv->pm && drv->pm->thaw_noirq) error = drv->pm->thaw_noirq(dev); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7c4e1aa67c67..59f29e3da4bc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1960,12 +1960,13 @@ EXPORT_SYMBOL(pci_wake_from_d3); /** * pci_target_state - find an appropriate low power state for a given PCI dev * @dev: PCI device + * @wakeup: Whether or not wakeup functionality will be enabled for the device. * * Use underlying platform code to find a supported low power state for @dev. * If the platform can't manage @dev, return the deepest state from which it * can generate wake events, based on any available PME info. */ -static pci_power_t pci_target_state(struct pci_dev *dev) +static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup) { pci_power_t target_state = PCI_D3hot; @@ -2002,7 +2003,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev) if (dev->current_state == PCI_D3cold) target_state = PCI_D3cold; - if (device_may_wakeup(&dev->dev)) { + if (wakeup) { /* * Find the deepest state from which the device can generate * wake-up events, make it the target state and enable device @@ -2028,13 +2029,14 @@ static pci_power_t pci_target_state(struct pci_dev *dev) */ int pci_prepare_to_sleep(struct pci_dev *dev) { - pci_power_t target_state = pci_target_state(dev); + bool wakeup = device_may_wakeup(&dev->dev); + pci_power_t target_state = pci_target_state(dev, wakeup); int error; if (target_state == PCI_POWER_ERROR) return -EIO; - pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); + pci_enable_wake(dev, target_state, wakeup); error = pci_set_power_state(dev, target_state); @@ -2067,9 +2069,10 @@ EXPORT_SYMBOL(pci_back_from_sleep); */ int pci_finish_runtime_suspend(struct pci_dev *dev) { - pci_power_t target_state = pci_target_state(dev); + pci_power_t target_state; int error; + target_state = pci_target_state(dev, device_can_wakeup(&dev->dev)); if (target_state == PCI_POWER_ERROR) return -EIO; @@ -2105,8 +2108,8 @@ bool pci_dev_run_wake(struct pci_dev *dev) if (!dev->pme_support) return false; - /* PME-capable in principle, but not from the intended sleep state */ - if (!pci_pme_capable(dev, pci_target_state(dev))) + /* PME-capable in principle, but not from the target power state */ + if (!pci_pme_capable(dev, pci_target_state(dev, false))) return false; while (bus->parent) { @@ -2141,10 +2144,12 @@ EXPORT_SYMBOL_GPL(pci_dev_run_wake); bool pci_dev_keep_suspended(struct pci_dev *pci_dev) { struct device *dev = &pci_dev->dev; + bool wakeup = device_may_wakeup(dev); if (!pm_runtime_suspended(dev) - || pci_target_state(pci_dev) != pci_dev->current_state - || platform_pci_need_resume(pci_dev)) + || pci_target_state(pci_dev, wakeup) != pci_dev->current_state + || platform_pci_need_resume(pci_dev) + || (pci_dev->dev_flags & PCI_DEV_FLAGS_NEEDS_RESUME)) return false; /* @@ -2160,7 +2165,7 @@ bool pci_dev_keep_suspended(struct pci_dev *pci_dev) spin_lock_irq(&dev->power.lock); if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold && - !device_may_wakeup(dev)) + !wakeup) __pci_pme_active(pci_dev, false); spin_unlock_irq(&dev->power.lock); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 16e6cd86ad71..e1deb796976a 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1684,6 +1684,19 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm); +static void quirk_radeon_pm(struct pci_dev *dev) +{ + if (dev->subsystem_vendor == PCI_VENDOR_ID_APPLE && + dev->subsystem_device == 0x00e2) { + if (dev->d3_delay < 20) { + dev->d3_delay = 20; + dev_info(&dev->dev, "extending delay after power-on from D3 to %d msec\n", + dev->d3_delay); + } + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6741, quirk_radeon_pm); + #ifdef CONFIG_X86_IO_APIC static int dmi_disable_ioapicreroute(const struct dmi_system_id *d) { diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index cc6e085008fb..f6a63406c76e 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1291,7 +1291,6 @@ static struct switchtec_dev *stdev_create(struct pci_dev *pdev) cdev = &stdev->cdev; cdev_init(cdev, &switchtec_fops); cdev->owner = THIS_MODULE; - cdev->kobj.parent = &dev->kobj; return stdev; @@ -1442,12 +1441,15 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET; stdev->mmio_ntb = stdev->mmio + SWITCHTEC_GAS_NTB_OFFSET; - stdev->partition = ioread8(&stdev->mmio_ntb->partition_id); + stdev->partition = ioread8(&stdev->mmio_sys_info->partition_id); stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count); stdev->mmio_part_cfg_all = stdev->mmio + SWITCHTEC_GAS_PART_CFG_OFFSET; stdev->mmio_part_cfg = &stdev->mmio_part_cfg_all[stdev->partition]; stdev->mmio_pff_csr = stdev->mmio + SWITCHTEC_GAS_PFF_CSR_OFFSET; + if (stdev->partition_count < 1) + stdev->partition_count = 1; + init_pff(stdev); pci_set_drvdata(pdev, stdev); @@ -1479,11 +1481,7 @@ static int switchtec_pci_probe(struct pci_dev *pdev, SWITCHTEC_EVENT_EN_IRQ, &stdev->mmio_part_cfg->mrpc_comp_hdr); - rc = cdev_add(&stdev->cdev, stdev->dev.devt, 1); - if (rc) - goto err_put; - - rc = device_add(&stdev->dev); + rc = cdev_device_add(&stdev->cdev, &stdev->dev); if (rc) goto err_devadd; @@ -1492,7 +1490,6 @@ static int switchtec_pci_probe(struct pci_dev *pdev, return 0; err_devadd: - cdev_del(&stdev->cdev); stdev_kill(stdev); err_put: ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); @@ -1506,8 +1503,7 @@ static void switchtec_pci_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); - device_del(&stdev->dev); - cdev_del(&stdev->cdev); + cdev_device_del(&stdev->cdev, &stdev->dev); ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); dev_info(&stdev->dev, "unregistered.\n"); |