Commit 714fe383 authored by Thomas Gleixner's avatar Thomas Gleixner

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: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarBjorn 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.deSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent bb290fda
...@@ -86,6 +86,9 @@ config PCI_ATS ...@@ -86,6 +86,9 @@ config PCI_ATS
config PCI_ECAM config PCI_ECAM
bool bool
config PCI_LOCKLESS_CONFIG
bool
config PCI_IOV config PCI_IOV
bool "PCI IOV support" bool "PCI IOV support"
depends on PCI depends on PCI
......
...@@ -25,6 +25,14 @@ DEFINE_RAW_SPINLOCK(pci_lock); ...@@ -25,6 +25,14 @@ DEFINE_RAW_SPINLOCK(pci_lock);
#define PCI_word_BAD (pos & 1) #define PCI_word_BAD (pos & 1)
#define PCI_dword_BAD (pos & 3) #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) \ #define PCI_OP_READ(size, type, len) \
int pci_bus_read_config_##size \ int pci_bus_read_config_##size \
(struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
...@@ -33,10 +41,10 @@ int pci_bus_read_config_##size \ ...@@ -33,10 +41,10 @@ int pci_bus_read_config_##size \
unsigned long flags; \ unsigned long flags; \
u32 data = 0; \ u32 data = 0; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ 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); \ res = bus->ops->read(bus, devfn, pos, len, &data); \
*value = (type)data; \ *value = (type)data; \
raw_spin_unlock_irqrestore(&pci_lock, flags); \ pci_unlock_config(flags); \
return res; \ return res; \
} }
...@@ -47,9 +55,9 @@ int pci_bus_write_config_##size \ ...@@ -47,9 +55,9 @@ int pci_bus_write_config_##size \
int res; \ int res; \
unsigned long flags; \ unsigned long flags; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ 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); \ res = bus->ops->write(bus, devfn, pos, len, value); \
raw_spin_unlock_irqrestore(&pci_lock, flags); \ pci_unlock_config(flags); \
return res; \ return res; \
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment