From f85876ba82281f15bc4da11e41b94243a8b2b5b4 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Sat, 13 Jun 2009 15:52:14 +0800 Subject: PCI: support PM D0hot->D3 transition reset PCI PM 1.2 specifies that the device will perform an internal reset upon transitioning from D3hot to D0 when the NO_SOFT_RESET bit is clear. This method can be used to reset a function if neither PCIe FLR nor PCI AF FLR are supported. Reviewed-by: Kenji Kaneshige Signed-off-by: Yu Zhao Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6a052ada3fe..2e58acc66a8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2132,6 +2132,36 @@ clear: return 0; } +static int pci_pm_reset(struct pci_dev *dev, int probe) +{ + u16 csr; + + if (!dev->pm_cap) + return -ENOTTY; + + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr); + if (csr & PCI_PM_CTRL_NO_SOFT_RESET) + return -ENOTTY; + + if (probe) + return 0; + + if (dev->current_state != PCI_D0) + return -EINVAL; + + csr &= ~PCI_PM_CTRL_STATE_MASK; + csr |= PCI_D3hot; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr); + msleep(pci_pm_d3_delay); + + csr &= ~PCI_PM_CTRL_STATE_MASK; + csr |= PCI_D0; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr); + msleep(pci_pm_d3_delay); + + return 0; +} + static int pci_dev_reset(struct pci_dev *dev, int probe) { int rc; @@ -2149,6 +2179,10 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) goto done; rc = pci_af_flr(dev, probe); + if (rc != -ENOTTY) + goto done; + + rc = pci_pm_reset(dev, probe); done: if (!probe) { up(&dev->dev.sem); -- cgit v1.2.3