summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-03-17 00:50:06 +0300
committerThomas Gleixner <tglx@linutronix.de>2017-06-28 23:32:56 +0300
commit714fe383d6c9bd95d0d2cad8cbeff3688342d025 (patch)
tree183bc2a1007b91839c7e29ebaefc29dd8ca68984
parentbb290fda879ffd1f6f6b0869bf7335554093f4bd (diff)
downloadlinux-714fe383d6c9bd95d0d2cad8cbeff3688342d025.tar.xz
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>
-rw-r--r--drivers/pci/Kconfig3
-rw-r--r--drivers/pci/access.c16
2 files changed, 15 insertions, 4 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index e0cacb7b8563..c32a77fc8b03 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -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
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index c80e37a69305..913d6722ece9 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -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; \
}