Skip to content

Commit

Permalink
PCI/PM: Fix config reg access for D3cold and bridge suspending
Browse files Browse the repository at this point in the history
This patch fixes the following bug:

http://marc.info/?l=linux-pci&m=134338059022620&w=2

Where lspci does not work properly if a device and the corresponding
parent bridge (such as PCIe port) is suspended.  This is because the
device configuration space registers will be not accessible if the
corresponding parent bridge is suspended or the device is put into
D3cold state.

To solve the issue, the bridge/PCIe port connected to the device is
put into active state before read/write configuration space registers.
If the device is in D3cold state, it will be put into active state
too.

To avoid resume/suspend PCIe port for each configuration register
read/write, a small delay is added before the PCIe port to go
suspended.

Reported-by: Bjorn Mork <[email protected]>
Signed-off-by: Huang Ying <[email protected]>
Signed-off-by: Bjorn Helgaas <[email protected]>
Reviewed-by: Rafael J. Wysocki <[email protected]>
  • Loading branch information
yhuang-intel authored and bjorn-helgaas committed Aug 21, 2012
1 parent ea8c88f commit 3d8387e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
42 changes: 42 additions & 0 deletions drivers/pci/pci-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,40 @@ boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
}
struct device_attribute vga_attr = __ATTR_RO(boot_vga);

static void
pci_config_pm_runtime_get(struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
struct device *parent = dev->parent;

if (parent)
pm_runtime_get_sync(parent);
pm_runtime_get_noresume(dev);
/*
* pdev->current_state is set to PCI_D3cold during suspending,
* so wait until suspending completes
*/
pm_runtime_barrier(dev);
/*
* Only need to resume devices in D3cold, because config
* registers are still accessible for devices suspended but
* not in D3cold.
*/
if (pdev->current_state == PCI_D3cold)
pm_runtime_resume(dev);
}

static void
pci_config_pm_runtime_put(struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
struct device *parent = dev->parent;

pm_runtime_put(dev);
if (parent)
pm_runtime_put_sync(parent);
}

static ssize_t
pci_read_config(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
Expand All @@ -484,6 +518,8 @@ pci_read_config(struct file *filp, struct kobject *kobj,
size = count;
}

pci_config_pm_runtime_get(dev);

if ((off & 1) && size) {
u8 val;
pci_user_read_config_byte(dev, off, &val);
Expand Down Expand Up @@ -529,6 +565,8 @@ pci_read_config(struct file *filp, struct kobject *kobj,
--size;
}

pci_config_pm_runtime_put(dev);

return count;
}

Expand All @@ -549,6 +587,8 @@ pci_write_config(struct file* filp, struct kobject *kobj,
count = size;
}

pci_config_pm_runtime_get(dev);

if ((off & 1) && size) {
pci_user_write_config_byte(dev, off, data[off - init_off]);
off++;
Expand Down Expand Up @@ -587,6 +627,8 @@ pci_write_config(struct file* filp, struct kobject *kobj,
--size;
}

pci_config_pm_runtime_put(dev);

return count;
}

Expand Down
9 changes: 9 additions & 0 deletions drivers/pci/pcie/portdrv_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,17 @@ static int pcie_port_runtime_resume(struct device *dev)
{
return 0;
}

static int pcie_port_runtime_idle(struct device *dev)
{
/* Delay for a short while to prevent too frequent suspend/resume */
pm_schedule_suspend(dev, 10);
return -EBUSY;
}
#else
#define pcie_port_runtime_suspend NULL
#define pcie_port_runtime_resume NULL
#define pcie_port_runtime_idle NULL
#endif

static const struct dev_pm_ops pcie_portdrv_pm_ops = {
Expand All @@ -155,6 +163,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.resume_noirq = pcie_port_resume_noirq,
.runtime_suspend = pcie_port_runtime_suspend,
.runtime_resume = pcie_port_runtime_resume,
.runtime_idle = pcie_port_runtime_idle,
};

#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops)
Expand Down

0 comments on commit 3d8387e

Please sign in to comment.