From: Yu Zhao Date: Sat, 13 Jun 2009 07:52:15 +0000 (+0800) Subject: PCI: support Secondary Bus Reset X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=c12ff1df5f114484e3d8abd028769a624cc3399f;p=linux-beck.git PCI: support Secondary Bus Reset PCI-to-PCI Bridge 1.2 specifies that the Secondary Bus Reset bit can force the assertion of RST# on the secondary interface, which can be used to reset all devices including subordinates under this bus. This can be used to reset a function if this function is the only device under this bus. Reviewed-by: Kenji Kaneshige Signed-off-by: Yu Zhao Signed-off-by: Jesse Barnes --- diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2e58acc66a8c..c56a4a0355a8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2162,6 +2162,33 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) return 0; } +static int pci_parent_bus_reset(struct pci_dev *dev, int probe) +{ + u16 ctrl; + struct pci_dev *pdev; + + if (dev->subordinate) + return -ENOTTY; + + list_for_each_entry(pdev, &dev->bus->devices, bus_list) + if (pdev != dev) + return -ENOTTY; + + if (probe) + return 0; + + pci_read_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, &ctrl); + ctrl |= PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl); + msleep(100); + + ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl); + msleep(100); + + return 0; +} + static int pci_dev_reset(struct pci_dev *dev, int probe) { int rc; @@ -2183,6 +2210,10 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) goto done; rc = pci_pm_reset(dev, probe); + if (rc != -ENOTTY) + goto done; + + rc = pci_parent_bus_reset(dev, probe); done: if (!probe) { up(&dev->dev.sem);