PCI: Provide Kconfig option for lockless config space accessors
authorThomas Gleixner <tglx@linutronix.de>
Thu, 16 Mar 2017 21:50:06 +0000 (22:50 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 28 Jun 2017 20:32:56 +0000 (22:32 +0200)
The generic PCI configuration space accessors are globally serialized via
pci_lock. On larger systems this causes massive lock contention when the
configuration space has to be accessed frequently. One such access pattern
is the Intel Uncore performance counter unit.

Provide a kernel config option which can be selected by an architecture
when the low level PCI configuration space accessors in the architecture
use their own serialization or can operate completely lockless.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: linux-pci@vger.kernel.org
Link: http://lkml.kernel.org/r/20170316215057.205961140@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
drivers/pci/Kconfig
drivers/pci/access.c

index e0cacb7b8563468fe9ce98ed603e176f267c7ac7..c32a77fc8b03a5ff876768ade086c818dee3a116 100644 (file)
@@ -86,6 +86,9 @@ config PCI_ATS
 config PCI_ECAM
        bool
 
+config PCI_LOCKLESS_CONFIG
+       bool
+
 config PCI_IOV
        bool "PCI IOV support"
        depends on PCI
index c80e37a69305c18f2879957c92fa3308bb45b175..913d6722ece988463b9850b7e7add11634766091 100644 (file)
@@ -25,6 +25,14 @@ DEFINE_RAW_SPINLOCK(pci_lock);
 #define PCI_word_BAD (pos & 1)
 #define PCI_dword_BAD (pos & 3)
 
+#ifdef CONFIG_PCI_LOCKLESS_CONFIG
+# define pci_lock_config(f)    do { (void)(f); } while (0)
+# define pci_unlock_config(f)  do { (void)(f); } while (0)
+#else
+# define pci_lock_config(f)    raw_spin_lock_irqsave(&pci_lock, f)
+# define pci_unlock_config(f)  raw_spin_unlock_irqrestore(&pci_lock, f)
+#endif
+
 #define PCI_OP_READ(size, type, len) \
 int pci_bus_read_config_##size \
        (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
@@ -33,10 +41,10 @@ int pci_bus_read_config_##size \
        unsigned long flags;                                            \
        u32 data = 0;                                                   \
        if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \
-       raw_spin_lock_irqsave(&pci_lock, flags);                        \
+       pci_lock_config(flags);                                         \
        res = bus->ops->read(bus, devfn, pos, len, &data);              \
        *value = (type)data;                                            \
-       raw_spin_unlock_irqrestore(&pci_lock, flags);           \
+       pci_unlock_config(flags);                                       \
        return res;                                                     \
 }
 
@@ -47,9 +55,9 @@ int pci_bus_write_config_##size \
        int res;                                                        \
        unsigned long flags;                                            \
        if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \
-       raw_spin_lock_irqsave(&pci_lock, flags);                        \
+       pci_lock_config(flags);                                         \
        res = bus->ops->write(bus, devfn, pos, len, value);             \
-       raw_spin_unlock_irqrestore(&pci_lock, flags);           \
+       pci_unlock_config(flags);                                       \
        return res;                                                     \
 }