Commit 8ca541f5 authored by Martin J. Bligh's avatar Martin J. Bligh Committed by Linus Torvalds

[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.
parent 639f8771
......@@ -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;
......
......@@ -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();
......
......@@ -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
......
......@@ -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) \
......
......@@ -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;
......
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