[3.16.y-ckt stable] Patch "PCI: Add flag for devices where we can't use bus reset" has been added to staging queue

Luis Henriques luis.henriques at canonical.com
Mon Feb 2 11:50:17 UTC 2015


This is a note to let you know that I have just added a patch titled

    PCI: Add flag for devices where we can't use bus reset

to the linux-3.16.y-queue branch of the 3.16.y-ckt extended stable tree 
which can be found at:

 http://kernel.ubuntu.com/git?p=ubuntu/linux.git;a=shortlog;h=refs/heads/linux-3.16.y-queue

This patch is scheduled to be released in version 3.16.7-ckt6.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.16.y-ckt tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Luis

------

>From 83790d096d8f7571ce3237967533df2492828998 Mon Sep 17 00:00:00 2001
From: Alex Williamson <alex.williamson at redhat.com>
Date: Thu, 15 Jan 2015 18:16:04 -0600
Subject: PCI: Add flag for devices where we can't use bus reset

commit f331a859e0ee5a898c1f47596eddad4c4f02d657 upstream.

Enable a mechanism for devices to quirk that they do not behave when
doing a PCI bus reset.  We require a modest level of spec compliant
behavior in order to do a reset, for instance the device should come
out of reset without throwing errors and PCI config space should be
accessible after reset.  This is too much to ask for some devices.

Link: http://lkml.kernel.org/r/20140923210318.498dacbd@dualc.maya.org
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas at google.com>
Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
---
 drivers/pci/pci.c   | 40 ++++++++++++++++++++++++++++++++++++----
 include/linux/pci.h |  2 ++
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 81d49d3ab221..3e981329c7a9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3241,7 +3241,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
 {
 	struct pci_dev *pdev;

-	if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self)
+	if (pci_is_root_bus(dev->bus) || dev->subordinate ||
+	    !dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
 		return -ENOTTY;

 	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
@@ -3275,7 +3276,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
 {
 	struct pci_dev *pdev;

-	if (dev->subordinate || !dev->slot)
+	if (dev->subordinate || !dev->slot ||
+	    dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
 		return -ENOTTY;

 	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
@@ -3527,6 +3529,20 @@ int pci_try_reset_function(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_try_reset_function);

+/* Do any devices on or below this bus prevent a bus reset? */
+static bool pci_bus_resetable(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
+		    (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
+			return false;
+	}
+
+	return true;
+}
+
 /* Lock devices from the top of the tree down */
 static void pci_bus_lock(struct pci_bus *bus)
 {
@@ -3577,6 +3593,22 @@ unlock:
 	return 0;
 }

+/* Do any devices on or below this slot prevent a bus reset? */
+static bool pci_slot_resetable(struct pci_slot *slot)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+		if (!dev->slot || dev->slot != slot)
+			continue;
+		if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
+		    (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
+			return false;
+	}
+
+	return true;
+}
+
 /* Lock devices from the top of the tree down */
 static void pci_slot_lock(struct pci_slot *slot)
 {
@@ -3698,7 +3730,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe)
 {
 	int rc;

-	if (!slot)
+	if (!slot || !pci_slot_resetable(slot))
 		return -ENOTTY;

 	if (!probe)
@@ -3790,7 +3822,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot);

 static int pci_bus_reset(struct pci_bus *bus, int probe)
 {
-	if (!bus->self)
+	if (!bus->self || !pci_bus_resetable(bus))
 		return -ENOTTY;

 	if (probe)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 04fdc409eec6..5d711ffb8f4d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -175,6 +175,8 @@ enum pci_dev_flags {
 	PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4),
 	/* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */
 	PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5),
+	/* Do not use bus resets for device */
+	PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6),
 };

 enum pci_irq_reroute_variant {
--
2.1.4





More information about the kernel-team mailing list