Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8b9cf0f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull PCI updates from Bjorn Helgaas:
 "Power management
    - PCI/PM: Enable D3/D3cold by default for most devices
    - PCI/PM: Keep parent bridge active when probing device
    - PCI/PM: Fix config reg access for D3cold and bridge suspending
    - PCI/PM: Add ABI document for sysfs file d3cold_allowed
  Core
    - PCI: Don't print anything while decoding is disabled"

* tag '3.6-pci-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  PCI: Don't print anything while decoding is disabled
  PCI/PM: Add ABI document for sysfs file d3cold_allowed
  PCI/PM: Fix config reg access for D3cold and bridge suspending
  PCI/PM: Keep parent bridge active when probing device
  PCI/PM: Enable D3/D3cold by default for most devices
parents eeea3ac9 0ff9514b
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -210,3 +210,15 @@ Users:
		firmware assigned instance number of the PCI
		device that can help in understanding the firmware
		intended order of the PCI device.

What:		/sys/bus/pci/devices/.../d3cold_allowed
Date:		July 2012
Contact:	Huang Ying <ying.huang@intel.com>
Description:
		d3cold_allowed is bit to control whether the corresponding PCI
		device can be put into D3Cold state.  If it is cleared, the
		device will never be put into D3Cold state.  If it is set, the
		device may be put into D3Cold state if other requirements are
		satisfied too.  Reading this attribute will show the current
		value of d3cold_allowed bit.  Writing this attribute will set
		the value of d3cold_allowed bit.
+6 −0
Original line number Diff line number Diff line
@@ -280,8 +280,12 @@ static long local_pci_probe(void *_ddi)
{
	struct drv_dev_and_id *ddi = _ddi;
	struct device *dev = &ddi->dev->dev;
	struct device *parent = dev->parent;
	int rc;

	/* The parent bridge must be in active state when probing */
	if (parent)
		pm_runtime_get_sync(parent);
	/* Unbound PCI devices are always set to disabled and suspended.
	 * During probe, the device is set to enabled and active and the
	 * usage count is incremented.  If the driver supports runtime PM,
@@ -298,6 +302,8 @@ static long local_pci_probe(void *_ddi)
		pm_runtime_set_suspended(dev);
		pm_runtime_put_noidle(dev);
	}
	if (parent)
		pm_runtime_put(parent);
	return rc;
}

+42 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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);
@@ -529,6 +565,8 @@ pci_read_config(struct file *filp, struct kobject *kobj,
		--size;
	}

	pci_config_pm_runtime_put(dev);

	return count;
}

@@ -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++;
@@ -587,6 +627,8 @@ pci_write_config(struct file* filp, struct kobject *kobj,
		--size;
	}

	pci_config_pm_runtime_put(dev);

	return count;
}

+1 −0
Original line number Diff line number Diff line
@@ -1941,6 +1941,7 @@ void pci_pm_init(struct pci_dev *dev)
	dev->pm_cap = pm;
	dev->d3_delay = PCI_PM_D3_WAIT;
	dev->d3cold_delay = PCI_PM_D3COLD_WAIT;
	dev->d3cold_allowed = true;

	dev->d1_support = false;
	dev->d2_support = false;
+14 −0
Original line number Diff line number Diff line
@@ -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 = {
@@ -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)
@@ -200,6 +209,11 @@ static int __devinit pcie_portdrv_probe(struct pci_dev *dev,
		return status;

	pci_save_state(dev);
	/*
	 * D3cold may not work properly on some PCIe port, so disable
	 * it by default.
	 */
	dev->d3cold_allowed = false;
	if (!pci_match_id(port_runtime_pm_black_list, dev))
		pm_runtime_put_noidle(&dev->dev);

Loading