Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Provide Kconfig option for lockless config space accessors

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>

+15 -4
+3
drivers/pci/Kconfig
··· 86 86 config PCI_ECAM 87 87 bool 88 88 89 + config PCI_LOCKLESS_CONFIG 90 + bool 91 + 89 92 config PCI_IOV 90 93 bool "PCI IOV support" 91 94 depends on PCI
+12 -4
drivers/pci/access.c
··· 25 25 #define PCI_word_BAD (pos & 1) 26 26 #define PCI_dword_BAD (pos & 3) 27 27 28 + #ifdef CONFIG_PCI_LOCKLESS_CONFIG 29 + # define pci_lock_config(f) do { (void)(f); } while (0) 30 + # define pci_unlock_config(f) do { (void)(f); } while (0) 31 + #else 32 + # define pci_lock_config(f) raw_spin_lock_irqsave(&pci_lock, f) 33 + # define pci_unlock_config(f) raw_spin_unlock_irqrestore(&pci_lock, f) 34 + #endif 35 + 28 36 #define PCI_OP_READ(size, type, len) \ 29 37 int pci_bus_read_config_##size \ 30 38 (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ ··· 41 33 unsigned long flags; \ 42 34 u32 data = 0; \ 43 35 if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ 44 - raw_spin_lock_irqsave(&pci_lock, flags); \ 36 + pci_lock_config(flags); \ 45 37 res = bus->ops->read(bus, devfn, pos, len, &data); \ 46 38 *value = (type)data; \ 47 - raw_spin_unlock_irqrestore(&pci_lock, flags); \ 39 + pci_unlock_config(flags); \ 48 40 return res; \ 49 41 } 50 42 ··· 55 47 int res; \ 56 48 unsigned long flags; \ 57 49 if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ 58 - raw_spin_lock_irqsave(&pci_lock, flags); \ 50 + pci_lock_config(flags); \ 59 51 res = bus->ops->write(bus, devfn, pos, len, value); \ 60 - raw_spin_unlock_irqrestore(&pci_lock, flags); \ 52 + pci_unlock_config(flags); \ 61 53 return res; \ 62 54 } 63 55