Blob Blame History Raw
From: Sebastian Ott <sebott@linux.vnet.ibm.com>
Subject: s390/pci: recognize name clashes with uids
Patch-mainline: v4.13-rc1
Git-commit: 312e8462ab6a1594a0bc4bc51c8e36c9f07b447b
References: bnc#1066983, LTC#157731

Description:  PCI: fix hotplug related issues
Symptom:      After serveral cycles of hot-unplug/hotplug the affected
              function stops working or the kernel oopses.
Problem:      Hotplug notifications happen after the fact, meaning it's
              not possible to issue instructions to the function for
              cleanup purposes. Thus we never release the associated
              resources and at some point fail to allocate new ones.
Solution:     During clean up treat some errors as success (e.g. a
              function that's gone can't create an interrupt).
Reproduction: vmcp att pcif XXX to \* ;vmcp det pcif XXX #in a loop

Upstream-Description:

              s390/pci: recognize name clashes with uids

              When uid checking is enabled firmware guarantees uniqueness of the uids
              and we use them for device enumeration. Tests have shown that uid checking
              can be toggled at runtime. This is unfortunate since it can lead to name
              clashes.

              Recognize these name clashes by allocating bits in zpci_domain even for
              firmware provided ids.

              Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
              Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com>
              Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
              Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>


Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Acked-by: Hannes Reinecke <hare@suse.com>
---
 arch/s390/pci/pci.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -736,6 +736,16 @@ static int zpci_alloc_domain(struct zpci
 {
 	if (zpci_unique_uid) {
 		zdev->domain = (u16) zdev->uid;
+		if (zdev->domain >= ZPCI_NR_DEVICES)
+			return 0;
+
+		spin_lock(&zpci_domain_lock);
+		if (test_bit(zdev->domain, zpci_domain)) {
+			spin_unlock(&zpci_domain_lock);
+			return -EEXIST;
+		}
+		set_bit(zdev->domain, zpci_domain);
+		spin_unlock(&zpci_domain_lock);
 		return 0;
 	}
 
@@ -752,7 +762,7 @@ static int zpci_alloc_domain(struct zpci
 
 static void zpci_free_domain(struct zpci_dev *zdev)
 {
-	if (zpci_unique_uid)
+	if (zdev->domain >= ZPCI_NR_DEVICES)
 		return;
 
 	spin_lock(&zpci_domain_lock);