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

Commit edb1daab authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/huang-d3cold-fixes' into next

* pci/huang-d3cold-fixes:
  PCI/PM: Keep runtime PM enabled for unbound PCI devices
parents be5cd530 967577b0
Loading
Loading
Loading
Loading
+40 −27
Original line number Original line Diff line number Diff line
@@ -256,31 +256,26 @@ struct drv_dev_and_id {
static long local_pci_probe(void *_ddi)
static long local_pci_probe(void *_ddi)
{
{
	struct drv_dev_and_id *ddi = _ddi;
	struct drv_dev_and_id *ddi = _ddi;
	struct device *dev = &ddi->dev->dev;
	struct pci_dev *pci_dev = ddi->dev;
	struct device *parent = dev->parent;
	struct pci_driver *pci_drv = ddi->drv;
	struct device *dev = &pci_dev->dev;
	int rc;
	int rc;


	/* The parent bridge must be in active state when probing */
	/*
	if (parent)
	 * Unbound PCI devices are always put in D0, regardless of
		pm_runtime_get_sync(parent);
	 * runtime PM status.  During probe, the device is set to
	/* Unbound PCI devices are always set to disabled and suspended.
	 * active and the usage count is incremented.  If the driver
	 * During probe, the device is set to enabled and active and the
	 * supports runtime PM, it should call pm_runtime_put_noidle()
	 * usage count is incremented.  If the driver supports runtime PM,
	 * in its probe routine and pm_runtime_get_noresume() in its
	 * it should call pm_runtime_put_noidle() in its probe routine and
	 * remove routine.
	 * pm_runtime_get_noresume() in its remove routine.
	 */
	 */
	pm_runtime_get_noresume(dev);
	pm_runtime_get_sync(dev);
	pm_runtime_set_active(dev);
	pci_dev->driver = pci_drv;
	pm_runtime_enable(dev);
	rc = pci_drv->probe(pci_dev, ddi->id);

	rc = ddi->drv->probe(ddi->dev, ddi->id);
	if (rc) {
	if (rc) {
		pm_runtime_disable(dev);
		pci_dev->driver = NULL;
		pm_runtime_set_suspended(dev);
		pm_runtime_put_sync(dev);
		pm_runtime_put_noidle(dev);
	}
	}
	if (parent)
		pm_runtime_put(parent);
	return rc;
	return rc;
}
}


@@ -330,11 +325,9 @@ __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
		id = pci_match_device(drv, pci_dev);
		id = pci_match_device(drv, pci_dev);
		if (id)
		if (id)
			error = pci_call_probe(drv, pci_dev, id);
			error = pci_call_probe(drv, pci_dev, id);
		if (error >= 0) {
		if (error >= 0)
			pci_dev->driver = drv;
			error = 0;
			error = 0;
	}
	}
	}
	return error;
	return error;
}
}


@@ -369,9 +362,7 @@ static int pci_device_remove(struct device * dev)
	}
	}


	/* Undo the runtime PM settings in local_pci_probe() */
	/* Undo the runtime PM settings in local_pci_probe() */
	pm_runtime_disable(dev);
	pm_runtime_put_sync(dev);
	pm_runtime_set_suspended(dev);
	pm_runtime_put_noidle(dev);


	/*
	/*
	 * If the device is still on, set the power state as "unknown",
	 * If the device is still on, set the power state as "unknown",
@@ -994,6 +985,13 @@ static int pci_pm_runtime_suspend(struct device *dev)
	pci_power_t prev = pci_dev->current_state;
	pci_power_t prev = pci_dev->current_state;
	int error;
	int error;


	/*
	 * If pci_dev->driver is not set (unbound), the device should
	 * always remain in D0 regardless of the runtime PM status
	 */
	if (!pci_dev->driver)
		return 0;

	if (!pm || !pm->runtime_suspend)
	if (!pm || !pm->runtime_suspend)
		return -ENOSYS;
		return -ENOSYS;


@@ -1029,6 +1027,13 @@ static int pci_pm_runtime_resume(struct device *dev)
	struct pci_dev *pci_dev = to_pci_dev(dev);
	struct pci_dev *pci_dev = to_pci_dev(dev);
	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;


	/*
	 * If pci_dev->driver is not set (unbound), the device should
	 * always remain in D0 regardless of the runtime PM status
	 */
	if (!pci_dev->driver)
		return 0;

	if (!pm || !pm->runtime_resume)
	if (!pm || !pm->runtime_resume)
		return -ENOSYS;
		return -ENOSYS;


@@ -1046,8 +1051,16 @@ static int pci_pm_runtime_resume(struct device *dev)


static int pci_pm_runtime_idle(struct device *dev)
static int pci_pm_runtime_idle(struct device *dev)
{
{
	struct pci_dev *pci_dev = to_pci_dev(dev);
	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;


	/*
	 * If pci_dev->driver is not set (unbound), the device should
	 * always remain in D0 regardless of the runtime PM status
	 */
	if (!pci_dev->driver)
		goto out;

	if (!pm)
	if (!pm)
		return -ENOSYS;
		return -ENOSYS;


@@ -1057,8 +1070,8 @@ static int pci_pm_runtime_idle(struct device *dev)
			return ret;
			return ret;
	}
	}


out:
	pm_runtime_suspend(dev);
	pm_runtime_suspend(dev);

	return 0;
	return 0;
}
}


+2 −0
Original line number Original line Diff line number Diff line
@@ -1910,6 +1910,8 @@ void pci_pm_init(struct pci_dev *dev)
	u16 pmc;
	u16 pmc;


	pm_runtime_forbid(&dev->dev);
	pm_runtime_forbid(&dev->dev);
	pm_runtime_set_active(&dev->dev);
	pm_runtime_enable(&dev->dev);
	device_enable_async_suspend(&dev->dev);
	device_enable_async_suspend(&dev->dev);
	dev->wakeup_prepared = false;
	dev->wakeup_prepared = false;