setup_ioapic_ids_from_mpc()
By means of Zen, voodoo, and guessing the method from the results, I came to a conclusion somewhat resembling this patch.
Since this has approximately zero resemblance to the "Pee Cee" case, I think it best to avoid crossdressing the box to get it to survive IO-APIC init and just break off our own version which blindly trusts the BIOS and doesn't panic() at the drop of a hat, much unlike the Pee Cee version. It also runs (mostly) silent, which I consider a bonus.
100% untested. I'll spin it sometime tomorrow.
-- wli
===== arch/i386/kernel/io_apic.c 1.40 vs edited =====
arch/i386/kernel/io_apic.c +35 -1
@@ -1132,7 +1132,40 @@* by Matt Domsch <[email protected]> Tue Dec 21 12:25:05 CST 1999 */ -static void __init setup_ioapic_ids_from_mpc (void ) +#ifdef CONFIG_X86_NUMAQ +static void __init setup_ioapic_ids_from_mpc (void ) +{ +int io_apic; + +for (io_apic =0 ; io_apic < nr_ioapics; ++io_apic) { +struct IO_APIC_reg_00 reg; +int node, local, global, *regval = (int *)® + + global = mp_ioapics[apic].mpc_apicid; +for (node =0 ; node <MAX_NUMNODES ; ++node) { +if (mp_ioapic_id_map[node][0 ][0 ] == global) + local = mp_ioapic_id_map[node][0 ][1 ]; +else if (mp_ioapic_id_map[node][1 ][0 ] == global) + local = mp_ioapic_id_map[node][1 ][1 ]; + } + +if (!local) { +printk ("mystery IO-APIC, it will die\n" ); +continue ; + } + + +spin_lock_irqsave (&ioapic_lock, flags); + *regval =io_apic_read (apic,0 ); +if (reg.ID != local) { + reg.ID = local; +io_apic_write (apic,0 , *regval); + } +spin_unlock_irqrestore (&ioapic_lock, flags); + } +} +#else /* !CONFIG_X86_NUMAQ */ +static void __init setup_ioapic_ids_from_mpc (void ) {struct IO_APIC_reg_00 reg_00;unsigned long phys_id_present_map;
@@ -1225,6 +1258,7 @@ printk(" ok.\n"); } } +#endif /* * There is a nasty bug in some older SMP boards, their mptable lies
===== arch/i386/kernel/mpparse.c 1.32 vs edited =====
arch/i386/kernel/mpparse.c +2 -0
@@ -47,6 +47,7 @@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_ioapic_id_map [MAX_NUMNODES ][2 ][2 ];int mp_current_pci_id;/* I/O APIC entries */
@@ -232,6 +233,7 @@return ; } mp_ioapics[nr_ioapics] = *m; +mpc_oem_ioapic (m, str, translation_table[mpc_record]); nr_ioapics++; }
===== include/asm-i386/mpspec.h 1.11 vs edited =====
include/asm-i386/mpspec.h +1 -0
@@ -204,6 +204,7 @@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 int mp_ioapic_id_map [MAX_NUMNODES ][2 ][2 ];extern unsigned int boot_cpu_physical_apicid;extern unsigned long phys_cpu_present_map;
===== include/asm-i386/mach-default/mach_mpparse.h 1.2 vs edited =====
include/asm-i386/mach-default/mach_mpparse.h +5 -0
@@ -12,6 +12,11 @@ { } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
===== include/asm-i386/mach-numaq/mach_mpparse.h 1.4 vs edited =====
include/asm-i386/mach-numaq/mach_mpparse.h +19 -0
@@ -24,6 +24,25 @@ quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +int quad = translation->trans_quad; +int local = translation->trans_local; +int *info; + +if (!mp_ioapic_id_map[quad][0 ][0 ]) + info = mp_ioapic_id_map[quad][0 ]; +else if (!mp_ioapic_id_map[quad][1 ][0 ]) + info = mp_ioapic_id_map[quad][1 ]; +else { +printk ("bad IO-APIC! go to your quad!\n" ); +return ; + } + info[0 ] = global; + info[1 ] = local; +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
===== include/asm-i386/mach-summit/mach_mpparse.h 1.3 vs edited =====
include/asm-i386/mach-summit/mach_mpparse.h +5 -0
@@ -12,6 +12,11 @@ { } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
Quoted 1 line · William Lee Irwin III
100% untested. I'll spin it sometime tomorrow.
Take 2: I eyeballed a couple bogosities.
===== arch/i386/kernel/io_apic.c 1.40 vs edited =====
arch/i386/kernel/io_apic.c +36 -1
@@ -1132,7 +1132,41 @@* by Matt Domsch <[email protected]> Tue Dec 21 12:25:05 CST 1999 */ -static void __init setup_ioapic_ids_from_mpc (void ) +#ifdef CONFIG_X86_NUMAQ +static void __init setup_ioapic_ids_from_mpc (void ) +{ +int io_apic; + +for (io_apic =0 ; io_apic < nr_ioapics; ++io_apic) { +struct IO_APIC_reg_00 reg; +int node, local, global, *regval = (int *)® + + global = mp_ioapics[apic].mpc_apicid; + local =0 ; +for (node =0 ; node <MAX_NUMNODES ; ++node) { +if (mp_ioapic_id_map[node][0 ][0 ] == global) + local = mp_ioapic_id_map[node][0 ][1 ]; +else if (mp_ioapic_id_map[node][1 ][0 ] == global) + local = mp_ioapic_id_map[node][1 ][1 ]; + } + +if (!local) { +printk ("mystery IO-APIC, it will die\n" ); +continue ; + } + + +spin_lock_irqsave (&ioapic_lock, flags); + *regval =io_apic_read (io_apic,0 ); +if (reg.ID != local) { + reg.ID = local; +io_apic_write (io_apic,0 , *regval); + } +spin_unlock_irqrestore (&ioapic_lock, flags); + } +} +#else /* !CONFIG_X86_NUMAQ */ +static void __init setup_ioapic_ids_from_mpc (void ) {struct IO_APIC_reg_00 reg_00;unsigned long phys_id_present_map;
@@ -1225,6 +1259,7 @@ printk(" ok.\n"); } } +#endif /* * There is a nasty bug in some older SMP boards, their mptable lies
===== arch/i386/kernel/mpparse.c 1.32 vs edited =====
arch/i386/kernel/mpparse.c +2 -0
@@ -47,6 +47,7 @@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_ioapic_id_map [MAX_NUMNODES ][2 ][2 ];int mp_current_pci_id;/* I/O APIC entries */
@@ -232,6 +233,7 @@return ; } mp_ioapics[nr_ioapics] = *m; +mpc_oem_ioapic (m, str, translation_table[mpc_record]); nr_ioapics++; }
===== include/asm-i386/mpspec.h 1.11 vs edited =====
include/asm-i386/mpspec.h +1 -0
@@ -204,6 +204,7 @@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 int mp_ioapic_id_map [MAX_NUMNODES ][2 ][2 ];extern unsigned int boot_cpu_physical_apicid;extern unsigned long phys_cpu_present_map;
===== include/asm-i386/mach-default/mach_mpparse.h 1.2 vs edited =====
include/asm-i386/mach-default/mach_mpparse.h +5 -0
@@ -12,6 +12,11 @@ { } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
===== include/asm-i386/mach-numaq/mach_mpparse.h 1.4 vs edited =====
include/asm-i386/mach-numaq/mach_mpparse.h +19 -0
@@ -24,6 +24,25 @@ quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +int quad = translation->trans_quad; +int local = translation->trans_local; +int *info; + +if (!mp_ioapic_id_map[quad][0 ][0 ]) + info = mp_ioapic_id_map[quad][0 ]; +else if (!mp_ioapic_id_map[quad][1 ][0 ]) + info = mp_ioapic_id_map[quad][1 ]; +else { +printk ("bad IO-APIC! go to your quad!\n" ); +return ; + } + info[0 ] = global; + info[1 ] = local; +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
===== include/asm-i386/mach-summit/mach_mpparse.h 1.3 vs edited =====
include/asm-i386/mach-summit/mach_mpparse.h +5 -0
@@ -12,6 +12,11 @@ { } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
Quoted 1 line · William Lee Irwin III
Quoted 1 line
100% untested. I'll spin it sometime tomorrow.
Quoted 1 line · William Lee Irwin III
Take 2: I eyeballed a couple bogosities.
Take 3: flags undeclared, regval/reg aliasing might need barriers; speed is not an issue at boot-time, so slap down the heaviest barrier imaginable.
===== arch/i386/kernel/io_apic.c 1.40 vs edited =====
arch/i386/kernel/io_apic.c +39 -1
@@ -1132,7 +1132,44 @@* by Matt Domsch <[email protected]> Tue Dec 21 12:25:05 CST 1999 */ -static void __init setup_ioapic_ids_from_mpc (void ) +#ifdef CONFIG_X86_NUMAQ +static void __init setup_ioapic_ids_from_mpc (void ) +{ +int io_apic; + +for (io_apic =0 ; io_apic < nr_ioapics; ++io_apic) { +struct IO_APIC_reg_00 reg; +int node, local, global, *regval = (int *)® +unsigned long flags; + + global = mp_ioapics[apic].mpc_apicid; + local =0 ; +for (node =0 ; node <MAX_NUMNODES ; ++node) { +if (mp_ioapic_id_map[node][0 ][0 ] == global) + local = mp_ioapic_id_map[node][0 ][1 ]; +else if (mp_ioapic_id_map[node][1 ][0 ] == global) + local = mp_ioapic_id_map[node][1 ][1 ]; + } + +if (!local) { +printk ("mystery IO-APIC, it will die\n" ); +continue ; + } + + +spin_lock_irqsave (&ioapic_lock, flags); + *regval =io_apic_read (io_apic,0 ); +mb ();/* b/c regval aliases ® */ +if (reg.ID != local) { + reg.ID = local; +mb ();/* b/c regval aliases ® */ +io_apic_write (io_apic,0 , *regval); + } +spin_unlock_irqrestore (&ioapic_lock, flags); + } +} +#else /* !CONFIG_X86_NUMAQ */ +static void __init setup_ioapic_ids_from_mpc (void ) {struct IO_APIC_reg_00 reg_00;unsigned long phys_id_present_map;
@@ -1225,6 +1262,7 @@ printk(" ok.\n"); } } +#endif /* * There is a nasty bug in some older SMP boards, their mptable lies
===== arch/i386/kernel/mpparse.c 1.32 vs edited =====
arch/i386/kernel/mpparse.c +2 -0
@@ -47,6 +47,7 @@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_ioapic_id_map [MAX_NUMNODES ][2 ][2 ];int mp_current_pci_id;/* I/O APIC entries */
@@ -232,6 +233,7 @@return ; } mp_ioapics[nr_ioapics] = *m; +mpc_oem_ioapic (m, str, translation_table[mpc_record]); nr_ioapics++; }
===== include/asm-i386/mpspec.h 1.11 vs edited =====
include/asm-i386/mpspec.h +1 -0
@@ -204,6 +204,7 @@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 int mp_ioapic_id_map [MAX_NUMNODES ][2 ][2 ];extern unsigned int boot_cpu_physical_apicid;extern unsigned long phys_cpu_present_map;
===== include/asm-i386/mach-default/mach_mpparse.h 1.2 vs edited =====
include/asm-i386/mach-default/mach_mpparse.h +5 -0
@@ -12,6 +12,11 @@ { } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
===== include/asm-i386/mach-numaq/mach_mpparse.h 1.4 vs edited =====
include/asm-i386/mach-numaq/mach_mpparse.h +19 -0
@@ -24,6 +24,25 @@ quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +int quad = translation->trans_quad; +int local = translation->trans_local; +int *info; + +if (!mp_ioapic_id_map[quad][0 ][0 ]) + info = mp_ioapic_id_map[quad][0 ]; +else if (!mp_ioapic_id_map[quad][1 ][0 ]) + info = mp_ioapic_id_map[quad][1 ]; +else { +printk ("bad IO-APIC! go to your quad!\n" ); +return ; + } + info[0 ] = global; + info[1 ] = local; +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
===== include/asm-i386/mach-summit/mach_mpparse.h 1.3 vs edited =====
include/asm-i386/mach-summit/mach_mpparse.h +5 -0
@@ -12,6 +12,11 @@ { } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
Quoted 1 line · William Lee Irwin III
100% untested. I'll spin it sometime tomorrow.
This one is tested, and works.
Use NUMA-Q specific MP OEM tables to program the physical APIC ID's of the IO-APIC's. This fixes boot-time panic()'s on NUMA-Q's in the stock version of setup_ioapic_ids_from_mpc().
arch/i386/kernel/io_apic.c | 40 ++++++++++++++++++++++++++- arch/i386/kernel/mpparse.c | 2 + include/asm-i386/mach-default/mach_mpparse.h | 5 +++ include/asm-i386/mach-numaq/mach_mpparse.h | 19 ++++++++++++ include/asm-i386/mach-summit/mach_mpparse.h | 5 +++ include/asm-i386/mpspec.h | 3 ++ 6 files changed, 73 insertions(+), 1 deletion(-)
arch/i386/kernel/io_apic.c +39 -1
@@ -1438,7 +1438,44 @@ void disable_IO_APIC(void)* by Matt Domsch <[email protected]> Tue Dec 21 12:25:05 CST 1999 */ -static void __init setup_ioapic_ids_from_mpc (void ) +#ifdef CONFIG_X86_NUMAQ +static void __init setup_ioapic_ids_from_mpc (void ) +{ +int io_apic; + +for (io_apic =0 ; io_apic < nr_ioapics; ++io_apic) { +struct IO_APIC_reg_00 reg; +int node, local, global, *regval = (int *)® +unsigned long flags; + + global = mp_ioapics[io_apic].mpc_apicid; + local =0 ; +for (node =0 ; node <MAX_NUMNODES ; ++node) { +if (mp_ioapic_id_map[node][0 ][0 ] == global) + local = mp_ioapic_id_map[node][0 ][1 ]; +else if (mp_ioapic_id_map[node][1 ][0 ] == global) + local = mp_ioapic_id_map[node][1 ][1 ]; + } + +if (!local) { +printk ("mystery IO-APIC, it will die\n" ); +continue ; + } + + +spin_lock_irqsave (&ioapic_lock, flags); + *regval =io_apic_read (io_apic,0 ); +mb ();/* b/c regval aliases ® */ +if (reg.ID != local) { + reg.ID = local; +mb ();/* b/c regval aliases ® */ +io_apic_write (io_apic,0 , *regval); + } +spin_unlock_irqrestore (&ioapic_lock, flags); + } +} +#else /* !CONFIG_X86_NUMAQ */ +static void __init setup_ioapic_ids_from_mpc (void ) {struct IO_APIC_reg_00 reg_00;unsigned long phys_id_present_map;
@@ -1531,6 +1568,7 @@ static void __init setup_ioapic_ids_from printk(" ok.\n"); } } +#endif /* * There is a nasty bug in some older SMP boards, their mptable lies
arch/i386/kernel/mpparse.c +2 -0
@@ -47,6 +47,7 @@ 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_ioapic_id_map [MAX_NUMNODES ][2 ][2 ];int mp_current_pci_id;/* I/O APIC entries */
@@ -232,6 +233,7 @@ static void __init MP_ioapic_info (strucreturn ; } mp_ioapics[nr_ioapics] = *m; +mpc_oem_ioapic (m, translation_table[mpc_record]); nr_ioapics++; }
include/asm-i386/mach-default/mach_mpparse.h +5 -0
@@ -12,6 +12,11 @@ static inline void mpc_oem_pci_bus(struc { } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
include/asm-i386/mach-numaq/mach_mpparse.h +19 -0
@@ -24,6 +24,25 @@ static inline void mpc_oem_pci_bus(struc quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +int quad = translation->trans_quad; +int local = translation->trans_local; +int *info; + +if (!mp_ioapic_id_map[quad][0 ][0 ]) + info = mp_ioapic_id_map[quad][0 ]; +else if (!mp_ioapic_id_map[quad][1 ][0 ]) + info = mp_ioapic_id_map[quad][1 ]; +else { +printk ("bad IO-APIC! go to your quad!\n" ); +return ; + } + info[0 ] = m->mpc_apicid; + info[1 ] = local; +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
include/asm-i386/mach-summit/mach_mpparse.h +5 -0
@@ -12,6 +12,11 @@ static inline void mpc_oem_pci_bus(struc { } +static inline void mpc_oem_ioapic (struct mpc_config_ioapic *m, +struct mpc_config_translation *translation) +{ +} +static inline void mps_oem_check (struct mp_config_table *mpc,char *oem,char *productid) {
include/asm-i386/mpspec.h +3 -0
@@ -1,6 +1,8 @@#ifndef __ASM_MPSPEC_H#define __ASM_MPSPEC_H +#include <asm/numnodes.h> +/* * Structure definitions for SMP machines following the * Intel Multiprocessing Specification 1.1 and 1.4.
@@ -204,6 +206,7 @@ extern int mp_bus_id_to_node [MAX_MP_BUSextern 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 int mp_ioapic_id_map [MAX_NUMNODES ][2 ][2 ];extern unsigned int boot_cpu_physical_apicid;extern unsigned long phys_cpu_present_map;
Quoted 3 lines
Use NUMA-Q specific MP OEM tables to program the physical APIC ID's of the IO-APIC's. This fixes boot-time panic()'s on NUMA-Q's in the stock version of
setup_ioapic_ids_from_mpc().
I think you can just skip this whole routine altogether on NUMA-Q, it's all pre-programmed for us by firmware. Much smaller patch ;-)
M.
Quoted 3 lines · At some point in the past, I wrote:
Quoted 3 lines
Use NUMA-Q specific MP OEM tables to program the physical APIC ID's of the IO-APIC's. This fixes boot-time panic()'s on NUMA-Q's in the stock version of
setup_ioapic_ids_from_mpc().
Quoted 2 lines · Martin J. Bligh
I think you can just skip this whole routine altogether on NUMA-Q, it's all pre-programmed for us by firmware. Much smaller patch ;-)
Don't touch IO-APIC physid's on NUMA-Q. The BIOS pre-programs them.
io_apic.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletion(-)
arch/i386/kernel/io_apic.c +5 -1
@@ -1438,7 +1438,8 @@ void disable_IO_APIC(void)* by Matt Domsch <[email protected]> Tue Dec 21 12:25:05 CST 1999 */ -static void __init setup_ioapic_ids_from_mpc (void ) +#ifndef CONFIG_X86_NUMAQ +static void __init setup_ioapic_ids_from_mpc (void ) {struct IO_APIC_reg_00 reg_00;unsigned long phys_id_present_map;
@@ -1531,6 +1532,9 @@ static void __init setup_ioapic_ids_from printk(" ok.\n"); } } +#else +static void __init setup_ioapic_ids_from_mpc (void ) { } +#endif /* * There is a nasty bug in some older SMP boards, their mptable lies