Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 1570

kernel-2.6.18-194.11.1.el5.src.rpm

From: Bhavna Sarathy <bnagendr@redhat.com>
Date: Wed, 3 Feb 2010 20:45:13 -0500
Subject: [misc] EDAC driver fix for non-MMCONFIG systems
Message-id: <4B69E059.7050309@redhat.com>
Patchwork-id: 23120
O-Subject: Re: [RHEL5.5 PATCH] EDAC driver fix for non-MMCONFIG systems
Bugzilla: 550123
RH-Acked-by: Andrew Jones <drjones@redhat.com>
RH-Acked-by: Mauro Carvalho Chehab <mchehab@redhat.com>
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>

Resolved BZ 550123

x86: add PCI extended config space access for AMD F10h

This patch implements PCI extended configuration space access for
AMD's Barcelona and later CPUs. It extends the method using CF8/CFC IO
addresses. An x86 capability bit has been introduced that is set for
CPUs supporting PCI extended config space accesses.

(backport of upstream commit id:
831d991821daedd4839073dbca55514432ef1768)

Signed-off-by: Jarod Wilson <jarod@redhat.com>

diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index c201a15..2b8c150 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -1,6 +1,7 @@
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/mm.h>
+#include <linux/setup.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/pci-direct.h>
@@ -312,6 +313,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 
 	if ((c->x86 == 0x10 || c->x86 == 0x11) && !force_mwait)
 		clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
+
+	if (c->x86 >= 0x10)
+		amd_enable_pci_ext_cfg(c);
 }
 
 static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index 5961dc6..9004085 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -26,6 +26,7 @@ int pcibios_last_bus = -1;
 unsigned long pirq_table_addr;
 struct pci_bus *pci_root_bus;
 struct pci_raw_ops *raw_pci_ops;
+struct pci_raw_ops *raw_pci_ext_ops;
 
 #ifdef CONFIG_X86
 int pci_noseg = 0;
@@ -33,16 +34,28 @@ int pci_noseg = 0;
 
 struct pci_sysdata pci_default_sysdata = { .node = -1 };
 
-static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
+static int pci_read(struct pci_bus *bus, unsigned int devfn, int reg, int size,
+		    u32 *value)
 {
-	return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
-				 devfn, where, size, value);
+	if (raw_pci_ops && (reg < 256 || (pci_probe & PCI_USING_MMCONF)))
+		return raw_pci_ops->read(pci_domain_nr(bus), bus->number, devfn,
+					 reg, size, value);
+	if (raw_pci_ext_ops)
+		return raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number,
+					     devfn, reg, size, value);
+	return -EINVAL;
 }
 
-static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
+static int pci_write(struct pci_bus *bus, unsigned int devfn, int reg, int size,
+		     u32 value)
 {
-	return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
-				  devfn, where, size, value);
+	if (raw_pci_ops && (reg < 256 || (pci_probe & PCI_USING_MMCONF)))
+		return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
+					  devfn, reg, size, value);
+	if (raw_pci_ext_ops)
+		return raw_pci_ext_ops->write(pci_domain_nr(bus), bus->number,
+					      devfn, reg, size, value);
+	return -EINVAL;
 }
 
 struct pci_ops pci_root_ops = {
diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c
index 5d81fb5..79aced0 100644
--- a/arch/i386/pci/direct.c
+++ b/arch/i386/pci/direct.c
@@ -8,18 +8,21 @@
 #include "pci.h"
 
 /*
- * Functions for accessing PCI configuration space with type 1 accesses
+ * Functions for accessing PCI base (first 256 bytes) and extended
+ * (4096 bytes per PCI function) configuration space with type 1
+ * accesses.
  */
 
 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
-	(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
+	(0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
+	| (devfn << 8) | (reg & 0xFC))
 
 int pci_conf1_read(unsigned int seg, unsigned int bus,
 			  unsigned int devfn, int reg, int len, u32 *value)
 {
 	unsigned long flags;
 
-	if ((bus > 255) || (devfn > 255) || (reg > 255)) {
+	if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
 		*value = -1;
 		return -EINVAL;
 	}
@@ -50,7 +53,7 @@ int pci_conf1_write(unsigned int seg, unsigned int bus,
 {
 	unsigned long flags;
 
-	if ((bus > 255) || (devfn > 255) || (reg > 255)) 
+	if ((bus > 255) || (devfn > 255) || (reg > 4095))
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -267,6 +270,12 @@ void __init pci_direct_init(void)
 	if (pci_check_type1()) {
 		printk(KERN_INFO "PCI: Using configuration type 1\n");
 		raw_pci_ops = &pci_direct_conf1;
+
+		if (!raw_pci_ext_ops && cpu_has_pci_ext_cfg) {
+			printk(KERN_INFO "PCI: Using configuration type 1 "
+					"for extended access\n");
+			raw_pci_ext_ops = &pci_direct_conf1;
+		}
 		return;
 	}
 	release_resource(region);
diff --git a/arch/x86_64/kernel/setup-xen.c b/arch/x86_64/kernel/setup-xen.c
index debea88..666ecd7 100644
--- a/arch/x86_64/kernel/setup-xen.c
+++ b/arch/x86_64/kernel/setup-xen.c
@@ -45,6 +45,7 @@
 #include <linux/dmi.h>
 #include <linux/dma-mapping.h>
 #include <linux/ctype.h>
+#include <linux/setup.h>
 
 #include <asm/mtrr.h>
 #include <asm/uaccess.h>
@@ -1191,6 +1192,9 @@ static void __init init_amd(struct cpuinfo_x86 *c)
 
 	/* Fix cpuid4 emulation for more */
 	num_cache_leaves = 3;
+
+	if (c->x86 >= 0x10)
+		amd_enable_pci_ext_cfg(c);
 }
 
 static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index ad74550..13fc8ea 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -46,6 +46,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/ctype.h>
 #include <linux/efi.h>
+#include <linux/setup.h>
 
 #include <asm/mtrr.h>
 #include <asm/uaccess.h>
@@ -980,6 +981,9 @@ static void __init init_amd(struct cpuinfo_x86 *c)
 	if (c->x86 == 0x10 && !force_mwait)
 		clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
 	set_bit(X86_FEATURE_MFENCE_RDTSC, &c->x86_capability);
+
+	if (c->x86 >= 0x10)
+		amd_enable_pci_ext_cfg(c);
 }
 
 static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 7bf5921..d13ab75 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2613,7 +2613,7 @@ static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
 {
        int node_id = pvt->mc_node_id;
        struct mem_ctl_info *mci;
-       int ret;
+	int ret = -ENODEV;
 
        amd64_read_mc_registers(pvt);
 
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index 0202008..52f50f5 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -76,6 +76,7 @@
 #define X86_FEATURE_IDA		(3*32+16) /* Intel Dynamic Acceleration */
 #define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */
 #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
+#define X86_FEATURE_PCI_EXT_CFG	(3*32+19) /* PCI extended cfg access */
 #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
 #define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */
 #define X86_FEATURE_ARAT	(3*32+25) /* Always Running APIC Timer */
@@ -162,6 +163,7 @@
 #define cpu_has_hypervisor	boot_cpu_has(X86_FEATURE_HYPERVISOR)
 #define cpu_has_xmm4_1		boot_cpu_has(X86_FEATURE_XMM4_1)
 #define cpu_has_xmm4_2		boot_cpu_has(X86_FEATURE_XMM4_2)
+#define cpu_has_pci_ext_cfg	boot_cpu_has(X86_FEATURE_PCI_EXT_CFG)
 
 #endif /* __ASM_I386_CPUFEATURE_H */
 
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index 9cb6ecc..a57ec13 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -251,6 +251,9 @@ static inline void wrmsrl (unsigned long msr, unsigned long long val)
 #define MSR_K7_FID_VID_CTL		0xC0010041
 #define MSR_K7_FID_VID_STATUS		0xC0010042
 
+#define ENABLE_CF8_EXT_CFG		(1ULL << 46)
+#define MSR_K8_NB_CFG			0xc001001f
+
 /* extended feature register */
 #define MSR_EFER 			0xc0000080
 
diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h
index e07bb14..dc2973f 100644
--- a/include/asm-x86_64/cpufeature.h
+++ b/include/asm-x86_64/cpufeature.h
@@ -71,6 +71,7 @@
 #define X86_FEATURE_IDA		(3*32+16) /* Intel Dynamic Acceleration */
 #define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */
 #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
+#define X86_FEATURE_PCI_EXT_CFG	(3*32+19) /* PCI extended cfg access */
 #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
 #define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */
 #define X86_FEATURE_ARAT	(3*32+25) /* Always Running APIC Timer */
@@ -144,5 +145,6 @@
 #define cpu_has_hypervisor	boot_cpu_has(X86_FEATURE_HYPERVISOR)
 #define cpu_has_xmm4_1		boot_cpu_has(X86_FEATURE_XMM4_1)
 #define cpu_has_xmm4_2		boot_cpu_has(X86_FEATURE_XMM4_2)
+#define cpu_has_pci_ext_cfg	boot_cpu_has(X86_FEATURE_PCI_EXT_CFG)
 
 #endif /* __ASM_X8664_CPUFEATURE_H */
diff --git a/include/asm-x86_64/mach-xen/asm/msr.h b/include/asm-x86_64/mach-xen/asm/msr.h
index 4b44263..88817f4 100644
--- a/include/asm-x86_64/mach-xen/asm/msr.h
+++ b/include/asm-x86_64/mach-xen/asm/msr.h
@@ -161,6 +161,8 @@ static inline unsigned int cpuid_edx(unsigned int op)
 #define MSR_FS_BASE 0xc0000100		/* 64bit GS base */
 #define MSR_GS_BASE 0xc0000101		/* 64bit FS base */
 #define MSR_KERNEL_GS_BASE  0xc0000102	/* SwapGS GS shadow (or USER_GS from kernel) */ 
+#define ENABLE_CF8_EXT_CFG	(1ULL << 46)
+#define MSR_K8_NB_CFG	0xc001001f
 /* EFER bits: */ 
 #define _EFER_SCE 0  /* SYSCALL/SYSRET */
 #define _EFER_LME 8  /* Long mode enable */
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
index 7de513d..00c24e7 100644
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -187,6 +187,9 @@ static inline void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
 #define MSR_FS_BASE 0xc0000100		/* 64bit GS base */
 #define MSR_GS_BASE 0xc0000101		/* 64bit FS base */
 #define MSR_KERNEL_GS_BASE  0xc0000102	/* SwapGS GS shadow (or USER_GS from kernel) */ 
+
+#define ENABLE_CF8_EXT_CFG      (1ULL << 46)
+#define MSR_K8_NB_CFG 0xc001001f
 /* EFER bits: */ 
 #define _EFER_SCE 0  /* SYSCALL/SYSRET */
 #define _EFER_LME 8  /* Long mode enable */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index e72580f..4963e53 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -338,6 +338,7 @@ struct pci_raw_ops {
 };
 
 extern struct pci_raw_ops *raw_pci_ops;
+extern struct pci_raw_ops *raw_pci_ext_ops;
 
 #ifdef CONFIG_64BIT
 struct pci_bus_region {
diff --git a/include/linux/setup.h b/include/linux/setup.h
new file mode 100644
index 0000000..a82ab71
--- /dev/null
+++ b/include/linux/setup.h
@@ -0,0 +1,16 @@
+#ifndef _LINUX_SETUP_H
+#define _LINUX_SETUP_H */
+
+static inline void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c)
+{
+	u64 reg;
+	rdmsrl(MSR_K8_NB_CFG, reg);
+	if (!(reg & ENABLE_CF8_EXT_CFG)) {
+		reg |= ENABLE_CF8_EXT_CFG;
+		wrmsrl(MSR_K8_NB_CFG, reg);
+	}
+	set_bit(X86_FEATURE_PCI_EXT_CFG, &c->x86_capability);
+}
+
+#endif  /* _LINUX_SETUP_H */
+