mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
synced 2026-04-25 00:52:45 -04:00
Merge branch 'pci/vpd'
- Ensure device is accessible before VPD access via sysfs (Alex Williamson) - Ensure device doesn't go to a low-power state while we're polling for PME (Alex Williamson) * pci/vpd: PCI: Fix runtime PM race with PME polling PCI/VPD: Add runtime power management to sysfs interface
This commit is contained in:
@@ -2420,10 +2420,13 @@ static void pci_pme_list_scan(struct work_struct *work)
|
||||
|
||||
mutex_lock(&pci_pme_list_mutex);
|
||||
list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
|
||||
if (pme_dev->dev->pme_poll) {
|
||||
struct pci_dev *bridge;
|
||||
struct pci_dev *pdev = pme_dev->dev;
|
||||
|
||||
if (pdev->pme_poll) {
|
||||
struct pci_dev *bridge = pdev->bus->self;
|
||||
struct device *dev = &pdev->dev;
|
||||
int pm_status;
|
||||
|
||||
bridge = pme_dev->dev->bus->self;
|
||||
/*
|
||||
* If bridge is in low power state, the
|
||||
* configuration space of subordinate devices
|
||||
@@ -2431,14 +2434,20 @@ static void pci_pme_list_scan(struct work_struct *work)
|
||||
*/
|
||||
if (bridge && bridge->current_state != PCI_D0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If the device is in D3cold it should not be
|
||||
* polled either.
|
||||
* If the device is in a low power state it
|
||||
* should not be polled either.
|
||||
*/
|
||||
if (pme_dev->dev->current_state == PCI_D3cold)
|
||||
pm_status = pm_runtime_get_if_active(dev, true);
|
||||
if (!pm_status)
|
||||
continue;
|
||||
|
||||
pci_pme_wakeup(pme_dev->dev, NULL);
|
||||
if (pdev->current_state != PCI_D3cold)
|
||||
pci_pme_wakeup(pdev, NULL);
|
||||
|
||||
if (pm_status > 0)
|
||||
pm_runtime_put(dev);
|
||||
} else {
|
||||
list_del(&pme_dev->list);
|
||||
kfree(pme_dev);
|
||||
|
||||
@@ -275,8 +275,23 @@ static ssize_t vpd_read(struct file *filp, struct kobject *kobj,
|
||||
size_t count)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
|
||||
struct pci_dev *vpd_dev = dev;
|
||||
ssize_t ret;
|
||||
|
||||
return pci_read_vpd(dev, off, count, buf);
|
||||
if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) {
|
||||
vpd_dev = pci_get_func0_dev(dev);
|
||||
if (!vpd_dev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pci_config_pm_runtime_get(vpd_dev);
|
||||
ret = pci_read_vpd(vpd_dev, off, count, buf);
|
||||
pci_config_pm_runtime_put(vpd_dev);
|
||||
|
||||
if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0)
|
||||
pci_dev_put(vpd_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t vpd_write(struct file *filp, struct kobject *kobj,
|
||||
@@ -284,8 +299,23 @@ static ssize_t vpd_write(struct file *filp, struct kobject *kobj,
|
||||
size_t count)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
|
||||
struct pci_dev *vpd_dev = dev;
|
||||
ssize_t ret;
|
||||
|
||||
return pci_write_vpd(dev, off, count, buf);
|
||||
if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) {
|
||||
vpd_dev = pci_get_func0_dev(dev);
|
||||
if (!vpd_dev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pci_config_pm_runtime_get(vpd_dev);
|
||||
ret = pci_write_vpd(vpd_dev, off, count, buf);
|
||||
pci_config_pm_runtime_put(vpd_dev);
|
||||
|
||||
if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0)
|
||||
pci_dev_put(vpd_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static BIN_ATTR(vpd, 0600, vpd_read, vpd_write, 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user