Commit 1efe4998 authored by William Lee Irwin III's avatar William Lee Irwin III Committed by Linus Torvalds

[PATCH] APIC enumeration fixes

The following patch appears sound according to an audit to ensure that all
of the codepaths where it was introduced were called after the APIC
fixmappings were set up.

This patch introduces get_physical_broadcast(), which checks the version ID
of the local APIC to determine whether it's a serial APIC or xAPIC, and
returns the correct physical broadcast ID.  It replaces all uses of
APIC_BROADCAST_ID and IO_APIC_MAX_ID with this in order to ensure.  It also
changes the checks during MP table parsing so the APIC ID is checked in
tandem with the version number.

I'm holding out for some kind of testing to get an idea of whether this
covers the cases or introduces regressions, or whatever.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ed6b796c
...@@ -722,6 +722,17 @@ static int __init ioapic_pirq_setup(char *str) ...@@ -722,6 +722,17 @@ static int __init ioapic_pirq_setup(char *str)
__setup("pirq=", ioapic_pirq_setup); __setup("pirq=", ioapic_pirq_setup);
static int get_physical_broadcast(void)
{
unsigned int lvr, version;
lvr = apic_read(APIC_LVR);
version = GET_APIC_VERSION(lvr);
if (version >= 0x14)
return 0xff;
else
return 0xf;
}
/* /*
* Find the IRQ entry number of a certain pin. * Find the IRQ entry number of a certain pin.
*/ */
...@@ -1326,7 +1337,7 @@ void __init print_IO_APIC(void) ...@@ -1326,7 +1337,7 @@ void __init print_IO_APIC(void)
printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type); printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS); printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS);
if (reg_00.bits.ID >= APIC_BROADCAST_ID) if (reg_00.bits.ID >= get_physical_broadcast())
UNEXPECTED_IO_APIC(); UNEXPECTED_IO_APIC();
if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
UNEXPECTED_IO_APIC(); UNEXPECTED_IO_APIC();
...@@ -1642,7 +1653,7 @@ static void __init setup_ioapic_ids_from_mpc(void) ...@@ -1642,7 +1653,7 @@ static void __init setup_ioapic_ids_from_mpc(void)
old_id = mp_ioapics[apic].mpc_apicid; old_id = mp_ioapics[apic].mpc_apicid;
if (mp_ioapics[apic].mpc_apicid >= APIC_BROADCAST_ID) { if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) {
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
apic, mp_ioapics[apic].mpc_apicid); apic, mp_ioapics[apic].mpc_apicid);
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
...@@ -1663,10 +1674,10 @@ static void __init setup_ioapic_ids_from_mpc(void) ...@@ -1663,10 +1674,10 @@ static void __init setup_ioapic_ids_from_mpc(void)
mp_ioapics[apic].mpc_apicid)) { mp_ioapics[apic].mpc_apicid)) {
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
apic, mp_ioapics[apic].mpc_apicid); apic, mp_ioapics[apic].mpc_apicid);
for (i = 0; i < APIC_BROADCAST_ID; i++) for (i = 0; i < get_physical_broadcast(); i++)
if (!physid_isset(i, phys_id_present_map)) if (!physid_isset(i, phys_id_present_map))
break; break;
if (i >= APIC_BROADCAST_ID) if (i >= get_physical_broadcast())
panic("Max APIC ID exceeded!\n"); panic("Max APIC ID exceeded!\n");
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
i); i);
...@@ -2263,8 +2274,6 @@ late_initcall(io_apic_bug_finalize); ...@@ -2263,8 +2274,6 @@ late_initcall(io_apic_bug_finalize);
#ifdef CONFIG_ACPI_BOOT #ifdef CONFIG_ACPI_BOOT
#define IO_APIC_MAX_ID APIC_BROADCAST_ID
int __init io_apic_get_unique_id (int ioapic, int apic_id) int __init io_apic_get_unique_id (int ioapic, int apic_id)
{ {
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
...@@ -2289,7 +2298,7 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) ...@@ -2289,7 +2298,7 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id)
reg_00.raw = io_apic_read(ioapic, 0); reg_00.raw = io_apic_read(ioapic, 0);
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
if (apic_id >= IO_APIC_MAX_ID) { if (apic_id >= get_physical_broadcast()) {
printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
"%d\n", ioapic, apic_id, reg_00.bits.ID); "%d\n", ioapic, apic_id, reg_00.bits.ID);
apic_id = reg_00.bits.ID; apic_id = reg_00.bits.ID;
...@@ -2301,12 +2310,12 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) ...@@ -2301,12 +2310,12 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id)
*/ */
if (check_apicid_used(apic_id_map, apic_id)) { if (check_apicid_used(apic_id_map, apic_id)) {
for (i = 0; i < IO_APIC_MAX_ID; i++) { for (i = 0; i < get_physical_broadcast(); i++) {
if (!check_apicid_used(apic_id_map, i)) if (!check_apicid_used(apic_id_map, i))
break; break;
} }
if (i == IO_APIC_MAX_ID) if (i == get_physical_broadcast())
panic("Max apic_id exceeded!\n"); panic("Max apic_id exceeded!\n");
printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
#include <linux/bitops.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/acpi.h> #include <asm/acpi.h>
...@@ -103,6 +104,31 @@ static int __init mpf_checksum(unsigned char *mp, int len) ...@@ -103,6 +104,31 @@ static int __init mpf_checksum(unsigned char *mp, int len)
static int mpc_record; static int mpc_record;
static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata; static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata;
#ifdef CONFIG_X86_NUMAQ
static int MP_valid_apicid(int apicid, int version)
{
return hweight_long(i & 0xf) == 1 && (i >> 4) != 0xf;
}
#else
static int MP_valid_apicid(int apicid, int version)
{
if (version >= 0x14)
return apicid < 0xff;
else
return apicid < 0xf;
}
#endif
static void MP_mark_version_physids(int version)
{
int i;
for (i = 0; i < MAX_APICS; ++i) {
if (!MP_valid_apicid(i, version))
physid_set(i, phys_cpu_present_map);
}
}
void __init MP_processor_info (struct mpc_config_processor *m) void __init MP_processor_info (struct mpc_config_processor *m)
{ {
int ver, apicid; int ver, apicid;
...@@ -179,14 +205,16 @@ void __init MP_processor_info (struct mpc_config_processor *m) ...@@ -179,14 +205,16 @@ void __init MP_processor_info (struct mpc_config_processor *m)
return; return;
} }
num_processors++; num_processors++;
ver = m->mpc_apicver;
if (MAX_APICS - m->mpc_apicid <= 0) { if (MP_valid_apicid(m->mpc_apicid, ver))
MP_mark_version_physids(ver);
else {
printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n", printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n",
m->mpc_apicid, MAX_APICS); m->mpc_apicid, MAX_APICS);
--num_processors; --num_processors;
return; return;
} }
ver = m->mpc_apicver;
tmp = apicid_to_cpu_present(apicid); tmp = apicid_to_cpu_present(apicid);
physids_or(phys_cpu_present_map, phys_cpu_present_map, tmp); physids_or(phys_cpu_present_map, phys_cpu_present_map, tmp);
......
...@@ -57,12 +57,12 @@ void __init MP_processor_info (struct mpc_config_processor *m) ...@@ -57,12 +57,12 @@ void __init MP_processor_info (struct mpc_config_processor *m)
boot_cpu_logical_apicid = logical_apicid; boot_cpu_logical_apicid = logical_apicid;
} }
if (m->mpc_apicid > MAX_APICS) { ver = m->mpc_apicver;
if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) {
printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n", printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
m->mpc_apicid, MAX_APICS); m->mpc_apicid, MAX_APICS);
return; return;
} }
ver = m->mpc_apicver;
apic_cpus = apicid_to_cpu_present(m->mpc_apicid); apic_cpus = apicid_to_cpu_present(m->mpc_apicid);
physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus); physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
...@@ -75,6 +75,14 @@ void __init MP_processor_info (struct mpc_config_processor *m) ...@@ -75,6 +75,14 @@ void __init MP_processor_info (struct mpc_config_processor *m)
m->mpc_apicid); m->mpc_apicid);
ver = 0x10; ver = 0x10;
} }
if (ver >= 0x14)
physid_set(0xff, phys_cpu_present_map);
else {
int i;
for (i = 0xf; i < MAX_APICS; ++i)
physid_set(i, phys_cpu_present_map);
}
apic_version[m->mpc_apicid] = ver; apic_version[m->mpc_apicid] = ver;
} }
......
...@@ -25,7 +25,6 @@ struct genapic { ...@@ -25,7 +25,6 @@ struct genapic {
cpumask_t (*target_cpus)(void); cpumask_t (*target_cpus)(void);
int int_delivery_mode; int int_delivery_mode;
int int_dest_mode; int int_dest_mode;
int apic_broadcast_id;
int ESR_DISABLE; int ESR_DISABLE;
int apic_destination_logical; int apic_destination_logical;
unsigned long (*check_apicid_used)(physid_mask_t bitmap, int apicid); unsigned long (*check_apicid_used)(physid_mask_t bitmap, int apicid);
...@@ -78,7 +77,6 @@ struct genapic { ...@@ -78,7 +77,6 @@ struct genapic {
.probe = aprobe, \ .probe = aprobe, \
.int_delivery_mode = INT_DELIVERY_MODE, \ .int_delivery_mode = INT_DELIVERY_MODE, \
.int_dest_mode = INT_DEST_MODE, \ .int_dest_mode = INT_DEST_MODE, \
.apic_broadcast_id = APIC_BROADCAST_ID, \
.no_balance_irq = NO_BALANCE_IRQ, \ .no_balance_irq = NO_BALANCE_IRQ, \
.no_ioapic_check = NO_IOAPIC_CHECK, \ .no_ioapic_check = NO_IOAPIC_CHECK, \
.ESR_DISABLE = esr_disable, \ .ESR_DISABLE = esr_disable, \
......
...@@ -39,7 +39,6 @@ static inline cpumask_t target_cpus(void) ...@@ -39,7 +39,6 @@ static inline cpumask_t target_cpus(void)
#define INT_DELIVERY_MODE dest_Fixed #define INT_DELIVERY_MODE dest_Fixed
#define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */
#define APIC_BROADCAST_ID (0xff)
static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
{ {
return 0; return 0;
......
#ifndef __ASM_MACH_MPSPEC_H #ifndef __ASM_MACH_MPSPEC_H
#define __ASM_MACH_MPSPEC_H #define __ASM_MACH_MPSPEC_H
/*
* a maximum of 16 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 16
#define MAX_IRQ_SOURCES 256 #define MAX_IRQ_SOURCES 256
#define MAX_MP_BUSSES 32 #define MAX_MP_BUSSES 32
......
...@@ -23,12 +23,6 @@ static inline cpumask_const_t target_cpus(void) ...@@ -23,12 +23,6 @@ static inline cpumask_const_t target_cpus(void)
#define INT_DELIVERY_MODE dest_LowestPrio #define INT_DELIVERY_MODE dest_LowestPrio
#define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */
/*
* this isn't really broadcast, just a (potentially inaccurate) upper
* bound for valid physical APIC id's
*/
#define APIC_BROADCAST_ID 0x0F
static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
{ {
return physid_isset(apicid, bitmap); return physid_isset(apicid, bitmap);
......
#ifndef __ASM_MACH_MPSPEC_H #ifndef __ASM_MACH_MPSPEC_H
#define __ASM_MACH_MPSPEC_H #define __ASM_MACH_MPSPEC_H
/*
* a maximum of 16 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 16
#define MAX_IRQ_SOURCES 256 #define MAX_IRQ_SOURCES 256
#define MAX_MP_BUSSES 32 #define MAX_MP_BUSSES 32
......
...@@ -38,7 +38,6 @@ static inline cpumask_t target_cpus(void) ...@@ -38,7 +38,6 @@ static inline cpumask_t target_cpus(void)
#define WAKE_SECONDARY_VIA_INIT #define WAKE_SECONDARY_VIA_INIT
#endif #endif
#define APIC_BROADCAST_ID (0xff)
#define NO_IOAPIC_CHECK (1) #define NO_IOAPIC_CHECK (1)
static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
......
#ifndef __ASM_MACH_MPSPEC_H #ifndef __ASM_MACH_MPSPEC_H
#define __ASM_MACH_MPSPEC_H #define __ASM_MACH_MPSPEC_H
/*
* a maximum of 256 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 256
#define MAX_IRQ_SOURCES 256 #define MAX_IRQ_SOURCES 256
#define MAX_MP_BUSSES 32 #define MAX_MP_BUSSES 32
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#define esr_disable (genapic->ESR_DISABLE) #define esr_disable (genapic->ESR_DISABLE)
#define NO_BALANCE_IRQ (genapic->no_balance_irq) #define NO_BALANCE_IRQ (genapic->no_balance_irq)
#define NO_IOAPIC_CHECK (genapic->no_ioapic_check) #define NO_IOAPIC_CHECK (genapic->no_ioapic_check)
#define APIC_BROADCAST_ID (genapic->apic_broadcast_id)
#define INT_DELIVERY_MODE (genapic->int_delivery_mode) #define INT_DELIVERY_MODE (genapic->int_delivery_mode)
#define INT_DEST_MODE (genapic->int_dest_mode) #define INT_DEST_MODE (genapic->int_dest_mode)
#undef APIC_DEST_LOGICAL #undef APIC_DEST_LOGICAL
......
#ifndef __ASM_MACH_MPSPEC_H #ifndef __ASM_MACH_MPSPEC_H
#define __ASM_MACH_MPSPEC_H #define __ASM_MACH_MPSPEC_H
/*
* a maximum of 256 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 256
#define MAX_IRQ_SOURCES 256 #define MAX_IRQ_SOURCES 256
/* Summit or generic (i.e. installer) kernels need lots of bus entries. */ /* Summit or generic (i.e. installer) kernels need lots of bus entries. */
......
...@@ -22,7 +22,6 @@ static inline cpumask_t target_cpus(void) ...@@ -22,7 +22,6 @@ static inline cpumask_t target_cpus(void)
#define INT_DELIVERY_MODE dest_LowestPrio #define INT_DELIVERY_MODE dest_LowestPrio
#define INT_DEST_MODE 0 /* physical delivery on LOCAL quad */ #define INT_DEST_MODE 0 /* physical delivery on LOCAL quad */
#define APIC_BROADCAST_ID 0x0F
#define check_apicid_used(bitmap, apicid) physid_isset(apicid, bitmap) #define check_apicid_used(bitmap, apicid) physid_isset(apicid, bitmap)
#define check_apicid_present(bit) physid_isset(bit, phys_cpu_present_map) #define check_apicid_present(bit) physid_isset(bit, phys_cpu_present_map)
#define apicid_cluster(apicid) (apicid & 0xF0) #define apicid_cluster(apicid) (apicid & 0xF0)
......
#ifndef __ASM_MACH_MPSPEC_H #ifndef __ASM_MACH_MPSPEC_H
#define __ASM_MACH_MPSPEC_H #define __ASM_MACH_MPSPEC_H
/*
* a maximum of 256 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 256
#define MAX_IRQ_SOURCES 512 #define MAX_IRQ_SOURCES 512
#define MAX_MP_BUSSES 32 #define MAX_MP_BUSSES 32
......
...@@ -27,7 +27,6 @@ static inline cpumask_t target_cpus(void) ...@@ -27,7 +27,6 @@ static inline cpumask_t target_cpus(void)
#define INT_DELIVERY_MODE (dest_Fixed) #define INT_DELIVERY_MODE (dest_Fixed)
#define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */
#define APIC_BROADCAST_ID (0xFF)
static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
{ {
return 0; return 0;
......
#ifndef __ASM_MACH_MPSPEC_H #ifndef __ASM_MACH_MPSPEC_H
#define __ASM_MACH_MPSPEC_H #define __ASM_MACH_MPSPEC_H
/*
* a maximum of 256 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 256
#define MAX_IRQ_SOURCES 256 #define MAX_IRQ_SOURCES 256
/* Maximum 256 PCI busses, plus 1 ISA bus in each of 4 cabinets. */ /* Maximum 256 PCI busses, plus 1 ISA bus in each of 4 cabinets. */
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#define TARGET_CPUS cpumask_of_cpu(0) #define TARGET_CPUS cpumask_of_cpu(0)
#endif #endif
#define APIC_BROADCAST_ID 0x0F
#define check_apicid_used(bitmap, apicid) physid_isset(apicid, bitmap) #define check_apicid_used(bitmap, apicid) physid_isset(apicid, bitmap)
#define check_apicid_present(bit) physid_isset(bit, phys_cpu_present_map) #define check_apicid_present(bit) physid_isset(bit, phys_cpu_present_map)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') #define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
#define MAX_MPC_ENTRY 1024 #define MAX_MPC_ENTRY 1024
#define MAX_APICS 256
struct intel_mp_floating struct intel_mp_floating
{ {
......
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