Commit 49db1399 authored by Zhao Yakui's avatar Zhao Yakui Committed by Jesse Barnes

PCI: Disable PME during PCI scan

If a device supports #PME and can generate PME events from D0, we may see
superfluous events before a driver is loaded (drivers should only enable PME as
needed), preventing suspend from working if the corresponding GPE was enabled.

Likewise, if the ACPI device has the _PRW object, the _PSW/_DSW object will be
called in order to disable the wakeup functionality. But when it is allowed to
wake up the sleeping state, OSPM will enable it again.

So we should disable PME in the course of scanning PCI devices and enable it
again only when PME events are actually required to be generated from the
requested PCI state (for example, D3_hot or D3_cold).  It is also safe to
disable PME again when the PME is disabled for the PCI devices.
Signed-off-by: default avatarZhao Yakui <yakui.zhao@intel.com>
Signed-off-by: default avatarLi Shaohua <shaohua.li@intel.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent e1a2a51e
...@@ -857,6 +857,49 @@ int pci_cfg_space_size_ext(struct pci_dev *dev) ...@@ -857,6 +857,49 @@ int pci_cfg_space_size_ext(struct pci_dev *dev)
return PCI_CFG_SPACE_SIZE; return PCI_CFG_SPACE_SIZE;
} }
/**
* pci_disable_pme - Disable the PME function of PCI device
* @dev: PCI device affected
* -EINVAL is returned if PCI device doesn't support PME.
* Zero is returned if the PME is supported and can be disabled.
*/
static int pci_disable_pme(struct pci_dev *dev)
{
int pm;
u16 value;
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
/* If device doesn't support PM Capabilities, it means that PME is
* not supported.
*/
if (!pm)
return -EINVAL;
/* Check device's ability to generate PME# */
pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
value &= PCI_PM_CAP_PME_MASK;
/* Check if it can generate PME# */
if (!value) {
/*
* If it is zero, it means that PME is still unsupported
* although there exists the PM capability.
*/
return -EINVAL;
}
pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
/* Clear PME_Status by writing 1 to it */
value |= PCI_PM_CTRL_PME_STATUS ;
/* Disable PME enable bit */
value &= ~PCI_PM_CTRL_PME_ENABLE;
pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
return 0;
}
int pci_cfg_space_size(struct pci_dev *dev) int pci_cfg_space_size(struct pci_dev *dev)
{ {
int pos; int pos;
...@@ -964,6 +1007,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) ...@@ -964,6 +1007,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
} }
pci_vpd_pci22_init(dev); pci_vpd_pci22_init(dev);
pci_disable_pme(dev);
return dev; return dev;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment