Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin J. Bligh <martin.bligh@us.ibm.com>2002-03-07 00:54:03 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-03-07 00:54:03 -0800
commit8ca541f55c1f1d48704e20e26ddfcc2786068229 (patch)
tree3ff8e6e37141d524a1a7794d0c04a761e6827614
parent639f87714e1a45e29647289cb2e81954ef1a5e7b (diff)
[PATCH] forward port of NUMA-Q pci patch from 2.4.19-pre2
This patch enables PCI buses on nodes above node 0 for the NUMA-Q architecture. It also enables node-directed port/IO, and cleans up a couple of tiny things that only affect CONFIG_MULTIQUAD.
-rw-r--r--arch/i386/kernel/mpparse.c19
-rw-r--r--arch/i386/kernel/pci-pc.c94
-rw-r--r--arch/i386/kernel/smpboot.c13
-rw-r--r--include/asm-i386/io.h62
-rw-r--r--include/asm-i386/mpspec.h3
5 files changed, 150 insertions, 41 deletions
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index eb6f71e02b02..862e80c26f3a 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -37,6 +37,8 @@ int smp_found_config;
int apic_version [MAX_APICS];
int mp_bus_id_to_type [MAX_MP_BUSSES];
int mp_bus_id_to_node [MAX_MP_BUSSES];
+int mp_bus_id_to_local [MAX_MP_BUSSES];
+int quad_local_to_mp_bus_id [NR_CPUS/4][4];
int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
int mp_current_pci_id;
@@ -241,13 +243,17 @@ void __init MP_processor_info (struct mpc_config_processor *m)
static void __init MP_bus_info (struct mpc_config_bus *m)
{
char str[7];
+ int quad;
memcpy(str, m->mpc_bustype, 6);
str[6] = 0;
if (clustered_apic_mode) {
- mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad;
- printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]);
+ quad = translation_table[mpc_record]->trans_quad;
+ mp_bus_id_to_node[m->mpc_busid] = quad;
+ mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local;
+ quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid;
+ printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad);
} else {
Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
}
@@ -324,13 +330,14 @@ static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
static void __init MP_translation_info (struct mpc_config_translation *m)
{
- printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type,
- m->trans_quad, m->trans_global, m->trans_local);
+ printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local);
if (mpc_record >= MAX_MPC_ENTRY)
printk("MAX_MPC_ENTRY exceeded!\n");
else
translation_table[mpc_record] = m; /* stash this for later */
+ if (m->trans_quad+1 > numnodes)
+ numnodes = m->trans_quad+1;
}
/*
@@ -495,10 +502,6 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
}
++mpc_record;
}
- if (clustered_apic_mode && nr_ioapics > 2) {
- /* don't initialise IO apics on secondary quads */
- nr_ioapics = 2;
- }
if (!num_processors)
printk(KERN_ERR "SMP mptable: no processors registered!\n");
return num_processors;
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
index 5abb2259c192..7281c71e0467 100644
--- a/arch/i386/kernel/pci-pc.c
+++ b/arch/i386/kernel/pci-pc.c
@@ -14,6 +14,7 @@
#include <asm/segment.h>
#include <asm/io.h>
+#include <asm/smp.h>
#include "pci-i386.h"
@@ -26,6 +27,16 @@ struct pci_ops *pci_root_ops = NULL;
int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL;
int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL;
+#ifdef CONFIG_MULTIQUAD
+#define BUS2QUAD(global) (mp_bus_id_to_node[global])
+#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
+#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
+#else
+#define BUS2QUAD(global) (0)
+#define BUS2LOCAL(global) (global)
+#define QUADLOCAL2BUS(quad,local) (local)
+#endif
+
/*
* This interrupt-safe spinlock protects all accesses to PCI
* configuration space.
@@ -39,10 +50,71 @@ static spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED;
#ifdef CONFIG_PCI_DIRECT
+#ifdef CONFIG_MULTIQUAD
+#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
+ (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
+
+static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */
+{
+ unsigned long flags;
+
+ if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+ return -EINVAL;
+
+ spin_lock_irqsave(&pci_config_lock, flags);
+
+ outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+ switch (len) {
+ case 1:
+ *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
+ break;
+ case 2:
+ *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
+ break;
+ case 4:
+ *value = inl_quad(0xCFC, BUS2QUAD(bus));
+ break;
+ }
+
+ spin_unlock_irqrestore(&pci_config_lock, flags);
+
+ return 0;
+}
+
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */
+{
+ unsigned long flags;
+
+ if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+ return -EINVAL;
+
+ spin_lock_irqsave(&pci_config_lock, flags);
+
+ outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+ switch (len) {
+ case 1:
+ outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
+ break;
+ case 2:
+ outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
+ break;
+ case 4:
+ outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
+ break;
+ }
+
+ spin_unlock_irqrestore(&pci_config_lock, flags);
+
+ return 0;
+}
+
+#else /* !CONFIG_MULTIQUAD */
#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
-static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* !CONFIG_MULTIQUAD */
{
unsigned long flags;
@@ -70,7 +142,7 @@ static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len,
return 0;
}
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* !CONFIG_MULTIQUAD */
{
unsigned long flags;
@@ -98,6 +170,8 @@ static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len,
return 0;
}
+#endif /* CONFIG_MULTIQUAD */
+
#undef PCI_CONF1_ADDRESS
static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
@@ -1017,6 +1091,8 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
*/
int pxb, reg;
u8 busno, suba, subb;
+ int quad = BUS2QUAD(d->bus->number);
+
printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
reg = 0xd0;
for(pxb=0; pxb<2; pxb++) {
@@ -1025,9 +1101,9 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
pci_read_config_byte(d, reg++, &subb);
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
if (busno)
- pci_scan_bus(busno, pci_root_ops, NULL); /* Bus A */
+ pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL); /* Bus A */
if (suba < subb)
- pci_scan_bus(suba+1, pci_root_ops, NULL); /* Bus B */
+ pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL); /* Bus B */
}
pcibios_last_bus = -1;
}
@@ -1199,6 +1275,8 @@ void __devinit pcibios_config_init(void)
void __init pcibios_init(void)
{
+ int quad;
+
if (!pci_root_ops)
pcibios_config_init();
if (!pci_root_ops) {
@@ -1208,6 +1286,14 @@ void __init pcibios_init(void)
printk("PCI: Probing PCI hardware\n");
pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
+ if (clustered_apic_mode && (numnodes > 1)) {
+ for (quad = 1; quad < numnodes; ++quad) {
+ printk("Scanning PCI bus %d for quad %d\n",
+ QUADLOCAL2BUS(quad,0), quad);
+ pci_scan_bus(QUADLOCAL2BUS(quad,0),
+ pci_root_ops, NULL);
+ }
+ }
pcibios_irq_init();
pcibios_fixup_peer_bridges();
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index f5449dadbc5a..34b0d8ac6f9a 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -1012,11 +1012,14 @@ void __init smp_boot_cpus(void)
{
int apicid, cpu, bit;
- if (clustered_apic_mode) {
- /* remap the 1st quad's 256k range for cross-quad I/O */
- xquad_portio = ioremap (XQUAD_PORTIO_BASE, XQUAD_PORTIO_LEN);
- printk("Cross quad port I/O vaddr 0x%08lx, len %08lx\n",
- (u_long) xquad_portio, (u_long) XQUAD_PORTIO_LEN);
+ if (clustered_apic_mode && (numnodes > 1)) {
+ printk("Remapping cross-quad port I/O for %d quads\n",
+ numnodes);
+ printk("xquad_portio vaddr 0x%08lx, len %08lx\n",
+ (u_long) xquad_portio,
+ (u_long) numnodes * XQUAD_PORTIO_LEN);
+ xquad_portio = ioremap (XQUAD_PORTIO_BASE,
+ numnodes * XQUAD_PORTIO_LEN);
}
#ifdef CONFIG_MTRR
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index 1d12e37180ac..f578b76c40cf 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -39,7 +39,8 @@
#define IO_SPACE_LIMIT 0xffff
#define XQUAD_PORTIO_BASE 0xfe400000
-#define XQUAD_PORTIO_LEN 0x40000 /* 256k per quad. Only remapping 1st */
+#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
+#define XQUAD_PORTIO_LEN 0x80000 /* Only remapping first 2 quads */
#ifdef __KERNEL__
@@ -261,52 +262,65 @@ static inline void out##s(unsigned x value, unsigned short port) {
__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
#ifdef CONFIG_MULTIQUAD
-/* Make the default portio routines operate on quad 0 for now */
-#define __OUT(s,s1,x) \
-__OUT1(s##_local,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
-__OUTQ0(s,s,x) \
-__OUTQ0(s,s##_p,x)
-#else
-#define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));}
-#endif /* CONFIG_MULTIQUAD */
-
-#ifdef CONFIG_MULTIQUAD
-#define __OUTQ0(s,ss,x) /* Do the equivalent of the portio op on quad 0 */ \
+#define __OUTQ(s,ss,x) /* Do the equivalent of the portio op on quads */ \
static inline void out##ss(unsigned x value, unsigned short port) { \
if (xquad_portio) \
write##s(value, (unsigned long) xquad_portio + port); \
else /* We're still in early boot, running on quad 0 */ \
out##ss##_local(value, port); \
-}
+} \
+static inline void out##ss##_quad(unsigned x value, unsigned short port, int quad) { \
+ if (xquad_portio) \
+ write##s(value, (unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
+ + port); \
+}
-#define __INQ0(s,ss) /* Do the equivalent of the portio op on quad 0 */ \
+#define __INQ(s,ss) /* Do the equivalent of the portio op on quads */ \
static inline RETURN_TYPE in##ss(unsigned short port) { \
if (xquad_portio) \
return read##s((unsigned long) xquad_portio + port); \
else /* We're still in early boot, running on quad 0 */ \
return in##ss##_local(port); \
+} \
+static inline RETURN_TYPE in##ss##_quad(unsigned short port, int quad) { \
+ if (xquad_portio) \
+ return read##s((unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
+ + port); \
+ else\
+ return 0;\
}
#endif /* CONFIG_MULTIQUAD */
+#ifndef CONFIG_MULTIQUAD
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));}
+#else
+/* Make the default portio routines operate on quad 0 */
+#define __OUT(s,s1,x) \
+__OUT1(s##_local,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUTQ(s,s,x) \
+__OUTQ(s,s##_p,x)
+#endif /* CONFIG_MULTIQUAD */
+
#define __IN1(s) \
static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
#define __IN2(s,s1,s2) \
__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
-#ifdef CONFIG_MULTIQUAD
-#define __IN(s,s1,i...) \
-__IN1(s##_local) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__INQ0(s,s) \
-__INQ0(s,s##_p)
-#else
+#ifndef CONFIG_MULTIQUAD
#define __IN(s,s1,i...) \
__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; }
+#else
+/* Make the default portio routines operate on quad 0 */
+#define __IN(s,s1,i...) \
+__IN1(s##_local) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__INQ(s,s) \
+__INQ(s,s##_p)
#endif /* CONFIG_MULTIQUAD */
#define __INS(s) \
diff --git a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
index b5719c0bb046..fe838c12ea9d 100644
--- a/include/asm-i386/mpspec.h
+++ b/include/asm-i386/mpspec.h
@@ -198,6 +198,9 @@ enum mp_bustype {
MP_BUS_MCA
};
extern int mp_bus_id_to_type [MAX_MP_BUSSES];
+extern int mp_bus_id_to_node [MAX_MP_BUSSES];
+extern int mp_bus_id_to_local [MAX_MP_BUSSES];
+extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
extern unsigned int boot_cpu_physical_apicid;