Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1602908 > unrolled thread

[patch 0/7] x86/pci: Switch to lockless ECAM configuration mode

Started byThomas Gleixner <tglx@linutronix.de>
First post2017-03-17 00:20 +0100
Last post2017-03-17 00:20 +0100
Articles 13 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [patch 0/7] x86/pci: Switch to lockless ECAM configuration mode Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 00:20 +0100
    [patch 4/7] PCI: Provide Kconfig option for lockless config space  accessors Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 00:20 +0100
    [patch 1/7] x86/pci: Remove duplicate defines Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 00:20 +0100
    [patch 5/7] x86/pci: Select CONFIG_PCI_LOCKLESS_CONFIG Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 00:20 +0100
    [patch 3/7] x86/pci/ce4100: Properly lock accessor functions Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 00:20 +0100
      Re: [patch 3/7] x86/pci/ce4100: Properly lock accessor functions Andi Kleen <ak@linux.intel.com> - 2017-03-17 01:50 +0100
    [patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared code Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 00:20 +0100
      Re: [patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared  code Andi Kleen <ak@linux.intel.com> - 2017-03-17 01:40 +0100
        Re: [patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared  code Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 09:50 +0100
    [patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if possible Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 00:20 +0100
      Re: [patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if possible Andi Kleen <ak@linux.intel.com> - 2017-03-17 01:50 +0100
        Re: [patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if  possible Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 07:20 +0100
    [patch 2/7] x86/pci: Abort if legacy init fails Thomas Gleixner <tglx@linutronix.de> - 2017-03-17 00:20 +0100

#1602908 — [patch 0/7] x86/pci: Switch to lockless ECAM configuration mode

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 00:20 +0100
Subject[patch 0/7] x86/pci: Switch to lockless ECAM configuration mode
Message-ID<tlMQx-5vf-1@gated-at.bofh.it>
Andi reported that the Intel Uncore performance monitoring suffers from the
global pci_lock which protects the generic PCI config space accessors.

This lock can be removed on X86 because all architecture specific config
space accessors are either serialized by a seperate lock or can be
converted to have their own locking. The mmconfig based access (ECAM) does
not require serialization at the config read/write level because the access
is a simple byte/word/dword read from or write to the memory mapped
configuration space. In that case the lock does not provide any more
protection than the hardware provides already.

The series converts the CE4100 PCI low level accessors to use the x86
specific pci_config_lock and implements the switch over to lockless ECAM
configureation space accesors when the system is capable.

Thanks,

	tglx

---
 arch/x86/Kconfig               |    1 
 arch/x86/include/asm/pci.h     |    8 ---
 arch/x86/include/asm/pci_x86.h |   15 +++----
 arch/x86/pci/Makefile          |    2 
 arch/x86/pci/ce4100.c          |   87 ++++++++++++++++++++++-------------------
 arch/x86/pci/common.c          |   16 +++++++
 arch/x86/pci/legacy.c          |   19 +++++---
 arch/x86/pci/mmconfig-shared.c |   36 ++++++++++++++++
 arch/x86/pci/mmconfig_32.c     |   12 -----
 arch/x86/pci/mmconfig_64.c     |   16 +------
 drivers/pci/Kconfig            |    3 +
 drivers/pci/access.c           |   16 +++++--
 12 files changed, 142 insertions(+), 89 deletions(-)

[toc] | [next] | [standalone]


#1602909 — [patch 4/7] PCI: Provide Kconfig option for lockless config space accessors

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 00:20 +0100
Subject[patch 4/7] PCI: Provide Kconfig option for lockless config space accessors
Message-ID<tlMQx-5vf-3@gated-at.bofh.it>
In reply to#1602908
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>
---
 drivers/pci/Kconfig  |    3 +++
 drivers/pci/access.c |   16 ++++++++++++----
 2 files changed, 15 insertions(+), 4 deletions(-)

--- 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
--- 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;							\
 }
 

[toc] | [prev] | [next] | [standalone]


#1602910 — [patch 1/7] x86/pci: Remove duplicate defines

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 00:20 +0100
Subject[patch 1/7] x86/pci: Remove duplicate defines
Message-ID<tlMQx-5vf-7@gated-at.bofh.it>
In reply to#1602908
For some historic reason these defines are duplicated. Remove them.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/include/asm/pci.h |    8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -76,14 +76,8 @@ static inline bool is_vmd(struct pci_bus
 
 extern unsigned int pcibios_assign_all_busses(void);
 extern int pci_legacy_init(void);
-# ifdef CONFIG_ACPI
-#  define x86_default_pci_init pci_acpi_init
-# else
-#  define x86_default_pci_init pci_legacy_init
-# endif
 #else
-# define pcibios_assign_all_busses()	0
-# define x86_default_pci_init		NULL
+static inline int pcibios_assign_all_busses(void) { return 0; }
 #endif
 
 extern unsigned long pci_mem_start;

[toc] | [prev] | [next] | [standalone]


#1602911 — [patch 5/7] x86/pci: Select CONFIG_PCI_LOCKLESS_CONFIG

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 00:20 +0100
Subject[patch 5/7] x86/pci: Select CONFIG_PCI_LOCKLESS_CONFIG
Message-ID<tlMQx-5vf-15@gated-at.bofh.it>
In reply to#1602908
All x86 PCI configuration space accessors have either their own
serialization or can operate completely lockless (ECAM).

Disable the global lock in the generic PCI configuration space accessors.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/Kconfig |    1 +
 1 file changed, 1 insertion(+)

--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -165,6 +165,7 @@ config X86
 	select HAVE_UNSTABLE_SCHED_CLOCK
 	select HAVE_USER_RETURN_NOTIFIER
 	select IRQ_FORCED_THREADING
+	select PCI_LOCKLESS_CONFIG
 	select PERF_EVENTS
 	select RTC_LIB
 	select RTC_MC146818_LIB

[toc] | [prev] | [next] | [standalone]


#1602913 — [patch 3/7] x86/pci/ce4100: Properly lock accessor functions

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 00:20 +0100
Subject[patch 3/7] x86/pci/ce4100: Properly lock accessor functions
Message-ID<tlMQx-5vf-11@gated-at.bofh.it>
In reply to#1602908
x86 wants to get rid of the global pci_lock protecting the config space
accessors so ECAM mode can operate completely lockless, but the CE4100 pci
code relies on that to protect the simulation registers.

Restructure the code so it uses the x86 specific pci_config_lock to
serialize the inner workings of the CE4100 PCI magic. That allows to remove
the global locking via pci_lock later.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/pci/ce4100.c |   87 +++++++++++++++++++++++++++-----------------------
 1 file changed, 48 insertions(+), 39 deletions(-)

--- a/arch/x86/pci/ce4100.c
+++ b/arch/x86/pci/ce4100.c
@@ -65,6 +65,9 @@ struct sim_reg_op {
 { PCI_DEVFN(device, func), offset, init_op, read_op, write_op,\
 	{0, SIZE_TO_MASK(size)} },
 
+/*
+ * All read/write functions are called with pci_config_lock held.
+ */
 static void reg_init(struct sim_dev_reg *reg)
 {
 	pci_direct_conf1.read(0, 1, reg->dev_func, reg->reg, 4,
@@ -73,21 +76,13 @@ static void reg_init(struct sim_dev_reg
 
 static void reg_read(struct sim_dev_reg *reg, u32 *value)
 {
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&pci_config_lock, flags);
 	*value = reg->sim_reg.value;
-	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 }
 
 static void reg_write(struct sim_dev_reg *reg, u32 value)
 {
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&pci_config_lock, flags);
 	reg->sim_reg.value = (value & reg->sim_reg.mask) |
 		(reg->sim_reg.value & ~reg->sim_reg.mask);
-	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 }
 
 static void sata_reg_init(struct sim_dev_reg *reg)
@@ -117,12 +112,8 @@ static void sata_revid_read(struct sim_d
 
 static void reg_noirq_read(struct sim_dev_reg *reg, u32 *value)
 {
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&pci_config_lock, flags);
 	/* force interrupt pin value to 0 */
 	*value = reg->sim_reg.value & 0xfff00ff;
-	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 }
 
 static struct sim_dev_reg bus1_fixups[] = {
@@ -265,24 +256,33 @@ int bridge_read(unsigned int devfn, int
 	return retval;
 }
 
-static int ce4100_conf_read(unsigned int seg, unsigned int bus,
-			    unsigned int devfn, int reg, int len, u32 *value)
+static int ce4100_bus1_read(unsigned int devfn, int reg, int len, u32 *value)
 {
+	unsigned long flags;
 	int i;
 
-	WARN_ON(seg);
-	if (bus == 1) {
-		for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
-			if (bus1_fixups[i].dev_func == devfn &&
-			    bus1_fixups[i].reg == (reg & ~3) &&
-			    bus1_fixups[i].read) {
-				bus1_fixups[i].read(&(bus1_fixups[i]),
-						    value);
-				extract_bytes(value, reg, len);
-				return 0;
-			}
+	for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
+		if (bus1_fixups[i].dev_func == devfn &&
+		    bus1_fixups[i].reg == (reg & ~3) &&
+		    bus1_fixups[i].read) {
+
+			raw_spin_lock_irqsave(&pci_config_lock, flags);
+			bus1_fixups[i].read(&(bus1_fixups[i]), value);
+			raw_spin_unlock_irqrestore(&pci_config_lock, flags);
+			extract_bytes(value, reg, len);
+			return 0;
 		}
 	}
+	return -1;
+}
+
+static int ce4100_conf_read(unsigned int seg, unsigned int bus,
+			    unsigned int devfn, int reg, int len, u32 *value)
+{
+	WARN_ON(seg);
+
+	if (bus == 1 && !ce4100_bus1_read(devfn, reg, len, value))
+		return 0;
 
 	if (bus == 0 && (PCI_DEVFN(1, 0) == devfn) &&
 	    !bridge_read(devfn, reg, len, value))
@@ -291,23 +291,32 @@ static int ce4100_conf_read(unsigned int
 	return pci_direct_conf1.read(seg, bus, devfn, reg, len, value);
 }
 
-static int ce4100_conf_write(unsigned int seg, unsigned int bus,
-			     unsigned int devfn, int reg, int len, u32 value)
+static int ce4100_bus1_write(unsigned int devfn, int reg, int len, u32 value)
 {
+	unsigned long flags;
 	int i;
 
-	WARN_ON(seg);
-	if (bus == 1) {
-		for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
-			if (bus1_fixups[i].dev_func == devfn &&
-			    bus1_fixups[i].reg == (reg & ~3) &&
-			    bus1_fixups[i].write) {
-				bus1_fixups[i].write(&(bus1_fixups[i]),
-						     value);
-				return 0;
-			}
+	for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
+		if (bus1_fixups[i].dev_func == devfn &&
+		    bus1_fixups[i].reg == (reg & ~3) &&
+		    bus1_fixups[i].write) {
+
+			raw_spin_lock_irqsave(&pci_config_lock, flags);
+			bus1_fixups[i].write(&(bus1_fixups[i]), value);
+			raw_spin_unlock_irqrestore(&pci_config_lock, flags);
+			return 0;
 		}
 	}
+	return -1;
+}
+
+static int ce4100_conf_write(unsigned int seg, unsigned int bus,
+			     unsigned int devfn, int reg, int len, u32 value)
+{
+	WARN_ON(seg);
+
+	if (bus == 1 && !ce4100_bus1_write(devfn, reg, len, value))
+		return 0;
 
 	/* Discard writes to A/V bridge BAR. */
 	if (bus == 0 && PCI_DEVFN(1, 0) == devfn &&
@@ -318,8 +327,8 @@ static int ce4100_conf_write(unsigned in
 }
 
 static const struct pci_raw_ops ce4100_pci_conf = {
-	.read =	ce4100_conf_read,
-	.write = ce4100_conf_write,
+	.read	= ce4100_conf_read,
+	.write	= ce4100_conf_write,
 };
 
 int __init ce4100_pci_init(void)

[toc] | [prev] | [next] | [standalone]


#1602949 — Re: [patch 3/7] x86/pci/ce4100: Properly lock accessor functions

FromAndi Kleen <ak@linux.intel.com>
Date2017-03-17 01:50 +0100
SubjectRe: [patch 3/7] x86/pci/ce4100: Properly lock accessor functions
Message-ID<tlOfD-6lR-11@gated-at.bofh.it>
In reply to#1602913
Except for the comments the patches look good to me. Haven't tested so far.

Reviewed-by: Andi Kleen <ak@linux.intel.com>

[toc] | [prev] | [next] | [standalone]


#1602914 — [patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared code

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 00:20 +0100
Subject[patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared code
Message-ID<tlMQx-5vf-13@gated-at.bofh.it>
In reply to#1602908
Preparatory patch so the shared mmconfig code can access static functions
in the 32/64bit specific mmconfig implementations.

This is useful for the upcoming implementation of mmconfig based (ECAM) PCI
configuration space access for both the legacy part (0-0xff) and the
extended part (0x100-0xfff). Being able to access the low level mmconfig
read/write functions directly avoids extra indirections.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/pci/Makefile          |    2 +-
 arch/x86/pci/mmconfig-shared.c |    6 ++++++
 arch/x86/pci/mmconfig_32.c     |   12 ++----------
 arch/x86/pci/mmconfig_64.c     |   16 ++++------------
 4 files changed, 13 insertions(+), 23 deletions(-)

--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -1,7 +1,7 @@
 obj-y				:= i386.o init.o
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
-obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig_$(BITS).o direct.o mmconfig-shared.o
+obj-$(CONFIG_PCI_MMCONFIG)	+= direct.o mmconfig-shared.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
 obj-$(CONFIG_PCI_OLPC)		+= olpc.o
 obj-$(CONFIG_PCI_XEN)		+= xen.o
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -24,6 +24,12 @@
 
 #define PREFIX "PCI: "
 
+#ifdef CONFIG_X86_64
+# include "mmconfig_64.c"
+#else
+# include "mmconfig_32.c"
+#endif
+
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static bool pci_mmcfg_running_state;
 static bool pci_mmcfg_arch_init_failed;
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -3,18 +3,10 @@
  * Copyright (C) 2004 Intel Corp.
  *
  * This code is released under the GNU General Public License version 2.
+ *
+ * Low-level direct PCI config space access via MMCONFIG, 32bit version.
  */
 
-/*
- * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
- */
-
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/rcupdate.h>
-#include <asm/e820.h>
-#include <asm/pci_x86.h>
-
 /* Assume systems with more busses have correct MCFG */
 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
 
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -1,20 +1,12 @@
 /*
- * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
+ * Low-level direct PCI config space access via MMCONFIG
  *
  * This is an 64bit optimized version that always keeps the full mmconfig
  * space mapped. This allows lockless config space operation.
+ *
+ * This file is included into the 32/64bit shared code so the read/write
+ * accessors are directly reachable there.
  */
-
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/acpi.h>
-#include <linux/bitmap.h>
-#include <linux/rcupdate.h>
-#include <asm/e820.h>
-#include <asm/pci_x86.h>
-
-#define PREFIX "PCI: "
-
 static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
 {
 	struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);

[toc] | [prev] | [next] | [standalone]


#1602938 — Re: [patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared code

FromAndi Kleen <ak@linux.intel.com>
Date2017-03-17 01:40 +0100
SubjectRe: [patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared code
Message-ID<tlO5Y-6ig-25@gated-at.bofh.it>
In reply to#1602914
> --- a/arch/x86/pci/mmconfig-shared.c
> +++ b/arch/x86/pci/mmconfig-shared.c
> @@ -24,6 +24,12 @@
>  
>  #define PREFIX "PCI: "
>  
> +#ifdef CONFIG_X86_64
> +# include "mmconfig_64.c"
> +#else
> +# include "mmconfig_32.c"
> +#endif

This seems like a bad hack. If you want to access something from
multiple files just make it global, don't play preprocessor tricks.

-Andi

[toc] | [prev] | [next] | [standalone]


#1603118 — Re: [patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared code

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 09:50 +0100
SubjectRe: [patch 6/7] x86/pci/mmcfg: Include 32/64 bit code into shared code
Message-ID<tlVKa-3Fq-15@gated-at.bofh.it>
In reply to#1602938
On Thu, 16 Mar 2017, Andi Kleen wrote:
> > --- a/arch/x86/pci/mmconfig-shared.c
> > +++ b/arch/x86/pci/mmconfig-shared.c
> > @@ -24,6 +24,12 @@
> >  
> >  #define PREFIX "PCI: "
> >  
> > +#ifdef CONFIG_X86_64
> > +# include "mmconfig_64.c"
> > +#else
> > +# include "mmconfig_32.c"
> > +#endif
> 
> This seems like a bad hack. If you want to access something from
> multiple files just make it global, don't play preprocessor tricks.

That's a leftover from an earlier iteration of the patches, where including
the code made a significant text size difference. Forgot to recheck. With
the current version the difference is minimal. I'll drop it.

Thanks,

	tglx

[toc] | [prev] | [next] | [standalone]


#1602915 — [patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if possible

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 00:20 +0100
Subject[patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if possible
Message-ID<tlMQx-5vf-17@gated-at.bofh.it>
In reply to#1602908
To allow lockless access to the whole PCI configuration space the mmconfig
based accessor functions need to be propagated to the pci_root_ops.

Unfortunatly this cannot be done before the PCI subsystem initialization
happens even if mmconfig access is already available. The reason is that
some of the special platform PCI implementations must be able to overrule
that setting before further accesses happen.

The earliest possible point is after x86_init.pci.init() has been run. This
is at a point in the boot process where nothing actually uses the PCI
devices so the accessor function pointers can be updated lockless w/o risk.

The switch to full ECAM mode depends on the availability of mmconfig and
unchanged default accessors.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/include/asm/pci_x86.h |   15 +++++++--------
 arch/x86/pci/common.c          |   16 ++++++++++++++++
 arch/x86/pci/legacy.c          |    1 +
 arch/x86/pci/mmconfig-shared.c |   30 ++++++++++++++++++++++++++++++
 4 files changed, 54 insertions(+), 8 deletions(-)

--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -46,20 +46,14 @@ enum pci_bf_sort_state {
 	pci_dmi_bf,
 };
 
-/* pci-i386.c */
-
 void pcibios_resource_survey(void);
 void pcibios_set_cache_line_size(void);
 
-/* pci-pc.c */
-
 extern int pcibios_last_bus;
 extern struct pci_ops pci_root_ops;
 
 void pcibios_scan_specific_bus(int busn);
 
-/* pci-irq.c */
-
 struct irq_info {
 	u8 bus, devfn;			/* Bus, device and function */
 	struct {
@@ -120,11 +114,10 @@ extern void __init dmi_check_skip_isa_al
 extern int __init pci_acpi_init(void);
 extern void __init pcibios_irq_init(void);
 extern int __init pcibios_init(void);
+extern void __init pcibios_select_ops(void);
 extern int pci_legacy_init(void);
 extern void pcibios_fixup_irqs(void);
 
-/* pci-mmconfig.c */
-
 /* "PCI MMCONFIG %04x [bus %02x-%02x]" */
 #define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
 
@@ -139,6 +132,12 @@ struct pci_mmcfg_region {
 	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
 };
 
+#ifdef CONFIG_PCI_MMCONFIG
+extern void __init pci_mmcfg_select_ops(void);
+#else
+static inline void pci_mmcfg_select_ops(void) { }
+#endif
+
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
 extern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -157,6 +157,22 @@ static void pcibios_fixup_device_resourc
 }
 
 /*
+ * Called after the last possible modification to raw_pci_[ext_]ops.
+ *
+ * Verify that root_pci_ops have not been overwritten by any implementation
+ * of x86_init.pci.arch_init() and x86_init.pci.init().
+ *
+ * If not, let the mmconfig code decide whether the ops can be switched
+ * over to the ECAM accessor functions.
+ */
+void __init pcibios_select_ops(void)
+{
+	if (pci_root_ops.read != pci_read || pci_root_ops.write != pci_write)
+		return;
+	pci_mmcfg_select_ops();
+}
+
+/*
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -65,6 +65,7 @@ static int __init pci_subsys_init(void)
 		}
 	}
 
+	pcibios_select_ops();
 	pcibios_fixup_peer_bridges();
 	x86_init.pci.init_irq();
 	pcibios_init();
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -822,3 +822,33 @@ int pci_mmconfig_delete(u16 seg, u8 star
 
 	return -ENOENT;
 }
+
+static int pci_ecam_read(struct pci_bus *bus, unsigned int devfn, int reg,
+			 int size, u32 *value)
+{
+	return pci_mmcfg_read(pci_domain_nr(bus), bus->number, devfn, reg,
+			      size, value);
+}
+
+static int pci_ecam_write(struct pci_bus *bus, unsigned int devfn, int reg,
+			  int size, u32 value)
+{
+	return pci_mmcfg_write(pci_domain_nr(bus), bus->number, devfn, reg,
+			       size, value);
+}
+
+void __init pci_mmcfg_select_ops(void)
+{
+	if (raw_pci_ext_ops != &pci_mmcfg)
+		return;
+
+	/*
+	 * The pointer to root_pci_ops has been handed in to ACPI already
+	 * and is already set in the busses.
+	 *
+	 * Switch the functions over to ECAM for all config space accesses.
+	 */
+	pci_root_ops.read = pci_ecam_read;
+	pci_root_ops.write = pci_ecam_write;
+	pr_info("PCI: Switch to ECAM configuration mode\n");
+}

[toc] | [prev] | [next] | [standalone]


#1602944 — Re: [patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if possible

FromAndi Kleen <ak@linux.intel.com>
Date2017-03-17 01:50 +0100
SubjectRe: [patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if possible
Message-ID<tlOfD-6lR-7@gated-at.bofh.it>
In reply to#1602915
> +	/*
> +	 * The pointer to root_pci_ops has been handed in to ACPI already
> +	 * and is already set in the busses.
> +	 *
> +	 * Switch the functions over to ECAM for all config space accesses.
> +	 */
> +	pci_root_ops.read = pci_ecam_read;
> +	pci_root_ops.write = pci_ecam_write;
> +	pr_info("PCI: Switch to ECAM configuration mode\n");

That patch is fine, but it's generally called MMCONFIG (don't know
where this ECAM term comes from). So please use MMCONFIG or MCFG everywhere,
not ECAM.

-Andi

[toc] | [prev] | [next] | [standalone]


#1603054 — Re: [patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if possible

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 07:20 +0100
SubjectRe: [patch 7/7] x86/pci/mmcfg: Switch to ECAM config mode if possible
Message-ID<tlToZ-1N4-3@gated-at.bofh.it>
In reply to#1602944
On Thu, 16 Mar 2017, Andi Kleen wrote:

> > +	/*
> > +	 * The pointer to root_pci_ops has been handed in to ACPI already
> > +	 * and is already set in the busses.
> > +	 *
> > +	 * Switch the functions over to ECAM for all config space accesses.
> > +	 */
> > +	pci_root_ops.read = pci_ecam_read;
> > +	pci_root_ops.write = pci_ecam_write;
> > +	pr_info("PCI: Switch to ECAM configuration mode\n");
> 
> That patch is fine, but it's generally called MMCONFIG (don't know
> where this ECAM term comes from).

ECAM is the official name for the memory mapped configuration mechanism
according to the PCI express specification.

> So please use MMCONFIG or MCFG everywhere, not ECAM.

While I prefer using names which match specifications, I let Bjorn decide
on that one.

Thanks,

	tglx

[toc] | [prev] | [next] | [standalone]


#1602916 — [patch 2/7] x86/pci: Abort if legacy init fails

FromThomas Gleixner <tglx@linutronix.de>
Date2017-03-17 00:20 +0100
Subject[patch 2/7] x86/pci: Abort if legacy init fails
Message-ID<tlMQx-5vf-21@gated-at.bofh.it>
In reply to#1602908
If the legacy pci init fails, then there are no pci config space accesors
available, but the code continues and tries to scan the busses, which fails
due to the lack of config space accessors.

Return right away, if the last init fallback fails.

Switch the few printks to pr_info while at it.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/pci/legacy.c |   18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -24,12 +24,10 @@ static void pcibios_fixup_peer_bridges(v
 
 int __init pci_legacy_init(void)
 {
-	if (!raw_pci_ops) {
-		printk("PCI: System does not support PCI\n");
-		return 0;
-	}
+	if (!raw_pci_ops)
+		return 1;
 
-	printk("PCI: Probing PCI hardware\n");
+	pr_info("PCI: Probing PCI hardware\n");
 	pcibios_scan_root(0);
 	return 0;
 }
@@ -46,7 +44,7 @@ void pcibios_scan_specific_bus(int busn)
 		if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
 		    l != 0x0000 && l != 0xffff) {
 			DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
-			printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn);
+			pr_info("PCI: Discovered peer bus %02x\n", busn);
 			pcibios_scan_root(busn);
 			return;
 		}
@@ -60,8 +58,12 @@ static int __init pci_subsys_init(void)
 	 * The init function returns an non zero value when
 	 * pci_legacy_init should be invoked.
 	 */
-	if (x86_init.pci.init())
-		pci_legacy_init();
+	if (x86_init.pci.init()) {
+		if (pci_legacy_init()) {
+			pr_info("PCI: System does not support PCI\n");
+			return -ENODEV;
+		}
+	}
 
 	pcibios_fixup_peer_bridges();
 	x86_init.pci.init_irq();

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web