Message ID | 20130808200943.2932.42781.stgit@bling.home (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
On Thu, Aug 8, 2013 at 2:09 PM, Alex Williamson <alex.williamson@redhat.com> wrote: > If the hotplug controller provides a way to reset a slot, use that > before a direct parent bus reset. Like the bus reset option, this is > only available when a single pci_dev occupies the slot. > > Signed-off-by: Alex Williamson <alex.williamson@redhat.com> > --- > drivers/pci/pci.c | 34 ++++++++++++++++++++++++++++++++++ > 1 file changed, 34 insertions(+) > > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index d468608..9407aab 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -22,6 +22,7 @@ > #include <linux/interrupt.h> > #include <linux/device.h> > #include <linux/pm_runtime.h> > +#include <linux/pci_hotplug.h> > #include <asm-generic/pci-bridge.h> > #include <asm/setup.h> > #include "pci.h" > @@ -3256,6 +3257,35 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe) > return 0; > } > > +static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe) > +{ > + int rc = -ENOTTY; > + > + if (!hotplug || !try_module_get(hotplug->ops->owner)) > + return rc; > + > + if (hotplug->ops->reset_slot) > + rc = hotplug->ops->reset_slot(hotplug, probe); > + > + module_put(hotplug->ops->owner); > + > + return rc; > +} > + > +static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) > +{ > + struct pci_dev *pdev; > + > + if (dev->subordinate || !dev->slot) > + return -ENOTTY; > + > + list_for_each_entry(pdev, &dev->bus->devices, bus_list) > + if (pdev != dev && pdev->slot == dev->slot) > + return -ENOTTY; > + > + return pci_reset_hotplug_slot(dev->slot->hotplug, probe); I don't think this is hotplug-safe. It looks like pci_bus_sem might be the right semaphore to hold while verifying that we won't reset any unintended devices. But I think most users of the bus->devices list are unprotected, so there's no point in trying to fix just this one. > +} > + > static int __pci_dev_reset(struct pci_dev *dev, int probe) > { > int rc; > @@ -3278,6 +3308,10 @@ static int __pci_dev_reset(struct pci_dev *dev, int probe) > if (rc != -ENOTTY) > goto done; > > + rc = pci_dev_reset_slot_function(dev, probe); > + if (rc != -ENOTTY) > + goto done; > + > rc = pci_parent_bus_reset(dev, probe); > done: > return rc; > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 8/15/13, Bjorn Helgaas <bhelgaas@google.com> wrote: > On Thu, Aug 8, 2013 at 2:09 PM, Alex Williamson <snip> > I don't think this is hotplug-safe. It looks like pci_bus_sem might > be the right semaphore to hold while verifying that we won't reset any > unintended devices. Something like pci_bus_sem locks all the buses, which may pose a big overhead. So it doesn't seem like an ideal solution. A better approach is to lock only one parent to protect only a sub-tree. At least that's what I've seen in some other operating systems dealing with PCI hotplug. But that requires a significant amount of change. Thanks Rui But I think most users of the bus->devices list > are unprotected, so there's no point in trying to fix just this one. > >> +} >> + >> static int __pci_dev_reset(struct pci_dev *dev, int probe) >> { >> int rc; >> @@ -3278,6 +3308,10 @@ static int __pci_dev_reset(struct pci_dev *dev, int >> probe) >> if (rc != -ENOTTY) >> goto done; >> >> + rc = pci_dev_reset_slot_function(dev, probe); >> + if (rc != -ENOTTY) >> + goto done; >> + >> rc = pci_parent_bus_reset(dev, probe); >> done: >> return rc; >> > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d468608..9407aab 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -22,6 +22,7 @@ #include <linux/interrupt.h> #include <linux/device.h> #include <linux/pm_runtime.h> +#include <linux/pci_hotplug.h> #include <asm-generic/pci-bridge.h> #include <asm/setup.h> #include "pci.h" @@ -3256,6 +3257,35 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe) return 0; } +static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe) +{ + int rc = -ENOTTY; + + if (!hotplug || !try_module_get(hotplug->ops->owner)) + return rc; + + if (hotplug->ops->reset_slot) + rc = hotplug->ops->reset_slot(hotplug, probe); + + module_put(hotplug->ops->owner); + + return rc; +} + +static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) +{ + struct pci_dev *pdev; + + if (dev->subordinate || !dev->slot) + return -ENOTTY; + + list_for_each_entry(pdev, &dev->bus->devices, bus_list) + if (pdev != dev && pdev->slot == dev->slot) + return -ENOTTY; + + return pci_reset_hotplug_slot(dev->slot->hotplug, probe); +} + static int __pci_dev_reset(struct pci_dev *dev, int probe) { int rc; @@ -3278,6 +3308,10 @@ static int __pci_dev_reset(struct pci_dev *dev, int probe) if (rc != -ENOTTY) goto done; + rc = pci_dev_reset_slot_function(dev, probe); + if (rc != -ENOTTY) + goto done; + rc = pci_parent_bus_reset(dev, probe); done: return rc;
If the hotplug controller provides a way to reset a slot, use that before a direct parent bus reset. Like the bus reset option, this is only available when a single pci_dev occupies the slot. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> --- drivers/pci/pci.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html