* [RFC] Summit interrupt routing patches
@ 2002-01-18 22:46 James Cleverdon
2002-01-18 23:15 ` Alan Cox
0 siblings, 1 reply; 6+ messages in thread
From: James Cleverdon @ 2002-01-18 22:46 UTC (permalink / raw)
To: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 986 bytes --]
For a forthcoming NUMA box that uses Foster processors and IBM's Summit
chipset, I've had to extend Martin Bligh's multiquad code beyond the usual
APIC flat mode and his clustered logical mode. The problem with the latter
is that Intel's new APIC numbering scheme only puts two physical CPUs per
cluster. Linux leaves all the TPRs and XTPRs at zero, so that means that all
the interrupts will hit just one CPU per cluster, and generally everything
goes to one cluster.
To combat that, I used the XAPICs new physical cluster capability and a
simple (probably too simple) static round robin binding to roughly level out
the interrupt load. This works, though it seems somehow unsatisfying. The
alternative is much more invasive: adding interrupt code to adjust XTPRs,
hacks to the scheduler to somehow encapsulate task priority in 4 bits, etc.
What do you think?
--
James Cleverdon, IBM xSeries Platform (NUMA), Beaverton
jamesclv@us.ibm.com | cleverdj@us.ibm.com
[-- Attachment #2: summit_patch.2002-01-17_2.4.17 --]
[-- Type: text/x-diff, Size: 25398 bytes --]
diff -ru 2.4.17/arch/i386/kernel/apic.c jamesc-2.4.17/arch/i386/kernel/apic.c
--- 2.4.17/arch/i386/kernel/apic.c Fri Nov 9 17:12:55 2001
+++ jamesc-2.4.17/arch/i386/kernel/apic.c Thu Jan 17 14:51:47 2002
@@ -29,6 +29,7 @@
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
+#include <asm/smpboot.h>
/* Using APIC to generate smp_local_timer_interrupt? */
int using_apic_timer = 0;
@@ -282,21 +283,20 @@
* document number 292116). So here it goes...
*/
- if (!clustered_apic_mode) {
+ if (!clustered_apic_logical) {
/*
- * In clustered apic mode, the firmware does this for us
- * Put the APIC into flat delivery mode.
- * Must be "all ones" explicitly for 82489DX.
+ * For NUMA-Q (clustered apic logical), the firmware does this
+ * for us. Otherwise, put the APIC into clustered or flat
+ * delivery mode. Must be "all ones" explicitly for 82489DX.
*/
- apic_write_around(APIC_DFR, 0xffffffff);
+ apic_write_around(APIC_DFR, (clustered_apic_mode ?
+ APIC_DFR_CLUSTER : APIC_DFR_FLAT));
/*
* Set up the logical destination ID.
*/
value = apic_read(APIC_LDR);
- value &= ~APIC_LDR_MASK;
- value |= (1<<(smp_processor_id()+24));
- apic_write_around(APIC_LDR, value);
+ apic_write_around(APIC_LDR, apic_ldr_value(value));
}
/*
diff -ru 2.4.17/arch/i386/kernel/io_apic.c jamesc-2.4.17/arch/i386/kernel/io_apic.c
--- 2.4.17/arch/i386/kernel/io_apic.c Tue Nov 13 20:28:41 2001
+++ jamesc-2.4.17/arch/i386/kernel/io_apic.c Thu Jan 17 14:52:56 2002
@@ -32,6 +32,7 @@
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/desc.h>
+#include <asm/smpboot.h>
#undef APIC_LOCKUP_DEBUG
@@ -577,6 +578,37 @@
return current_vector;
}
+#ifdef CONFIG_SMP
+/*
+ * round_robin_cpu_apic_id -- Since Linux doesn't use either the APIC TPRs or
+ * XTPRs to set task/interrupt priority, xAPICs and SAPICs tend to hit one CPU
+ * with all interrupts for each quad. Distribute the interrupts using a simple
+ * round robin scheme.
+ * (I wish we could get dynamic load leveling without serious hacks to
+ * the interrupt entry points, scheduler, etc.)
+ */
+static int round_robin_cpu_apic_id(void)
+{
+ int val;
+ static unsigned next_cpu = 0;
+
+ for (;; ++next_cpu) {
+ if (next_cpu >= NR_CPUS)
+ next_cpu = 0;
+ if (!(logical_cpu_present_map & (1UL << next_cpu)))
+ continue;
+ val = cpu_present_to_apicid(next_cpu);
+ ++next_cpu;
+ return (val);
+ }
+}
+#else /* CONFIG_SMP */
+static inline int round_robin_cpu_apic_id(void)
+{
+ return (0);
+}
+#endif /* CONFIG_SMP */
+
extern void (*interrupt[NR_IRQS])(void);
static struct hw_interrupt_type ioapic_level_irq_type;
static struct hw_interrupt_type ioapic_edge_irq_type;
@@ -597,8 +629,8 @@
*/
memset(&entry,0,sizeof(entry));
- entry.delivery_mode = dest_LowestPrio;
- entry.dest_mode = INT_DELIVERY_MODE;
+ entry.delivery_mode = INT_DELIVERY_MODE;
+ entry.dest_mode = (INT_DEST_ADDR_MODE != 0);
entry.mask = 0; /* enable IRQ */
entry.dest.logical.logical_dest = TARGET_CPUS;
@@ -618,7 +650,6 @@
if (irq_trigger(idx)) {
entry.trigger = 1;
entry.mask = 1;
- entry.dest.logical.logical_dest = TARGET_CPUS;
}
irq = pin_2_irq(idx, apic, pin);
@@ -672,10 +703,10 @@
* We use logical delivery to get the timer IRQ
* to the first CPU.
*/
- entry.dest_mode = INT_DELIVERY_MODE;
+ entry.dest_mode = (INT_DEST_ADDR_MODE != 0);
entry.mask = 0; /* unmask IRQ now */
entry.dest.logical.logical_dest = TARGET_CPUS;
- entry.delivery_mode = dest_LowestPrio;
+ entry.delivery_mode = INT_DELIVERY_MODE;
entry.polarity = 0;
entry.trigger = 0;
entry.vector = vector;
@@ -1027,7 +1058,7 @@
old_id = mp_ioapics[apic].mpc_apicid;
- if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+ if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) {
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
apic, mp_ioapics[apic].mpc_apicid);
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
@@ -1039,14 +1070,16 @@
* Sanity check, is the ID really free? Every APIC in a
* system must have a unique ID or we get lots of nice
* 'stuck on smp_invalidate_needed IPI wait' messages.
+ * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs.
*/
- if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) {
+ if (!clustered_apic_physical &&
+ (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) {
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
apic, mp_ioapics[apic].mpc_apicid);
for (i = 0; i < 0xf; i++)
if (!(phys_id_present_map & (1 << i)))
break;
- if (i >= 0xf)
+ if (i >= apic_broadcast_id)
panic("Max APIC ID exceeded!\n");
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
i);
diff -ru 2.4.17/arch/i386/kernel/mpparse.c jamesc-2.4.17/arch/i386/kernel/mpparse.c
--- 2.4.17/arch/i386/kernel/mpparse.c Fri Nov 9 17:58:18 2001
+++ jamesc-2.4.17/arch/i386/kernel/mpparse.c Thu Jan 17 14:51:47 2002
@@ -26,6 +26,7 @@
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
+#include <asm/smpboot.h>
/* Have we found an MP table */
int smp_found_config;
@@ -62,6 +63,19 @@
/* Bitmask of physically existing CPUs */
unsigned long phys_cpu_present_map;
+unsigned long logical_cpu_present_map;
+
+#ifdef CONFIG_SMP
+unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC;
+unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL;
+unsigned char int_delivery_mode = dest_LowestPrio;
+unsigned char target_cpus = 0;
+unsigned char clustered_apic_mode = 0;
+unsigned char clustered_apic_logical = 0;
+unsigned char clustered_apic_physical = 0;
+unsigned char esr_disable = 0;
+#endif /* CONFIG_SMP */
+unsigned char raw_phys_apicid[NR_CPUS] = { 0 };
/*
* Intel MP BIOS table parsing routines:
@@ -143,7 +157,7 @@
return;
logical_apicid = m->mpc_apicid;
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
quad = translation_table[mpc_record]->trans_quad;
logical_apicid = (quad << 4) +
(m->mpc_apicid ? m->mpc_apicid << 1 : 1);
@@ -223,11 +237,8 @@
}
ver = m->mpc_apicver;
- if (clustered_apic_mode) {
- phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad);
- } else {
- phys_cpu_present_map |= 1 << m->mpc_apicid;
- }
+ logical_cpu_present_map |= 1 << (num_processors-1);
+ phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid);
/*
* Validate version
*/
@@ -236,6 +247,7 @@
ver = 0x10;
}
apic_version[m->mpc_apicid] = ver;
+ raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
}
static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -245,7 +257,7 @@
memcpy(str, m->mpc_bustype, 6);
str[6] = 0;
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
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]);
} else {
@@ -385,9 +397,12 @@
static int __init smp_read_mpc(struct mp_config_table *mpc)
{
- char str[16];
+ char oem[10];
+ char prod[14];
int count=sizeof(*mpc);
unsigned char *mpt=((unsigned char *)mpc)+count;
+ int numaq = 0;
+ int xapic = 0;
if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
panic("SMP mptable: bad signature [%c%c%c%c]!\n",
@@ -410,13 +425,20 @@
printk(KERN_ERR "SMP mptable: null local APIC address!\n");
return 0;
}
- memcpy(str,mpc->mpc_oem,8);
- str[8]=0;
- printk("OEM ID: %s ",str);
-
- memcpy(str,mpc->mpc_productid,12);
- str[12]=0;
- printk("Product ID: %s ",str);
+ memcpy(oem, mpc->mpc_oem, 8);
+ oem[8] = 0;
+ memcpy(prod, mpc->mpc_productid, 12);
+ prod[12] = 0;
+ printk("OEM ID: %s ", oem);
+ printk("Product ID: %s ",prod);
+ /*
+ * Can't recognize Summit xAPICs (see below), so use OEM/Product IDs.
+ */
+ if (!strncmp(oem, "IBM ENSW", 8) &&
+ (!strncmp(prod, "NF 6000R", 8) || !strncmp(prod, "VIGIL SMP", 9)) )
+ xapic = 1;
+ else if (!strncmp(oem, "IBM NUMA", 8))
+ numaq = 2;
printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
@@ -426,7 +448,7 @@
if (!have_acpi_tables)
mp_lapic_addr = mpc->mpc_lapic;
- if (clustered_apic_mode && mpc->mpc_oemptr) {
+ if (clustered_apic_logical && mpc->mpc_oemptr) {
/* We need to process the oem mpc tables to tell us which quad things are in ... */
mpc_record = 0;
smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize);
@@ -466,6 +488,19 @@
MP_ioapic_info(m);
mpt+=sizeof(*m);
count+=sizeof(*m);
+ /******
+ * Kludge Alert! We have an APIC version number collision
+ * between the APICs on Scorpio-based NUMA-Q boxes and Summit
+ * xAPICs. Intel didn't define the xAPIC ver ID range until
+ * relatively recently, so there is working silicon out there
+ * that doesn't match their range.
+ * For now, use the OEM strings until we have some assurance
+ * that only xAPICs occupy the version number range below.
+ ****
+ if (m->mpc_apicver >= XAPIC_ID_LOW &&
+ m->mpc_apicver <= XAPIC_ID_HIGH)
+ xapic = 1;
+ ******/
break;
}
case MP_INTSRC:
@@ -495,10 +530,33 @@
}
++mpc_record;
}
- if (clustered_apic_mode && nr_ioapics > 2) {
- /* don't initialise IO apics on secondary quads */
+ if (xapic || numaq) {
+#ifdef CONFIG_SMP
+ if (numaq) {
+ xapic = 0; /* NUMA-Q boxes never had xAPICs */
+ /* Broadcast intrs to local quad only. */
+ target_cpus = APIC_BROADCAST_ID_APIC;
+ }
+ clustered_apic_logical = (unsigned char) numaq;
+ clustered_apic_physical = (unsigned char) xapic;
+ clustered_apic_mode = clustered_apic_logical | clustered_apic_physical;
+ esr_disable = 1;
+ apic_broadcast_id = (xapic ? APIC_BROADCAST_ID_XAPIC : APIC_BROADCAST_ID_APIC);
+ int_dest_addr_mode = (xapic ? APIC_DEST_PHYSICAL : APIC_DEST_LOGICAL);
+ int_delivery_mode = (xapic ? dest_Fixed : dest_LowestPrio);
+#endif /* CONFIG_SMP */
+ phys_cpu_present_map = logical_cpu_present_map;
+ }
+#ifdef CONFIG_SMP
+ if (numaq && nr_ioapics > 2) {
+ /* NUMA-Q: don't initialise IO apics on secondary quads, yet. */
nr_ioapics = 2;
}
+ printk("Enabling APIC mode: %s. Using %d I/O APICs\n",
+ (clustered_apic_logical ? "Clustered Logical" :
+ (clustered_apic_physical ?"Physical" : "Flat")),
+ nr_ioapics);
+#endif /* CONFIG_SMP */
if (!num_processors)
printk(KERN_ERR "SMP mptable: no processors registered!\n");
return num_processors;
diff -ru 2.4.17/arch/i386/kernel/process.c jamesc-2.4.17/arch/i386/kernel/process.c
--- 2.4.17/arch/i386/kernel/process.c Thu Oct 4 21:42:54 2001
+++ jamesc-2.4.17/arch/i386/kernel/process.c Thu Jan 17 14:51:47 2002
@@ -186,7 +186,7 @@
}
/* we will leave sorting out the final value
when we are ready to reboot, since we might not
- have set up boot_cpu_id or smp_num_cpu */
+ have set up boot_cpu_physical_apicid or smp_num_cpu */
break;
#endif
}
diff -ru 2.4.17/arch/i386/kernel/smp.c jamesc-2.4.17/arch/i386/kernel/smp.c
--- 2.4.17/arch/i386/kernel/smp.c Fri Dec 21 12:41:53 2001
+++ jamesc-2.4.17/arch/i386/kernel/smp.c Thu Jan 17 14:51:47 2002
@@ -115,7 +115,7 @@
static inline int __prepare_ICR (unsigned int shortcut, int vector)
{
- return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
+ return APIC_DM_FIXED | shortcut | vector | INT_DEST_ADDR_MODE;
}
static inline int __prepare_ICR2 (unsigned int mask)
@@ -214,7 +214,9 @@
/*
* prepare target chip field
*/
- cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
+ cfg = __prepare_ICR2(clustered_apic_physical ?
+ cpu_to_physical_apicid(query_cpu) :
+ cpu_to_logical_apicid(query_cpu));
apic_write_around(APIC_ICR2, cfg);
/*
diff -ru 2.4.17/arch/i386/kernel/smpboot.c jamesc-2.4.17/arch/i386/kernel/smpboot.c
--- 2.4.17/arch/i386/kernel/smpboot.c Fri Dec 21 12:41:53 2001
+++ jamesc-2.4.17/arch/i386/kernel/smpboot.c Thu Jan 17 14:51:47 2002
@@ -540,7 +540,7 @@
* else physical apic ids
*/
{
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
logical_apicid_2_cpu[apicid] = cpu;
cpu_2_logical_apicid[cpu] = apicid;
} else {
@@ -555,7 +555,7 @@
* else physical apic ids
*/
{
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
logical_apicid_2_cpu[apicid] = -1;
cpu_2_logical_apicid[cpu] = -1;
} else {
@@ -785,7 +785,7 @@
unsigned long boot_error = 0;
int timeout, cpu;
unsigned long start_eip;
- unsigned short nmi_high, nmi_low;
+ unsigned short nmi_high = 0, nmi_low = 0;
cpu = ++cpucount;
/*
@@ -830,7 +830,7 @@
Dprintk("Setting warm reset code and vector.\n");
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
/* stash the current NMI vector, so we can put things back */
nmi_high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
nmi_low = *((volatile unsigned short *) TRAMPOLINE_LOW);
@@ -862,7 +862,7 @@
* Starting actual IPI sequence...
*/
- if (clustered_apic_mode)
+ if (clustered_apic_logical)
boot_error = wakeup_secondary_via_NMI(apicid);
else
boot_error = wakeup_secondary_via_INIT(apicid, start_eip);
@@ -917,7 +917,7 @@
/* mark "stuck" area as not stuck */
*((volatile unsigned long *)phys_to_virt(8192)) = 0;
- if(clustered_apic_mode) {
+ if (clustered_apic_logical) {
printk("Restoring NMI vector\n");
*((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high;
*((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low;
@@ -972,8 +972,10 @@
extern int prof_counter[NR_CPUS];
static int boot_cpu_logical_apicid;
+#ifdef CONFIG_MULTIQUAD
/* Where the IO area was mapped on multiquad, always 0 otherwise */
void *xquad_portio = NULL;
+#endif
int cpu_sibling_map[NR_CPUS] __cacheline_aligned;
@@ -981,12 +983,14 @@
{
int apicid, cpu, bit;
- if (clustered_apic_mode) {
+#ifdef CONFIG_MULTIQUAD
+ if (clustered_apic_logical) {
/* 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);
}
+#endif
#ifdef CONFIG_MTRR
/* Must be done before other processors booted */
@@ -1108,7 +1112,7 @@
if (apicid == boot_cpu_apicid)
continue;
- if (!(phys_cpu_present_map & (1 << bit)))
+ if (!(phys_cpu_present_map & (1ul << bit)))
continue;
if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
continue;
@@ -1119,9 +1123,9 @@
* Make sure we unmap all failed CPUs
*/
if ((boot_apicid_to_cpu(apicid) == -1) &&
- (phys_cpu_present_map & (1 << bit)))
- printk("CPU #%d not responding - cannot use it.\n",
- apicid);
+ (phys_cpu_present_map & (1ul << bit)))
+ printk("CPU #%d/0x%02x not responding - cannot use it.\n",
+ bit, apicid);
}
/*
diff -ru 2.4.17/arch/i386/kernel/trampoline.S jamesc-2.4.17/arch/i386/kernel/trampoline.S
--- 2.4.17/arch/i386/kernel/trampoline.S Thu Oct 4 21:42:54 2001
+++ jamesc-2.4.17/arch/i386/kernel/trampoline.S Thu Jan 17 14:51:47 2002
@@ -36,9 +36,9 @@
ENTRY(trampoline_data)
r_base = .
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_SMP
wbinvd
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_SMP */
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
diff -ru 2.4.17/include/asm-i386/apicdef.h jamesc-2.4.17/include/asm-i386/apicdef.h
--- 2.4.17/include/asm-i386/apicdef.h Sun Aug 12 14:13:59 2001
+++ jamesc-2.4.17/include/asm-i386/apicdef.h Thu Jan 17 14:51:47 2002
@@ -11,8 +11,15 @@
#define APIC_DEFAULT_PHYS_BASE 0xfee00000
#define APIC_ID 0x20
+#ifdef CONFIG_SMP /* Newer APIC family members have 8 bit phys IDs */
+#define APIC_ID_MASK (0xFF<<24)
+#define GET_APIC_ID(x) (((x)>>24)&0xFF)
+#else
#define APIC_ID_MASK (0x0F<<24)
#define GET_APIC_ID(x) (((x)>>24)&0x0F)
+#endif /* CONFIG_SMP */
+#define XAPIC_ID_LOW 0x14 /* Version num range */
+#define XAPIC_ID_HIGH 0x1F
#define APIC_LVR 0x30
#define APIC_LVR_MASK 0xFF00FF
#define GET_APIC_VERSION(x) ((x)&0xFF)
@@ -32,6 +39,8 @@
#define SET_APIC_LOGICAL_ID(x) (((x)<<24))
#define APIC_ALL_CPUS 0xFF
#define APIC_DFR 0xE0
+#define APIC_DFR_CLUSTER 0x0FFFFFFFul /* Clustered */
+#define APIC_DFR_FLAT 0xFFFFFFFFul /* Flat mode */
#define APIC_SPIV 0xF0
#define APIC_SPIV_FOCUS_DISABLED (1<<9)
#define APIC_SPIV_APIC_ENABLED (1<<8)
@@ -58,6 +67,7 @@
#define APIC_INT_ASSERT 0x04000
#define APIC_ICR_BUSY 0x01000
#define APIC_DEST_LOGICAL 0x00800
+#define APIC_DEST_PHYSICAL 0x0 /* For symmetry */
#define APIC_DM_FIXED 0x00000
#define APIC_DM_LOWEST 0x00100
#define APIC_DM_SMI 0x00200
@@ -107,7 +117,18 @@
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
-#define MAX_IO_APICS 8
+#ifdef CONFIG_SMP
+# define MAX_IO_APICS 32 /* Summit boxes can have 4*(2+3*2) I/O APICs */
+#else
+# define MAX_IO_APICS 8
+#endif /* CONFIG_SMP */
+
+/*
+ * The broadcast ID is 0xF for old APICs and 0xFF for xAPICs. SAPICs
+ * don't broadcast (yet?), but if they did, they might use 0xFFFF.
+ */
+#define APIC_BROADCAST_ID_XAPIC 0xFF
+#define APIC_BROADCAST_ID_APIC 0x0F
/*
* the local APIC register structure, memory mapped. Not terribly well
diff -ru 2.4.17/include/asm-i386/mpspec.h jamesc-2.4.17/include/asm-i386/mpspec.h
--- 2.4.17/include/asm-i386/mpspec.h Wed Jan 9 15:58:47 2002
+++ jamesc-2.4.17/include/asm-i386/mpspec.h Thu Jan 17 14:51:47 2002
@@ -14,13 +14,14 @@
#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
/*
- * a maximum of 16 APICs with the current APIC ID architecture.
+ * A maximum of 16 APICs with the classic APIC ID architecture.
+ * xAPICs can have up to 256. SAPICs have 16 ID bits.
*/
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_SMP
#define MAX_APICS 256
-#else /* !CONFIG_MULTIQUAD */
+#else /* !CONFIG_SMP */
#define MAX_APICS 16
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_SMP */
#define MAX_MPC_ENTRY 1024
@@ -184,13 +185,10 @@
* 7 2 CPU MCA+PCI
*/
-#ifdef CONFIG_MULTIQUAD
-#define MAX_IRQ_SOURCES 512
-#else /* !CONFIG_MULTIQUAD */
-#define MAX_IRQ_SOURCES 256
-#endif /* CONFIG_MULTIQUAD */
+#define MAX_MP_BUSSES 257 /* Need max PCI busses for hotplug + 1 for ISA. */
+ /* Four intrs per PCI slot. */
+#define MAX_IRQ_SOURCES (MAX_MP_BUSSES * 4)
-#define MAX_MP_BUSSES 32
enum mp_bustype {
MP_BUS_ISA = 1,
MP_BUS_EISA,
diff -ru 2.4.17/include/asm-i386/smp.h jamesc-2.4.17/include/asm-i386/smp.h
--- 2.4.17/include/asm-i386/smp.h Wed Jan 9 15:58:47 2002
+++ jamesc-2.4.17/include/asm-i386/smp.h Thu Jan 17 14:51:47 2002
@@ -23,27 +23,31 @@
#endif
#ifdef CONFIG_SMP
-# ifdef CONFIG_MULTIQUAD
-# define TARGET_CPUS 0xf /* all CPUs in *THIS* quad */
-# define INT_DELIVERY_MODE 0 /* physical delivery on LOCAL quad */
-# else
-# define TARGET_CPUS cpu_online_map
-# define INT_DELIVERY_MODE 1 /* logical delivery broadcast to all procs */
-# endif
+# ifndef __ASSEMBLY__
+ extern unsigned char clustered_apic_mode;
+ extern unsigned char clustered_apic_physical;
+ extern unsigned char clustered_apic_logical;
+ extern unsigned char target_cpus;
+ extern unsigned char esr_disable;
+ extern unsigned char int_delivery_mode;
+ extern unsigned int int_dest_addr_mode;
+ extern unsigned int apic_broadcast_id;
+# endif /* !__ASSEMBLY__ */
+# define TARGET_CPUS (target_cpus ? target_cpus : \
+ (clustered_apic_physical ? round_robin_cpu_apic_id() : \
+ cpu_online_map) )
+# define INT_DEST_ADDR_MODE (int_dest_addr_mode)
+# define INT_DELIVERY_MODE (int_delivery_mode)
#else
-# define INT_DELIVERY_MODE 1 /* logical delivery */
+# define clustered_apic_mode (0)
+# define clustered_apic_logical (0)
+# define clustered_apic_physical (0)
+# define apic_broadcast_id (APIC_BROADCAST_ID_APIC)
+# define esr_disable (0)
# define TARGET_CPUS 0x01
-#endif
-
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
- #define clustered_apic_mode (1)
- #define esr_disable (1)
- #else /* !CONFIG_MULTIQUAD */
- #define clustered_apic_mode (0)
- #define esr_disable (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif
+# define INT_DEST_ADDR_MODE 1 /* logical delivery */
+# define INT_DELIVERY_MODE (dest_LowestPrio)
+#endif /* CONFIG_SMP */
#ifdef CONFIG_SMP
#ifndef __ASSEMBLY__
@@ -53,6 +57,7 @@
*/
extern void smp_alloc_memory(void);
+extern unsigned long logical_cpu_present_map;
extern unsigned long phys_cpu_present_map;
extern unsigned long cpu_online_map;
extern volatile unsigned long smp_invalidate_needed;
@@ -112,7 +117,7 @@
return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
}
-static __inline int logical_smp_processor_id(void)
+extern __inline int logical_smp_processor_id(void)
{
/* we don't want to mark this access volatile - bad code generation */
return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
diff -ru 2.4.17/include/asm-i386/smpboot.h jamesc-2.4.17/include/asm-i386/smpboot.h
--- 2.4.17/include/asm-i386/smpboot.h Wed Jan 9 16:05:38 2002
+++ jamesc-2.4.17/include/asm-i386/smpboot.h Thu Jan 17 14:51:47 2002
@@ -1,36 +1,57 @@
#ifndef __ASM_SMPBOOT_H
#define __ASM_SMPBOOT_H
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
- #define clustered_apic_mode (1)
- #else /* !CONFIG_MULTIQUAD */
- #define clustered_apic_mode (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif
-
-#ifdef CONFIG_MULTIQUAD
- #define TRAMPOLINE_LOW phys_to_virt(0x8)
- #define TRAMPOLINE_HIGH phys_to_virt(0xa)
-#else /* !CONFIG_MULTIQUAD */
- #define TRAMPOLINE_LOW phys_to_virt(0x467)
- #define TRAMPOLINE_HIGH phys_to_virt(0x469)
-#endif /* CONFIG_MULTIQUAD */
-
-#ifdef CONFIG_MULTIQUAD
- #define boot_cpu_apicid boot_cpu_logical_apicid
-#else /* !CONFIG_MULTIQUAD */
- #define boot_cpu_apicid boot_cpu_physical_apicid
-#endif /* CONFIG_MULTIQUAD */
+#ifndef __ASM_SMP_H
+#include "asm/smp.h"
+#endif
+
+#define TRAMPOLINE_LOW phys_to_virt(clustered_apic_logical?0x8:0x467)
+#define TRAMPOLINE_HIGH phys_to_virt(clustered_apic_logical?0xa:0x469)
+
+#define boot_cpu_apicid (clustered_apic_logical?boot_cpu_logical_apicid:boot_cpu_physical_apicid)
+
+/*
+ * To build the logical APIC ID for each CPU we have three cases:
+ * 1) Normal flat mode: use a bitmap of the CPU numbers
+ * 2) Logical multi-quad (NUMA-Q): do nothing, the BIOS has set it up
+ * 3) Physical multi-quad (xAPIC clusters): convert the Intel standard
+ * physical APIC ID to a cluster nibble/cpu bitmap nibble
+ */
+#ifdef CONFIG_SMP
+/*** mps_cpu (index number): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... */
+/*** CPUs have xAPIC phys IDs: 00, 01, 02, 03, 10, 11, 12, 13, 20, 21, ... */
+/*** its logical ID: 01, 02, 04, 08, 11, 12, 14, 18, 21, 22, ... */
+#define physical_to_logical_apicid(phys_apic) ( (1UL << (phys_apic & 0x3)) | (phys_apic & 0xF0U) )
+
+static inline unsigned long apic_ldr_value(unsigned long value)
+{
+ if (clustered_apic_logical)
+ return (value);
+ if (clustered_apic_physical)
+ return (((value) & ~APIC_LDR_MASK) |
+ SET_APIC_LOGICAL_ID(physical_to_logical_apicid(hard_smp_processor_id())));
+ return (((value) & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(1UL << smp_processor_id()));
+}
+#else
+ #define apic_ldr_value(value) (((value) & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(1UL << smp_processor_id()))
+#endif /* CONFIG_SMP */
/*
- * How to map from the cpu_present_map
+ * How to map from phys_cpu_present_map.
+ * 1) Normal flat mode: use the mps_cpu, apicid bitmap
+ * 2) Multi-Quad: only 4 CPUs per cluster, cluster ID in high nibble
+ * use
*/
-#ifdef CONFIG_MULTIQUAD
- #define cpu_present_to_apicid(mps_cpu) ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) )
-#else /* !CONFIG_MULTIQUAD */
- #define cpu_present_to_apicid(apicid) (apicid)
-#endif /* CONFIG_MULTIQUAD */
+#ifdef CONFIG_SMP
+#define cpu_present_to_apicid(mps_cpu) (clustered_apic_logical ? \
+ ( ((mps_cpu / 4) * 16) + (1 << (mps_cpu % 4)) ) : \
+ (clustered_apic_physical ? raw_phys_apicid[mps_cpu] : (mps_cpu) ) )
+extern unsigned char raw_phys_apicid[NR_CPUS];
+#define apicid_to_phys_cpu_present(apicid) (clustered_apic_mode ? (1UL << (((apicid >> 4) << 2) + (apicid & 0x3))) : (1UL << apicid))
+#else /* CONFIG_SMP */
+#define cpu_present_to_apicid(mps_cpu) (mps_cpu)
+#define apicid_to_phys_cpu_present(apicid) (apicid)
+#endif /* CONFIG_SMP */
/*
* Mappings between logical cpu number and logical / physical apicid
@@ -45,18 +66,8 @@
#define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu]
#define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
#define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu]
-#ifdef CONFIG_MULTIQUAD /* use logical IDs to bootstrap */
-#define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid]
-#define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu]
-#else /* !CONFIG_MULTIQUAD */ /* use physical IDs to bootstrap */
-#define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
-#define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu]
-#endif /* CONFIG_MULTIQUAD */
-
-
-#ifdef CONFIG_MULTIQUAD
-#else /* !CONFIG_MULTIQUAD */
-#endif /* CONFIG_MULTIQUAD */
+#define boot_apicid_to_cpu(apicid) (clustered_apic_logical ? logical_apicid_2_cpu[apicid] : physical_apicid_2_cpu[apicid])
+#define cpu_to_boot_apicid(cpu) (clustered_apic_logical ? cpu_2_logical_apicid[cpu] : cpu_2_physical_apicid[cpu])
#endif
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] Summit interrupt routing patches
2002-01-18 22:46 [RFC] Summit interrupt routing patches James Cleverdon
@ 2002-01-18 23:15 ` Alan Cox
2002-01-19 0:18 ` James Cleverdon
0 siblings, 1 reply; 6+ messages in thread
From: Alan Cox @ 2002-01-18 23:15 UTC (permalink / raw)
To: jamesclv; +Cc: linux-kernel
> alternative is much more invasive: adding interrupt code to adjust XTPRs,
> hacks to the scheduler to somehow encapsulate task priority in 4 bits, etc.
Is it necessary to try something complex. We already keep per cpu/per irq
data and if you have a lot of interrupts it feels like you can handwave them
to be roughly the same amount of cpu load.
Given that is it enough to once a second shuffle the irqs around to try and
get a rough balance based on a simple decaying history. Then all it needs
is a regular timer event to do what the hardware hasnt
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] Summit interrupt routing patches
2002-01-18 23:15 ` Alan Cox
@ 2002-01-19 0:18 ` James Cleverdon
2002-01-19 1:11 ` David S. Miller
2002-01-19 1:18 ` Alan Cox
0 siblings, 2 replies; 6+ messages in thread
From: James Cleverdon @ 2002-01-19 0:18 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-kernel
On Friday 18 January 2002 03:15 pm, Alan Cox wrote:
> > alternative is much more invasive: adding interrupt code to adjust
> > XTPRs, hacks to the scheduler to somehow encapsulate task priority in 4
> > bits, etc.
>
> Is it necessary to try something complex. We already keep per cpu/per irq
> data and if you have a lot of interrupts it feels like you can handwave
> them to be roughly the same amount of cpu load.
>
> Given that is it enough to once a second shuffle the irqs around to try and
> get a rough balance based on a simple decaying history. Then all it needs
> is a regular timer event to do what the hardware hasnt
Thanks for the reply.
What I'd like to see is a scheme where we route interrupts preferentially to
idle CPUs. If none are idle, then aim them at the CPUs running the "least
important" tasks. Also, since each CPU's local APIC only has two interrupt
latches per `level' (the upper nibble of the IRQ's vector), it would be a
good idea to avoid sending IRQs to those CPUs that are already processing one.
Since we only have 4 bits in each XPTR, suppose we used the high bit to
indicate IRQ-in-progress and the bottom three for some kind of compressed
task goodness measure. Idle equals zero. The XTPR would be updated on every
interrupt entry/exit and on every task switch.
What's the catch? The cost of doing the above. Plus, we still only have two
CPUs in each cluster, four if hyperthreading is turned on. (Of course, the
hyperthreaded "sibling processors" don't have the power of a full CPU --
maybe 20% to 40% of one.) All interrupts have to be targeted at a particular
cluster. So, lowest priority interrupt delivery may not buy us very much.
To make matters even more interesting, the economy version (non-NUMA) of this
hardware started shipping last month and the full version will be shipping
soon. I wonder if Marcelo is going to allow this kind of futzing around with
interrupt and scheduler code in 2.4....
--
James Cleverdon, IBM xSeries Platform (NUMA), Beaverton
jamesclv@us.ibm.com | cleverdj@us.ibm.com
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] Summit interrupt routing patches
2002-01-19 0:18 ` James Cleverdon
@ 2002-01-19 1:11 ` David S. Miller
2002-01-22 0:59 ` James Cleverdon
2002-01-19 1:18 ` Alan Cox
1 sibling, 1 reply; 6+ messages in thread
From: David S. Miller @ 2002-01-19 1:11 UTC (permalink / raw)
To: alan; +Cc: jamesclv, linux-kernel
From: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date: Sat, 19 Jan 2002 01:18:09 +0000 (GMT)
Im not sure aiming at least important is worth anything. Aiming at idle
processors on a box not doing power management seems easy providing you'll
accept 99.99% accuracy. Switch the priority up in the idle code, switch it
back down again before the idle task schedule()'s. If you hit during the
schedule well tough.
$ egrep idle_me_harder arch/sparc64/kernel/process.c
$ egrep "idle_volume|redirect_intr" arch/sparc64/kernel/irq.c
Been there, done that :-)
Franks a lot,
David S. Miller
davem@redhat.com
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] Summit interrupt routing patches
2002-01-19 0:18 ` James Cleverdon
2002-01-19 1:11 ` David S. Miller
@ 2002-01-19 1:18 ` Alan Cox
1 sibling, 0 replies; 6+ messages in thread
From: Alan Cox @ 2002-01-19 1:18 UTC (permalink / raw)
To: jamesclv; +Cc: Alan Cox, linux-kernel
> idle CPUs. If none are idle, then aim them at the CPUs running the "least
> important" tasks. Also, since each CPU's local APIC only has two interrupt
> latches per `level' (the upper nibble of the IRQ's vector), it would be a
> good idea to avoid sending IRQs to those CPUs that are already processing one.
Im not sure aiming at least important is worth anything. Aiming at idle
processors on a box not doing power management seems easy providing you'll
accept 99.99% accuracy. Switch the priority up in the idle code, switch it
back down again before the idle task schedule()'s. If you hit during the
schedule well tough.
> soon. I wonder if Marcelo is going to allow this kind of futzing around with
> interrupt and scheduler code in 2.4....
Thats another reason to keep it small and clean.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] Summit interrupt routing patches
2002-01-19 1:11 ` David S. Miller
@ 2002-01-22 0:59 ` James Cleverdon
0 siblings, 0 replies; 6+ messages in thread
From: James Cleverdon @ 2002-01-22 0:59 UTC (permalink / raw)
To: David S. Miller, alan; +Cc: linux-kernel, Marcelo Tosatti
[-- Attachment #1: Type: text/plain, Size: 1496 bytes --]
On Friday 18 January 2002 05:11 pm, David S. Miller wrote:
> From: Alan Cox <alan@lxorguk.ukuu.org.uk>
> Date: Sat, 19 Jan 2002 01:18:09 +0000 (GMT)
>
> Im not sure aiming at least important is worth anything. Aiming at idle
> processors on a box not doing power management seems easy providing
> you'll accept 99.99% accuracy. Switch the priority up in the idle code,
> switch it back down again before the idle task schedule()'s. If you hit
> during the schedule well tough.
>
> $ egrep idle_me_harder arch/sparc64/kernel/process.c
> $ egrep "idle_volume|redirect_intr" arch/sparc64/kernel/irq.c
>
> Been there, done that :-)
>
> Franks a lot,
> David S. Miller
> davem@redhat.com
Yeah, and a collegue has some patches for ia64, which has a similar problem
with SAPICs. But, my attempts at making a i386 version haven't panned out
yet (drops interrupts on Foster boxes). The code doesn't draw a strong
distinction between a CPU's number, its logical APIC ID, and it's physical
APIC ID. Martin Bligh did some work in this department for his multiquad
patches, but it is by no means complete.
Until I can untangle this snarl, how about taking the static patches as a
first step? They a bit less invasive than the lowest priority ones (i.e. no
apic_set_tpr calls inserted into do_IRQ, cpu_idle, etc.). Plus, they work on
all the hardware I can lay my hands on.
--
James Cleverdon, IBM xSeries Platform (NUMA), Beaverton
jamesclv@us.ibm.com | cleverdj@us.ibm.com
[-- Attachment #2: summit_patch.2002-01-17_2.4.17 --]
[-- Type: text/x-diff, Size: 25398 bytes --]
diff -ru 2.4.17/arch/i386/kernel/apic.c jamesc-2.4.17/arch/i386/kernel/apic.c
--- 2.4.17/arch/i386/kernel/apic.c Fri Nov 9 17:12:55 2001
+++ jamesc-2.4.17/arch/i386/kernel/apic.c Thu Jan 17 14:51:47 2002
@@ -29,6 +29,7 @@
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
+#include <asm/smpboot.h>
/* Using APIC to generate smp_local_timer_interrupt? */
int using_apic_timer = 0;
@@ -282,21 +283,20 @@
* document number 292116). So here it goes...
*/
- if (!clustered_apic_mode) {
+ if (!clustered_apic_logical) {
/*
- * In clustered apic mode, the firmware does this for us
- * Put the APIC into flat delivery mode.
- * Must be "all ones" explicitly for 82489DX.
+ * For NUMA-Q (clustered apic logical), the firmware does this
+ * for us. Otherwise, put the APIC into clustered or flat
+ * delivery mode. Must be "all ones" explicitly for 82489DX.
*/
- apic_write_around(APIC_DFR, 0xffffffff);
+ apic_write_around(APIC_DFR, (clustered_apic_mode ?
+ APIC_DFR_CLUSTER : APIC_DFR_FLAT));
/*
* Set up the logical destination ID.
*/
value = apic_read(APIC_LDR);
- value &= ~APIC_LDR_MASK;
- value |= (1<<(smp_processor_id()+24));
- apic_write_around(APIC_LDR, value);
+ apic_write_around(APIC_LDR, apic_ldr_value(value));
}
/*
diff -ru 2.4.17/arch/i386/kernel/io_apic.c jamesc-2.4.17/arch/i386/kernel/io_apic.c
--- 2.4.17/arch/i386/kernel/io_apic.c Tue Nov 13 20:28:41 2001
+++ jamesc-2.4.17/arch/i386/kernel/io_apic.c Thu Jan 17 14:52:56 2002
@@ -32,6 +32,7 @@
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/desc.h>
+#include <asm/smpboot.h>
#undef APIC_LOCKUP_DEBUG
@@ -577,6 +578,37 @@
return current_vector;
}
+#ifdef CONFIG_SMP
+/*
+ * round_robin_cpu_apic_id -- Since Linux doesn't use either the APIC TPRs or
+ * XTPRs to set task/interrupt priority, xAPICs and SAPICs tend to hit one CPU
+ * with all interrupts for each quad. Distribute the interrupts using a simple
+ * round robin scheme.
+ * (I wish we could get dynamic load leveling without serious hacks to
+ * the interrupt entry points, scheduler, etc.)
+ */
+static int round_robin_cpu_apic_id(void)
+{
+ int val;
+ static unsigned next_cpu = 0;
+
+ for (;; ++next_cpu) {
+ if (next_cpu >= NR_CPUS)
+ next_cpu = 0;
+ if (!(logical_cpu_present_map & (1UL << next_cpu)))
+ continue;
+ val = cpu_present_to_apicid(next_cpu);
+ ++next_cpu;
+ return (val);
+ }
+}
+#else /* CONFIG_SMP */
+static inline int round_robin_cpu_apic_id(void)
+{
+ return (0);
+}
+#endif /* CONFIG_SMP */
+
extern void (*interrupt[NR_IRQS])(void);
static struct hw_interrupt_type ioapic_level_irq_type;
static struct hw_interrupt_type ioapic_edge_irq_type;
@@ -597,8 +629,8 @@
*/
memset(&entry,0,sizeof(entry));
- entry.delivery_mode = dest_LowestPrio;
- entry.dest_mode = INT_DELIVERY_MODE;
+ entry.delivery_mode = INT_DELIVERY_MODE;
+ entry.dest_mode = (INT_DEST_ADDR_MODE != 0);
entry.mask = 0; /* enable IRQ */
entry.dest.logical.logical_dest = TARGET_CPUS;
@@ -618,7 +650,6 @@
if (irq_trigger(idx)) {
entry.trigger = 1;
entry.mask = 1;
- entry.dest.logical.logical_dest = TARGET_CPUS;
}
irq = pin_2_irq(idx, apic, pin);
@@ -672,10 +703,10 @@
* We use logical delivery to get the timer IRQ
* to the first CPU.
*/
- entry.dest_mode = INT_DELIVERY_MODE;
+ entry.dest_mode = (INT_DEST_ADDR_MODE != 0);
entry.mask = 0; /* unmask IRQ now */
entry.dest.logical.logical_dest = TARGET_CPUS;
- entry.delivery_mode = dest_LowestPrio;
+ entry.delivery_mode = INT_DELIVERY_MODE;
entry.polarity = 0;
entry.trigger = 0;
entry.vector = vector;
@@ -1027,7 +1058,7 @@
old_id = mp_ioapics[apic].mpc_apicid;
- if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+ if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) {
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
apic, mp_ioapics[apic].mpc_apicid);
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
@@ -1039,14 +1070,16 @@
* Sanity check, is the ID really free? Every APIC in a
* system must have a unique ID or we get lots of nice
* 'stuck on smp_invalidate_needed IPI wait' messages.
+ * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs.
*/
- if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) {
+ if (!clustered_apic_physical &&
+ (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) {
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
apic, mp_ioapics[apic].mpc_apicid);
for (i = 0; i < 0xf; i++)
if (!(phys_id_present_map & (1 << i)))
break;
- if (i >= 0xf)
+ if (i >= apic_broadcast_id)
panic("Max APIC ID exceeded!\n");
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
i);
diff -ru 2.4.17/arch/i386/kernel/mpparse.c jamesc-2.4.17/arch/i386/kernel/mpparse.c
--- 2.4.17/arch/i386/kernel/mpparse.c Fri Nov 9 17:58:18 2001
+++ jamesc-2.4.17/arch/i386/kernel/mpparse.c Thu Jan 17 14:51:47 2002
@@ -26,6 +26,7 @@
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
+#include <asm/smpboot.h>
/* Have we found an MP table */
int smp_found_config;
@@ -62,6 +63,19 @@
/* Bitmask of physically existing CPUs */
unsigned long phys_cpu_present_map;
+unsigned long logical_cpu_present_map;
+
+#ifdef CONFIG_SMP
+unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC;
+unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL;
+unsigned char int_delivery_mode = dest_LowestPrio;
+unsigned char target_cpus = 0;
+unsigned char clustered_apic_mode = 0;
+unsigned char clustered_apic_logical = 0;
+unsigned char clustered_apic_physical = 0;
+unsigned char esr_disable = 0;
+#endif /* CONFIG_SMP */
+unsigned char raw_phys_apicid[NR_CPUS] = { 0 };
/*
* Intel MP BIOS table parsing routines:
@@ -143,7 +157,7 @@
return;
logical_apicid = m->mpc_apicid;
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
quad = translation_table[mpc_record]->trans_quad;
logical_apicid = (quad << 4) +
(m->mpc_apicid ? m->mpc_apicid << 1 : 1);
@@ -223,11 +237,8 @@
}
ver = m->mpc_apicver;
- if (clustered_apic_mode) {
- phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad);
- } else {
- phys_cpu_present_map |= 1 << m->mpc_apicid;
- }
+ logical_cpu_present_map |= 1 << (num_processors-1);
+ phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid);
/*
* Validate version
*/
@@ -236,6 +247,7 @@
ver = 0x10;
}
apic_version[m->mpc_apicid] = ver;
+ raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
}
static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -245,7 +257,7 @@
memcpy(str, m->mpc_bustype, 6);
str[6] = 0;
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
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]);
} else {
@@ -385,9 +397,12 @@
static int __init smp_read_mpc(struct mp_config_table *mpc)
{
- char str[16];
+ char oem[10];
+ char prod[14];
int count=sizeof(*mpc);
unsigned char *mpt=((unsigned char *)mpc)+count;
+ int numaq = 0;
+ int xapic = 0;
if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
panic("SMP mptable: bad signature [%c%c%c%c]!\n",
@@ -410,13 +425,20 @@
printk(KERN_ERR "SMP mptable: null local APIC address!\n");
return 0;
}
- memcpy(str,mpc->mpc_oem,8);
- str[8]=0;
- printk("OEM ID: %s ",str);
-
- memcpy(str,mpc->mpc_productid,12);
- str[12]=0;
- printk("Product ID: %s ",str);
+ memcpy(oem, mpc->mpc_oem, 8);
+ oem[8] = 0;
+ memcpy(prod, mpc->mpc_productid, 12);
+ prod[12] = 0;
+ printk("OEM ID: %s ", oem);
+ printk("Product ID: %s ",prod);
+ /*
+ * Can't recognize Summit xAPICs (see below), so use OEM/Product IDs.
+ */
+ if (!strncmp(oem, "IBM ENSW", 8) &&
+ (!strncmp(prod, "NF 6000R", 8) || !strncmp(prod, "VIGIL SMP", 9)) )
+ xapic = 1;
+ else if (!strncmp(oem, "IBM NUMA", 8))
+ numaq = 2;
printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
@@ -426,7 +448,7 @@
if (!have_acpi_tables)
mp_lapic_addr = mpc->mpc_lapic;
- if (clustered_apic_mode && mpc->mpc_oemptr) {
+ if (clustered_apic_logical && mpc->mpc_oemptr) {
/* We need to process the oem mpc tables to tell us which quad things are in ... */
mpc_record = 0;
smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize);
@@ -466,6 +488,19 @@
MP_ioapic_info(m);
mpt+=sizeof(*m);
count+=sizeof(*m);
+ /******
+ * Kludge Alert! We have an APIC version number collision
+ * between the APICs on Scorpio-based NUMA-Q boxes and Summit
+ * xAPICs. Intel didn't define the xAPIC ver ID range until
+ * relatively recently, so there is working silicon out there
+ * that doesn't match their range.
+ * For now, use the OEM strings until we have some assurance
+ * that only xAPICs occupy the version number range below.
+ ****
+ if (m->mpc_apicver >= XAPIC_ID_LOW &&
+ m->mpc_apicver <= XAPIC_ID_HIGH)
+ xapic = 1;
+ ******/
break;
}
case MP_INTSRC:
@@ -495,10 +530,33 @@
}
++mpc_record;
}
- if (clustered_apic_mode && nr_ioapics > 2) {
- /* don't initialise IO apics on secondary quads */
+ if (xapic || numaq) {
+#ifdef CONFIG_SMP
+ if (numaq) {
+ xapic = 0; /* NUMA-Q boxes never had xAPICs */
+ /* Broadcast intrs to local quad only. */
+ target_cpus = APIC_BROADCAST_ID_APIC;
+ }
+ clustered_apic_logical = (unsigned char) numaq;
+ clustered_apic_physical = (unsigned char) xapic;
+ clustered_apic_mode = clustered_apic_logical | clustered_apic_physical;
+ esr_disable = 1;
+ apic_broadcast_id = (xapic ? APIC_BROADCAST_ID_XAPIC : APIC_BROADCAST_ID_APIC);
+ int_dest_addr_mode = (xapic ? APIC_DEST_PHYSICAL : APIC_DEST_LOGICAL);
+ int_delivery_mode = (xapic ? dest_Fixed : dest_LowestPrio);
+#endif /* CONFIG_SMP */
+ phys_cpu_present_map = logical_cpu_present_map;
+ }
+#ifdef CONFIG_SMP
+ if (numaq && nr_ioapics > 2) {
+ /* NUMA-Q: don't initialise IO apics on secondary quads, yet. */
nr_ioapics = 2;
}
+ printk("Enabling APIC mode: %s. Using %d I/O APICs\n",
+ (clustered_apic_logical ? "Clustered Logical" :
+ (clustered_apic_physical ?"Physical" : "Flat")),
+ nr_ioapics);
+#endif /* CONFIG_SMP */
if (!num_processors)
printk(KERN_ERR "SMP mptable: no processors registered!\n");
return num_processors;
diff -ru 2.4.17/arch/i386/kernel/process.c jamesc-2.4.17/arch/i386/kernel/process.c
--- 2.4.17/arch/i386/kernel/process.c Thu Oct 4 21:42:54 2001
+++ jamesc-2.4.17/arch/i386/kernel/process.c Thu Jan 17 14:51:47 2002
@@ -186,7 +186,7 @@
}
/* we will leave sorting out the final value
when we are ready to reboot, since we might not
- have set up boot_cpu_id or smp_num_cpu */
+ have set up boot_cpu_physical_apicid or smp_num_cpu */
break;
#endif
}
diff -ru 2.4.17/arch/i386/kernel/smp.c jamesc-2.4.17/arch/i386/kernel/smp.c
--- 2.4.17/arch/i386/kernel/smp.c Fri Dec 21 12:41:53 2001
+++ jamesc-2.4.17/arch/i386/kernel/smp.c Thu Jan 17 14:51:47 2002
@@ -115,7 +115,7 @@
static inline int __prepare_ICR (unsigned int shortcut, int vector)
{
- return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
+ return APIC_DM_FIXED | shortcut | vector | INT_DEST_ADDR_MODE;
}
static inline int __prepare_ICR2 (unsigned int mask)
@@ -214,7 +214,9 @@
/*
* prepare target chip field
*/
- cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
+ cfg = __prepare_ICR2(clustered_apic_physical ?
+ cpu_to_physical_apicid(query_cpu) :
+ cpu_to_logical_apicid(query_cpu));
apic_write_around(APIC_ICR2, cfg);
/*
diff -ru 2.4.17/arch/i386/kernel/smpboot.c jamesc-2.4.17/arch/i386/kernel/smpboot.c
--- 2.4.17/arch/i386/kernel/smpboot.c Fri Dec 21 12:41:53 2001
+++ jamesc-2.4.17/arch/i386/kernel/smpboot.c Thu Jan 17 14:51:47 2002
@@ -540,7 +540,7 @@
* else physical apic ids
*/
{
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
logical_apicid_2_cpu[apicid] = cpu;
cpu_2_logical_apicid[cpu] = apicid;
} else {
@@ -555,7 +555,7 @@
* else physical apic ids
*/
{
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
logical_apicid_2_cpu[apicid] = -1;
cpu_2_logical_apicid[cpu] = -1;
} else {
@@ -785,7 +785,7 @@
unsigned long boot_error = 0;
int timeout, cpu;
unsigned long start_eip;
- unsigned short nmi_high, nmi_low;
+ unsigned short nmi_high = 0, nmi_low = 0;
cpu = ++cpucount;
/*
@@ -830,7 +830,7 @@
Dprintk("Setting warm reset code and vector.\n");
- if (clustered_apic_mode) {
+ if (clustered_apic_logical) {
/* stash the current NMI vector, so we can put things back */
nmi_high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
nmi_low = *((volatile unsigned short *) TRAMPOLINE_LOW);
@@ -862,7 +862,7 @@
* Starting actual IPI sequence...
*/
- if (clustered_apic_mode)
+ if (clustered_apic_logical)
boot_error = wakeup_secondary_via_NMI(apicid);
else
boot_error = wakeup_secondary_via_INIT(apicid, start_eip);
@@ -917,7 +917,7 @@
/* mark "stuck" area as not stuck */
*((volatile unsigned long *)phys_to_virt(8192)) = 0;
- if(clustered_apic_mode) {
+ if (clustered_apic_logical) {
printk("Restoring NMI vector\n");
*((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high;
*((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low;
@@ -972,8 +972,10 @@
extern int prof_counter[NR_CPUS];
static int boot_cpu_logical_apicid;
+#ifdef CONFIG_MULTIQUAD
/* Where the IO area was mapped on multiquad, always 0 otherwise */
void *xquad_portio = NULL;
+#endif
int cpu_sibling_map[NR_CPUS] __cacheline_aligned;
@@ -981,12 +983,14 @@
{
int apicid, cpu, bit;
- if (clustered_apic_mode) {
+#ifdef CONFIG_MULTIQUAD
+ if (clustered_apic_logical) {
/* 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);
}
+#endif
#ifdef CONFIG_MTRR
/* Must be done before other processors booted */
@@ -1108,7 +1112,7 @@
if (apicid == boot_cpu_apicid)
continue;
- if (!(phys_cpu_present_map & (1 << bit)))
+ if (!(phys_cpu_present_map & (1ul << bit)))
continue;
if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
continue;
@@ -1119,9 +1123,9 @@
* Make sure we unmap all failed CPUs
*/
if ((boot_apicid_to_cpu(apicid) == -1) &&
- (phys_cpu_present_map & (1 << bit)))
- printk("CPU #%d not responding - cannot use it.\n",
- apicid);
+ (phys_cpu_present_map & (1ul << bit)))
+ printk("CPU #%d/0x%02x not responding - cannot use it.\n",
+ bit, apicid);
}
/*
diff -ru 2.4.17/arch/i386/kernel/trampoline.S jamesc-2.4.17/arch/i386/kernel/trampoline.S
--- 2.4.17/arch/i386/kernel/trampoline.S Thu Oct 4 21:42:54 2001
+++ jamesc-2.4.17/arch/i386/kernel/trampoline.S Thu Jan 17 14:51:47 2002
@@ -36,9 +36,9 @@
ENTRY(trampoline_data)
r_base = .
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_SMP
wbinvd
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_SMP */
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
diff -ru 2.4.17/include/asm-i386/apicdef.h jamesc-2.4.17/include/asm-i386/apicdef.h
--- 2.4.17/include/asm-i386/apicdef.h Sun Aug 12 14:13:59 2001
+++ jamesc-2.4.17/include/asm-i386/apicdef.h Thu Jan 17 14:51:47 2002
@@ -11,8 +11,15 @@
#define APIC_DEFAULT_PHYS_BASE 0xfee00000
#define APIC_ID 0x20
+#ifdef CONFIG_SMP /* Newer APIC family members have 8 bit phys IDs */
+#define APIC_ID_MASK (0xFF<<24)
+#define GET_APIC_ID(x) (((x)>>24)&0xFF)
+#else
#define APIC_ID_MASK (0x0F<<24)
#define GET_APIC_ID(x) (((x)>>24)&0x0F)
+#endif /* CONFIG_SMP */
+#define XAPIC_ID_LOW 0x14 /* Version num range */
+#define XAPIC_ID_HIGH 0x1F
#define APIC_LVR 0x30
#define APIC_LVR_MASK 0xFF00FF
#define GET_APIC_VERSION(x) ((x)&0xFF)
@@ -32,6 +39,8 @@
#define SET_APIC_LOGICAL_ID(x) (((x)<<24))
#define APIC_ALL_CPUS 0xFF
#define APIC_DFR 0xE0
+#define APIC_DFR_CLUSTER 0x0FFFFFFFul /* Clustered */
+#define APIC_DFR_FLAT 0xFFFFFFFFul /* Flat mode */
#define APIC_SPIV 0xF0
#define APIC_SPIV_FOCUS_DISABLED (1<<9)
#define APIC_SPIV_APIC_ENABLED (1<<8)
@@ -58,6 +67,7 @@
#define APIC_INT_ASSERT 0x04000
#define APIC_ICR_BUSY 0x01000
#define APIC_DEST_LOGICAL 0x00800
+#define APIC_DEST_PHYSICAL 0x0 /* For symmetry */
#define APIC_DM_FIXED 0x00000
#define APIC_DM_LOWEST 0x00100
#define APIC_DM_SMI 0x00200
@@ -107,7 +117,18 @@
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
-#define MAX_IO_APICS 8
+#ifdef CONFIG_SMP
+# define MAX_IO_APICS 32 /* Summit boxes can have 4*(2+3*2) I/O APICs */
+#else
+# define MAX_IO_APICS 8
+#endif /* CONFIG_SMP */
+
+/*
+ * The broadcast ID is 0xF for old APICs and 0xFF for xAPICs. SAPICs
+ * don't broadcast (yet?), but if they did, they might use 0xFFFF.
+ */
+#define APIC_BROADCAST_ID_XAPIC 0xFF
+#define APIC_BROADCAST_ID_APIC 0x0F
/*
* the local APIC register structure, memory mapped. Not terribly well
diff -ru 2.4.17/include/asm-i386/mpspec.h jamesc-2.4.17/include/asm-i386/mpspec.h
--- 2.4.17/include/asm-i386/mpspec.h Wed Jan 9 15:58:47 2002
+++ jamesc-2.4.17/include/asm-i386/mpspec.h Thu Jan 17 14:51:47 2002
@@ -14,13 +14,14 @@
#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
/*
- * a maximum of 16 APICs with the current APIC ID architecture.
+ * A maximum of 16 APICs with the classic APIC ID architecture.
+ * xAPICs can have up to 256. SAPICs have 16 ID bits.
*/
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_SMP
#define MAX_APICS 256
-#else /* !CONFIG_MULTIQUAD */
+#else /* !CONFIG_SMP */
#define MAX_APICS 16
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_SMP */
#define MAX_MPC_ENTRY 1024
@@ -184,13 +185,10 @@
* 7 2 CPU MCA+PCI
*/
-#ifdef CONFIG_MULTIQUAD
-#define MAX_IRQ_SOURCES 512
-#else /* !CONFIG_MULTIQUAD */
-#define MAX_IRQ_SOURCES 256
-#endif /* CONFIG_MULTIQUAD */
+#define MAX_MP_BUSSES 257 /* Need max PCI busses for hotplug + 1 for ISA. */
+ /* Four intrs per PCI slot. */
+#define MAX_IRQ_SOURCES (MAX_MP_BUSSES * 4)
-#define MAX_MP_BUSSES 32
enum mp_bustype {
MP_BUS_ISA = 1,
MP_BUS_EISA,
diff -ru 2.4.17/include/asm-i386/smp.h jamesc-2.4.17/include/asm-i386/smp.h
--- 2.4.17/include/asm-i386/smp.h Wed Jan 9 15:58:47 2002
+++ jamesc-2.4.17/include/asm-i386/smp.h Thu Jan 17 14:51:47 2002
@@ -23,27 +23,31 @@
#endif
#ifdef CONFIG_SMP
-# ifdef CONFIG_MULTIQUAD
-# define TARGET_CPUS 0xf /* all CPUs in *THIS* quad */
-# define INT_DELIVERY_MODE 0 /* physical delivery on LOCAL quad */
-# else
-# define TARGET_CPUS cpu_online_map
-# define INT_DELIVERY_MODE 1 /* logical delivery broadcast to all procs */
-# endif
+# ifndef __ASSEMBLY__
+ extern unsigned char clustered_apic_mode;
+ extern unsigned char clustered_apic_physical;
+ extern unsigned char clustered_apic_logical;
+ extern unsigned char target_cpus;
+ extern unsigned char esr_disable;
+ extern unsigned char int_delivery_mode;
+ extern unsigned int int_dest_addr_mode;
+ extern unsigned int apic_broadcast_id;
+# endif /* !__ASSEMBLY__ */
+# define TARGET_CPUS (target_cpus ? target_cpus : \
+ (clustered_apic_physical ? round_robin_cpu_apic_id() : \
+ cpu_online_map) )
+# define INT_DEST_ADDR_MODE (int_dest_addr_mode)
+# define INT_DELIVERY_MODE (int_delivery_mode)
#else
-# define INT_DELIVERY_MODE 1 /* logical delivery */
+# define clustered_apic_mode (0)
+# define clustered_apic_logical (0)
+# define clustered_apic_physical (0)
+# define apic_broadcast_id (APIC_BROADCAST_ID_APIC)
+# define esr_disable (0)
# define TARGET_CPUS 0x01
-#endif
-
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
- #define clustered_apic_mode (1)
- #define esr_disable (1)
- #else /* !CONFIG_MULTIQUAD */
- #define clustered_apic_mode (0)
- #define esr_disable (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif
+# define INT_DEST_ADDR_MODE 1 /* logical delivery */
+# define INT_DELIVERY_MODE (dest_LowestPrio)
+#endif /* CONFIG_SMP */
#ifdef CONFIG_SMP
#ifndef __ASSEMBLY__
@@ -53,6 +57,7 @@
*/
extern void smp_alloc_memory(void);
+extern unsigned long logical_cpu_present_map;
extern unsigned long phys_cpu_present_map;
extern unsigned long cpu_online_map;
extern volatile unsigned long smp_invalidate_needed;
@@ -112,7 +117,7 @@
return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
}
-static __inline int logical_smp_processor_id(void)
+extern __inline int logical_smp_processor_id(void)
{
/* we don't want to mark this access volatile - bad code generation */
return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
diff -ru 2.4.17/include/asm-i386/smpboot.h jamesc-2.4.17/include/asm-i386/smpboot.h
--- 2.4.17/include/asm-i386/smpboot.h Wed Jan 9 16:05:38 2002
+++ jamesc-2.4.17/include/asm-i386/smpboot.h Thu Jan 17 14:51:47 2002
@@ -1,36 +1,57 @@
#ifndef __ASM_SMPBOOT_H
#define __ASM_SMPBOOT_H
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
- #define clustered_apic_mode (1)
- #else /* !CONFIG_MULTIQUAD */
- #define clustered_apic_mode (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif
-
-#ifdef CONFIG_MULTIQUAD
- #define TRAMPOLINE_LOW phys_to_virt(0x8)
- #define TRAMPOLINE_HIGH phys_to_virt(0xa)
-#else /* !CONFIG_MULTIQUAD */
- #define TRAMPOLINE_LOW phys_to_virt(0x467)
- #define TRAMPOLINE_HIGH phys_to_virt(0x469)
-#endif /* CONFIG_MULTIQUAD */
-
-#ifdef CONFIG_MULTIQUAD
- #define boot_cpu_apicid boot_cpu_logical_apicid
-#else /* !CONFIG_MULTIQUAD */
- #define boot_cpu_apicid boot_cpu_physical_apicid
-#endif /* CONFIG_MULTIQUAD */
+#ifndef __ASM_SMP_H
+#include "asm/smp.h"
+#endif
+
+#define TRAMPOLINE_LOW phys_to_virt(clustered_apic_logical?0x8:0x467)
+#define TRAMPOLINE_HIGH phys_to_virt(clustered_apic_logical?0xa:0x469)
+
+#define boot_cpu_apicid (clustered_apic_logical?boot_cpu_logical_apicid:boot_cpu_physical_apicid)
+
+/*
+ * To build the logical APIC ID for each CPU we have three cases:
+ * 1) Normal flat mode: use a bitmap of the CPU numbers
+ * 2) Logical multi-quad (NUMA-Q): do nothing, the BIOS has set it up
+ * 3) Physical multi-quad (xAPIC clusters): convert the Intel standard
+ * physical APIC ID to a cluster nibble/cpu bitmap nibble
+ */
+#ifdef CONFIG_SMP
+/*** mps_cpu (index number): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... */
+/*** CPUs have xAPIC phys IDs: 00, 01, 02, 03, 10, 11, 12, 13, 20, 21, ... */
+/*** its logical ID: 01, 02, 04, 08, 11, 12, 14, 18, 21, 22, ... */
+#define physical_to_logical_apicid(phys_apic) ( (1UL << (phys_apic & 0x3)) | (phys_apic & 0xF0U) )
+
+static inline unsigned long apic_ldr_value(unsigned long value)
+{
+ if (clustered_apic_logical)
+ return (value);
+ if (clustered_apic_physical)
+ return (((value) & ~APIC_LDR_MASK) |
+ SET_APIC_LOGICAL_ID(physical_to_logical_apicid(hard_smp_processor_id())));
+ return (((value) & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(1UL << smp_processor_id()));
+}
+#else
+ #define apic_ldr_value(value) (((value) & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(1UL << smp_processor_id()))
+#endif /* CONFIG_SMP */
/*
- * How to map from the cpu_present_map
+ * How to map from phys_cpu_present_map.
+ * 1) Normal flat mode: use the mps_cpu, apicid bitmap
+ * 2) Multi-Quad: only 4 CPUs per cluster, cluster ID in high nibble
+ * use
*/
-#ifdef CONFIG_MULTIQUAD
- #define cpu_present_to_apicid(mps_cpu) ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) )
-#else /* !CONFIG_MULTIQUAD */
- #define cpu_present_to_apicid(apicid) (apicid)
-#endif /* CONFIG_MULTIQUAD */
+#ifdef CONFIG_SMP
+#define cpu_present_to_apicid(mps_cpu) (clustered_apic_logical ? \
+ ( ((mps_cpu / 4) * 16) + (1 << (mps_cpu % 4)) ) : \
+ (clustered_apic_physical ? raw_phys_apicid[mps_cpu] : (mps_cpu) ) )
+extern unsigned char raw_phys_apicid[NR_CPUS];
+#define apicid_to_phys_cpu_present(apicid) (clustered_apic_mode ? (1UL << (((apicid >> 4) << 2) + (apicid & 0x3))) : (1UL << apicid))
+#else /* CONFIG_SMP */
+#define cpu_present_to_apicid(mps_cpu) (mps_cpu)
+#define apicid_to_phys_cpu_present(apicid) (apicid)
+#endif /* CONFIG_SMP */
/*
* Mappings between logical cpu number and logical / physical apicid
@@ -45,18 +66,8 @@
#define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu]
#define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
#define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu]
-#ifdef CONFIG_MULTIQUAD /* use logical IDs to bootstrap */
-#define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid]
-#define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu]
-#else /* !CONFIG_MULTIQUAD */ /* use physical IDs to bootstrap */
-#define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
-#define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu]
-#endif /* CONFIG_MULTIQUAD */
-
-
-#ifdef CONFIG_MULTIQUAD
-#else /* !CONFIG_MULTIQUAD */
-#endif /* CONFIG_MULTIQUAD */
+#define boot_apicid_to_cpu(apicid) (clustered_apic_logical ? logical_apicid_2_cpu[apicid] : physical_apicid_2_cpu[apicid])
+#define cpu_to_boot_apicid(cpu) (clustered_apic_logical ? cpu_2_logical_apicid[cpu] : cpu_2_physical_apicid[cpu])
#endif
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2002-01-22 1:00 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-01-18 22:46 [RFC] Summit interrupt routing patches James Cleverdon
2002-01-18 23:15 ` Alan Cox
2002-01-19 0:18 ` James Cleverdon
2002-01-19 1:11 ` David S. Miller
2002-01-22 0:59 ` James Cleverdon
2002-01-19 1:18 ` Alan Cox
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®