2005-04-17 02:20:36 +04:00
/*
2008-05-14 19:02:57 +04:00
* Intel Multiprocessor Specification 1.1 and 1.4
2005-04-17 02:20:36 +04:00
* compliant MP - table parsing routines .
*
2009-01-05 17:08:04 +03:00
* ( c ) 1995 Alan Cox , Building # 3 < alan @ lxorguk . ukuu . org . uk >
2009-01-31 04:03:42 +03:00
* ( c ) 1998 , 1999 , 2000 , 2009 Ingo Molnar < mingo @ redhat . com >
2008-04-04 23:43:18 +04:00
* ( c ) 2008 Alexey Starikovskiy < astarikovskiy @ suse . de >
2005-04-17 02:20:36 +04:00
*/
# include <linux/mm.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/bootmem.h>
2010-08-26 00:39:17 +04:00
# include <linux/memblock.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel_stat.h>
# include <linux/mc146818rtc.h>
# include <linux/bitops.h>
2008-04-04 23:43:18 +04:00
# include <linux/acpi.h>
# include <linux/module.h>
2009-01-02 21:13:25 +03:00
# include <linux/smp.h>
2009-05-16 00:05:16 +04:00
# include <linux/pci.h>
2005-04-17 02:20:36 +04:00
# include <asm/mtrr.h>
# include <asm/mpspec.h>
2008-04-04 23:43:18 +04:00
# include <asm/pgalloc.h>
2005-04-17 02:20:36 +04:00
# include <asm/io_apic.h>
2008-04-04 23:43:18 +04:00
# include <asm/proto.h>
2008-03-17 22:08:17 +03:00
# include <asm/bios_ebda.h>
2008-06-02 00:17:38 +04:00
# include <asm/e820.h>
# include <asm/trampoline.h>
2008-07-19 13:07:25 +04:00
# include <asm/setup.h>
2009-01-11 16:08:55 +03:00
# include <asm/smp.h>
2005-04-17 02:20:36 +04:00
2009-02-17 15:58:15 +03:00
# include <asm/apic.h>
2005-04-17 02:20:36 +04:00
/*
* Checksum an MP configuration block .
*/
static int __init mpf_checksum ( unsigned char * mp , int len )
{
int sum = 0 ;
while ( len - - )
sum + = * mp + + ;
return sum & 0xFF ;
}
2009-08-20 12:41:58 +04:00
int __init default_mpc_apic_id ( struct mpc_cpu * m )
{
return m - > apicid ;
}
2009-01-03 13:18:52 +03:00
static void __init MP_processor_info ( struct mpc_cpu * m )
2008-03-27 23:54:13 +03:00
{
int apicid ;
2008-04-04 23:42:15 +04:00
char * bootup_cpu = " " ;
2008-03-27 23:54:13 +03:00
2009-01-04 19:28:25 +03:00
if ( ! ( m - > cpuflag & CPU_ENABLED ) ) {
2008-03-03 20:12:41 +03:00
disabled_cpus + + ;
2005-04-17 02:20:36 +04:00
return ;
2008-03-03 20:12:41 +03:00
}
2008-07-20 05:01:16 +04:00
2009-08-20 12:41:58 +04:00
apicid = x86_init . mpparse . mpc_apic_id ( m ) ;
2008-07-20 05:01:16 +04:00
2009-01-04 19:28:25 +03:00
if ( m - > cpuflag & CPU_BOOTPROCESSOR ) {
2008-04-04 23:42:15 +04:00
bootup_cpu = " (Bootup-CPU) " ;
2009-01-04 19:28:25 +03:00
boot_cpu_physical_apicid = m - > apicid ;
2005-04-17 02:20:36 +04:00
}
2009-01-04 19:28:25 +03:00
printk ( KERN_INFO " Processor #%d%s \n " , m - > apicid , bootup_cpu ) ;
generic_processor_info ( apicid , m - > apicver ) ;
2005-04-17 02:20:36 +04:00
}
2008-05-25 23:21:36 +04:00
# ifdef CONFIG_X86_IO_APIC
2009-08-20 14:34:47 +04:00
void __init default_mpc_oem_bus_info ( struct mpc_bus * m , char * str )
2005-04-17 02:20:36 +04:00
{
2009-01-04 19:29:26 +03:00
memcpy ( str , m - > bustype , 6 ) ;
2005-04-17 02:20:36 +04:00
str [ 6 ] = 0 ;
2009-08-20 14:34:47 +04:00
apic_printk ( APIC_VERBOSE , " Bus #%d is %s \n " , m - > busid , str ) ;
}
2005-04-17 02:20:36 +04:00
2009-08-20 14:34:47 +04:00
static void __init MP_bus_info ( struct mpc_bus * m )
{
char str [ 7 ] ;
2005-04-17 02:20:36 +04:00
2009-08-20 14:34:47 +04:00
x86_init . mpparse . mpc_oem_bus_info ( m , str ) ;
2005-04-17 02:20:36 +04:00
2006-09-26 12:52:35 +04:00
# if MAX_MP_BUSSES < 256
2009-01-04 19:29:26 +03:00
if ( m - > busid > = MAX_MP_BUSSES ) {
2006-04-11 09:53:13 +04:00
printk ( KERN_WARNING " MP table busid value (%d) for bustype %s "
2008-04-04 23:42:03 +04:00
" is too large, max. supported is %d \n " ,
2009-01-04 19:29:26 +03:00
m - > busid , str , MAX_MP_BUSSES - 1 ) ;
2006-04-11 09:53:13 +04:00
return ;
}
2006-09-26 12:52:35 +04:00
# endif
2006-04-11 09:53:13 +04:00
2011-09-26 01:29:00 +04:00
set_bit ( m - > busid , mp_bus_not_pci ) ;
2008-04-04 23:42:21 +04:00
if ( strncmp ( str , BUSTYPE_ISA , sizeof ( BUSTYPE_ISA ) - 1 ) = = 0 ) {
2009-01-02 21:13:25 +03:00
# if defined(CONFIG_EISA) || defined(CONFIG_MCA)
2009-01-04 19:29:26 +03:00
mp_bus_id_to_type [ m - > busid ] = MP_BUS_ISA ;
2008-04-04 23:42:21 +04:00
# endif
} else if ( strncmp ( str , BUSTYPE_PCI , sizeof ( BUSTYPE_PCI ) - 1 ) = = 0 ) {
2009-08-20 14:45:33 +04:00
if ( x86_init . mpparse . mpc_oem_pci_bus )
x86_init . mpparse . mpc_oem_pci_bus ( m ) ;
2008-07-20 05:01:16 +04:00
2009-01-04 19:29:26 +03:00
clear_bit ( m - > busid , mp_bus_not_pci ) ;
2009-01-02 21:13:25 +03:00
# if defined(CONFIG_EISA) || defined(CONFIG_MCA)
2009-01-04 19:29:26 +03:00
mp_bus_id_to_type [ m - > busid ] = MP_BUS_PCI ;
2008-04-04 23:42:03 +04:00
} else if ( strncmp ( str , BUSTYPE_EISA , sizeof ( BUSTYPE_EISA ) - 1 ) = = 0 ) {
2009-01-04 19:29:26 +03:00
mp_bus_id_to_type [ m - > busid ] = MP_BUS_EISA ;
2008-04-04 23:42:03 +04:00
} else if ( strncmp ( str , BUSTYPE_MCA , sizeof ( BUSTYPE_MCA ) - 1 ) = = 0 ) {
2009-01-04 19:29:26 +03:00
mp_bus_id_to_type [ m - > busid ] = MP_BUS_MCA ;
2008-03-20 14:55:02 +03:00
# endif
2008-04-04 23:42:21 +04:00
} else
printk ( KERN_WARNING " Unknown bustype %s - ignoring \n " , str ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-04 23:41:07 +04:00
2009-01-03 13:19:57 +03:00
static void __init MP_ioapic_info ( struct mpc_ioapic * m )
2005-04-17 02:20:36 +04:00
{
2010-12-08 10:18:57 +03:00
if ( m - > flags & MPC_APIC_USABLE )
mp_register_ioapic ( m - > apicid , m - > apicaddr , gsi_top ) ;
2008-06-02 00:17:38 +04:00
}
2009-01-12 15:17:22 +03:00
static void __init print_mp_irq_info ( struct mpc_intsrc * mp_irq )
2008-06-02 00:17:38 +04:00
{
2008-08-11 19:44:57 +04:00
apic_printk ( APIC_VERBOSE , " Int: type %d, pol %d, trig %d, bus %02x, "
2008-06-02 00:17:38 +04:00
" IRQ %02x, APIC ID %x, APIC INT %02x \n " ,
2009-01-12 15:17:22 +03:00
mp_irq - > irqtype , mp_irq - > irqflag & 3 ,
( mp_irq - > irqflag > > 2 ) & 3 , mp_irq - > srcbus ,
mp_irq - > srcbusirq , mp_irq - > dstapic , mp_irq - > dstirq ) ;
2008-06-02 00:17:38 +04:00
}
2009-03-18 18:12:28 +03:00
# else /* CONFIG_X86_IO_APIC */
static inline void __init MP_bus_info ( struct mpc_bus * m ) { }
static inline void __init MP_ioapic_info ( struct mpc_ioapic * m ) { }
# endif /* CONFIG_X86_IO_APIC */
2005-04-17 02:20:36 +04:00
2009-01-03 13:21:54 +03:00
static void __init MP_lintsrc_info ( struct mpc_lintsrc * m )
2005-04-17 02:20:36 +04:00
{
2008-08-11 19:44:57 +04:00
apic_printk ( APIC_VERBOSE , " Lint: type %d, pol %d, trig %d, bus %02x, "
2005-04-17 02:20:36 +04:00
" IRQ %02x, APIC ID %x, APIC LINT %02x \n " ,
2009-01-04 19:25:53 +03:00
m - > irqtype , m - > irqflag & 3 , ( m - > irqflag > > 2 ) & 3 , m - > srcbusid ,
m - > srcbusirq , m - > destapic , m - > destapiclint ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Read / parse the MPC
*/
2009-01-03 13:16:57 +03:00
static int __init smp_check_mpc ( struct mpc_table * mpc , char * oem , char * str )
2005-04-17 02:20:36 +04:00
{
2009-01-04 19:52:56 +03:00
if ( memcmp ( mpc - > signature , MPC_SIGNATURE , 4 ) ) {
2008-04-04 23:42:27 +04:00
printk ( KERN_ERR " MPTABLE: bad signature [%c%c%c%c]! \n " ,
2009-01-04 19:52:56 +03:00
mpc - > signature [ 0 ] , mpc - > signature [ 1 ] ,
mpc - > signature [ 2 ] , mpc - > signature [ 3 ] ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-04 19:52:56 +03:00
if ( mpf_checksum ( ( unsigned char * ) mpc , mpc - > length ) ) {
2008-04-04 23:42:27 +04:00
printk ( KERN_ERR " MPTABLE: checksum error! \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-04 19:52:56 +03:00
if ( mpc - > spec ! = 0x01 & & mpc - > spec ! = 0x04 ) {
2008-04-04 23:42:27 +04:00
printk ( KERN_ERR " MPTABLE: bad table version (%d)!! \n " ,
2009-01-04 19:52:56 +03:00
mpc - > spec ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-04 19:52:56 +03:00
if ( ! mpc - > lapic ) {
2008-04-04 23:42:27 +04:00
printk ( KERN_ERR " MPTABLE: null local APIC address! \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-04 19:52:56 +03:00
memcpy ( oem , mpc - > oem , 8 ) ;
2008-04-04 23:42:03 +04:00
oem [ 8 ] = 0 ;
2008-05-12 17:43:38 +04:00
printk ( KERN_INFO " MPTABLE: OEM ID: %s \n " , oem ) ;
2005-04-17 02:20:36 +04:00
2009-01-04 19:52:56 +03:00
memcpy ( str , mpc - > productid , 12 ) ;
2008-04-04 23:42:03 +04:00
str [ 12 ] = 0 ;
2005-04-17 02:20:36 +04:00
2008-05-12 17:43:38 +04:00
printk ( KERN_INFO " MPTABLE: Product ID: %s \n " , str ) ;
2005-04-17 02:20:36 +04:00
2009-01-04 19:52:56 +03:00
printk ( KERN_INFO " MPTABLE: APIC at: 0x%X \n " , mpc - > lapic ) ;
2005-04-17 02:20:36 +04:00
2008-06-02 00:17:38 +04:00
return 1 ;
}
2009-03-18 18:12:28 +03:00
static void skip_entry ( unsigned char * * ptr , int * count , int size )
{
* ptr + = size ;
* count + = size ;
}
2009-03-21 10:58:39 +03:00
static void __init smp_dump_mptable ( struct mpc_table * mpc , unsigned char * mpt )
{
printk ( KERN_ERR " Your mptable is wrong, contact your HW vendor! \n "
" type %x \n " , * mpt ) ;
print_hex_dump ( KERN_ERR , " " , DUMP_PREFIX_ADDRESS , 16 ,
1 , mpc , mpc - > length , 1 ) ;
}
2009-08-20 14:18:32 +04:00
void __init default_smp_read_mpc_oem ( struct mpc_table * mpc ) { }
2009-01-03 13:16:57 +03:00
static int __init smp_read_mpc ( struct mpc_table * mpc , unsigned early )
2008-06-02 00:17:38 +04:00
{
char str [ 16 ] ;
char oem [ 10 ] ;
int count = sizeof ( * mpc ) ;
unsigned char * mpt = ( ( unsigned char * ) mpc ) + count ;
if ( ! smp_check_mpc ( mpc , oem , str ) )
return 0 ;
# ifdef CONFIG_X86_32
2009-01-28 15:44:32 +03:00
generic_mps_oem_check ( mpc , oem , str ) ;
2008-06-02 00:17:38 +04:00
# endif
2010-12-07 11:55:29 +03:00
/* Initialize the lapic mapping */
2005-04-17 02:20:36 +04:00
if ( ! acpi_lapic )
2010-12-07 11:55:29 +03:00
register_lapic_address ( mpc - > lapic ) ;
2005-04-17 02:20:36 +04:00
2008-04-04 23:42:09 +04:00
if ( early )
return 1 ;
2009-08-20 14:18:32 +04:00
if ( mpc - > oemptr )
x86_init . mpparse . smp_read_mpc_oem ( mpc ) ;
2008-07-20 05:01:16 +04:00
2005-04-17 02:20:36 +04:00
/*
2008-04-04 23:42:03 +04:00
* Now process the configuration blocks .
2005-04-17 02:20:36 +04:00
*/
2009-08-20 14:05:01 +04:00
x86_init . mpparse . mpc_record ( 0 ) ;
2008-07-20 05:01:16 +04:00
2009-01-04 19:52:56 +03:00
while ( count < mpc - > length ) {
2008-04-04 23:42:03 +04:00
switch ( * mpt ) {
case MP_PROCESSOR :
2009-03-18 18:12:28 +03:00
/* ACPI may have already provided this data */
if ( ! acpi_lapic )
2009-03-19 10:50:35 +03:00
MP_processor_info ( ( struct mpc_cpu * ) mpt ) ;
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_cpu ) ) ;
break ;
2008-04-04 23:42:03 +04:00
case MP_BUS :
2009-03-19 10:50:35 +03:00
MP_bus_info ( ( struct mpc_bus * ) mpt ) ;
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_bus ) ) ;
break ;
2008-04-04 23:42:03 +04:00
case MP_IOAPIC :
2009-03-19 10:50:35 +03:00
MP_ioapic_info ( ( struct mpc_ioapic * ) mpt ) ;
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_ioapic ) ) ;
break ;
2008-04-04 23:42:03 +04:00
case MP_INTSRC :
2010-11-19 06:33:35 +03:00
mp_save_irq ( ( struct mpc_intsrc * ) mpt ) ;
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_intsrc ) ) ;
break ;
2008-04-04 23:42:03 +04:00
case MP_LINTSRC :
2009-03-19 10:50:35 +03:00
MP_lintsrc_info ( ( struct mpc_lintsrc * ) mpt ) ;
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_lintsrc ) ) ;
break ;
2008-04-04 23:42:03 +04:00
default :
2008-04-07 22:36:39 +04:00
/* wrong mptable */
2009-03-21 10:58:39 +03:00
smp_dump_mptable ( mpc , mpt ) ;
2009-01-04 19:52:56 +03:00
count = mpc - > length ;
2008-04-07 22:36:39 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2009-08-20 14:05:01 +04:00
x86_init . mpparse . mpc_record ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
2008-06-09 05:29:22 +04:00
2005-04-17 02:20:36 +04:00
if ( ! num_processors )
2008-04-04 23:42:27 +04:00
printk ( KERN_ERR " MPTABLE: no processors registered! \n " ) ;
2005-04-17 02:20:36 +04:00
return num_processors ;
}
2008-04-04 23:41:07 +04:00
# ifdef CONFIG_X86_IO_APIC
2005-04-17 02:20:36 +04:00
static int __init ELCR_trigger ( unsigned int irq )
{
unsigned int port ;
port = 0x4d0 + ( irq > > 3 ) ;
return ( inb ( port ) > > ( irq & 7 ) ) & 1 ;
}
static void __init construct_default_ioirq_mptable ( int mpc_default_type )
{
2009-01-03 13:20:52 +03:00
struct mpc_intsrc intsrc ;
2005-04-17 02:20:36 +04:00
int i ;
int ELCR_fallback = 0 ;
2009-01-04 19:26:44 +03:00
intsrc . type = MP_INTSRC ;
intsrc . irqflag = 0 ; /* conforming */
intsrc . srcbus = 0 ;
2011-05-19 03:31:37 +04:00
intsrc . dstapic = mpc_ioapic_id ( 0 ) ;
2005-04-17 02:20:36 +04:00
2009-01-04 19:26:44 +03:00
intsrc . irqtype = mp_INT ;
2005-04-17 02:20:36 +04:00
/*
* If true , we have an ISA / PCI system with no IRQ entries
* in the MP table . To prevent the PCI interrupts from being set up
* incorrectly , we try to use the ELCR . The sanity check to see if
* there is good ELCR data is very simple - IRQ0 , 1 , 2 and 13 can
* never be level sensitive , so we simply see if the ELCR agrees .
* If it does , we assume it ' s valid .
*/
if ( mpc_default_type = = 5 ) {
2008-04-04 23:42:34 +04:00
printk ( KERN_INFO " ISA/PCI bus type with no IRQ information... "
" falling back to ELCR \n " ) ;
2005-04-17 02:20:36 +04:00
2008-04-04 23:42:34 +04:00
if ( ELCR_trigger ( 0 ) | | ELCR_trigger ( 1 ) | | ELCR_trigger ( 2 ) | |
ELCR_trigger ( 13 ) )
printk ( KERN_ERR " ELCR contains invalid data... "
" not using ELCR \n " ) ;
2005-04-17 02:20:36 +04:00
else {
2008-04-04 23:42:03 +04:00
printk ( KERN_INFO
" Using ELCR to identify PCI interrupts \n " ) ;
2005-04-17 02:20:36 +04:00
ELCR_fallback = 1 ;
}
}
for ( i = 0 ; i < 16 ; i + + ) {
switch ( mpc_default_type ) {
case 2 :
if ( i = = 0 | | i = = 13 )
continue ; /* IRQ0 & IRQ13 not connected */
/* fall through */
default :
if ( i = = 2 )
continue ; /* IRQ2 is never connected */
}
if ( ELCR_fallback ) {
/*
* If the ELCR indicates a level - sensitive interrupt , we
* copy that information over to the MP table in the
* irqflag field ( level sensitive , active high polarity ) .
*/
if ( ELCR_trigger ( i ) )
2009-01-04 19:26:44 +03:00
intsrc . irqflag = 13 ;
2005-04-17 02:20:36 +04:00
else
2009-01-04 19:26:44 +03:00
intsrc . irqflag = 0 ;
2005-04-17 02:20:36 +04:00
}
2009-01-04 19:26:44 +03:00
intsrc . srcbusirq = i ;
intsrc . dstirq = i ? i : 2 ; /* IRQ0 to INTIN2 */
2010-11-19 06:33:35 +03:00
mp_save_irq ( & intsrc ) ;
2005-04-17 02:20:36 +04:00
}
2009-01-04 19:26:44 +03:00
intsrc . irqtype = mp_ExtINT ;
intsrc . srcbusirq = 0 ;
intsrc . dstirq = 0 ; /* 8259A to INTIN0 */
2010-11-19 06:33:35 +03:00
mp_save_irq ( & intsrc ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-04 23:41:07 +04:00
2008-08-11 02:09:38 +04:00
static void __init construct_ioapic_table ( int mpc_default_type )
2005-04-17 02:20:36 +04:00
{
2009-01-03 13:19:57 +03:00
struct mpc_ioapic ioapic ;
2009-01-03 13:17:32 +03:00
struct mpc_bus bus ;
2005-04-17 02:20:36 +04:00
2009-01-04 19:29:26 +03:00
bus . type = MP_BUS ;
bus . busid = 0 ;
2005-04-17 02:20:36 +04:00
switch ( mpc_default_type ) {
2008-04-04 23:42:03 +04:00
default :
2008-04-04 23:42:34 +04:00
printk ( KERN_ERR " ??? \n Unknown standard configuration %d \n " ,
2008-04-04 23:42:03 +04:00
mpc_default_type ) ;
/* fall through */
case 1 :
case 5 :
2009-01-04 19:29:26 +03:00
memcpy ( bus . bustype , " ISA " , 6 ) ;
2008-04-04 23:42:03 +04:00
break ;
case 2 :
case 6 :
case 3 :
2009-01-04 19:29:26 +03:00
memcpy ( bus . bustype , " EISA " , 6 ) ;
2008-04-04 23:42:03 +04:00
break ;
case 4 :
case 7 :
2009-01-04 19:29:26 +03:00
memcpy ( bus . bustype , " MCA " , 6 ) ;
2005-04-17 02:20:36 +04:00
}
MP_bus_info ( & bus ) ;
if ( mpc_default_type > 4 ) {
2009-01-04 19:29:26 +03:00
bus . busid = 1 ;
memcpy ( bus . bustype , " PCI " , 6 ) ;
2005-04-17 02:20:36 +04:00
MP_bus_info ( & bus ) ;
}
2009-08-24 21:53:36 +04:00
ioapic . type = MP_IOAPIC ;
ioapic . apicid = 2 ;
ioapic . apicver = mpc_default_type > 4 ? 0x10 : 0x01 ;
ioapic . flags = MPC_APIC_USABLE ;
ioapic . apicaddr = IO_APIC_DEFAULT_PHYS_BASE ;
2005-04-17 02:20:36 +04:00
MP_ioapic_info ( & ioapic ) ;
/*
* We set up most of the low 16 IO - APIC pins according to MPS rules .
*/
construct_default_ioirq_mptable ( mpc_default_type ) ;
2008-05-25 23:21:36 +04:00
}
# else
2008-08-11 02:09:38 +04:00
static inline void __init construct_ioapic_table ( int mpc_default_type ) { }
2008-04-04 23:41:07 +04:00
# endif
2008-05-25 23:21:36 +04:00
static inline void __init construct_default_ISA_mptable ( int mpc_default_type )
{
2009-01-03 13:18:52 +03:00
struct mpc_cpu processor ;
2009-01-03 13:21:54 +03:00
struct mpc_lintsrc lintsrc ;
2008-05-25 23:21:36 +04:00
int linttypes [ 2 ] = { mp_ExtINT , mp_NMI } ;
int i ;
/*
* local APIC has default address
*/
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE ;
/*
* 2 CPUs , numbered 0 & 1.
*/
2009-01-04 19:28:25 +03:00
processor . type = MP_PROCESSOR ;
2008-05-25 23:21:36 +04:00
/* Either an integrated APIC or a discrete 82489DX. */
2009-01-04 19:28:25 +03:00
processor . apicver = mpc_default_type > 4 ? 0x10 : 0x01 ;
processor . cpuflag = CPU_ENABLED ;
processor . cpufeature = ( boot_cpu_data . x86 < < 8 ) |
2008-05-25 23:21:36 +04:00
( boot_cpu_data . x86_model < < 4 ) | boot_cpu_data . x86_mask ;
2009-01-04 19:28:25 +03:00
processor . featureflag = boot_cpu_data . x86_capability [ 0 ] ;
processor . reserved [ 0 ] = 0 ;
processor . reserved [ 1 ] = 0 ;
2008-05-25 23:21:36 +04:00
for ( i = 0 ; i < 2 ; i + + ) {
2009-01-04 19:28:25 +03:00
processor . apicid = i ;
2008-05-25 23:21:36 +04:00
MP_processor_info ( & processor ) ;
}
construct_ioapic_table ( mpc_default_type ) ;
2009-01-04 19:25:53 +03:00
lintsrc . type = MP_LINTSRC ;
lintsrc . irqflag = 0 ; /* conforming */
lintsrc . srcbusid = 0 ;
lintsrc . srcbusirq = 0 ;
lintsrc . destapic = MP_APIC_ALL ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < 2 ; i + + ) {
2009-01-04 19:25:53 +03:00
lintsrc . irqtype = linttypes [ i ] ;
lintsrc . destapiclint = i ;
2005-04-17 02:20:36 +04:00
MP_lintsrc_info ( & lintsrc ) ;
}
}
2009-01-08 13:12:46 +03:00
static struct mpf_intel * mpf_found ;
2005-04-17 02:20:36 +04:00
2009-03-04 12:25:21 +03:00
static unsigned long __init get_mpc_size ( unsigned long physptr )
{
struct mpc_table * mpc ;
unsigned long size ;
mpc = early_ioremap ( physptr , PAGE_SIZE ) ;
size = mpc - > length ;
early_iounmap ( mpc , PAGE_SIZE ) ;
apic_printk ( APIC_VERBOSE , " mpc: %lx-%lx \n " , physptr , physptr + size ) ;
return size ;
}
2009-03-21 11:13:20 +03:00
static int __init check_physptr ( struct mpf_intel * mpf , unsigned int early )
{
struct mpc_table * mpc ;
unsigned long size ;
size = get_mpc_size ( mpf - > physptr ) ;
mpc = early_ioremap ( mpf - > physptr , size ) ;
/*
* Read the physical hardware table . Anything here will
* override the defaults .
*/
if ( ! smp_read_mpc ( mpc , early ) ) {
# ifdef CONFIG_X86_LOCAL_APIC
smp_found_config = 0 ;
# endif
printk ( KERN_ERR " BIOS bug, MP table errors detected!... \n "
" ... disabling SMP support. (tell your hw vendor) \n " ) ;
early_iounmap ( mpc , size ) ;
return - 1 ;
}
early_iounmap ( mpc , size ) ;
if ( early )
return - 1 ;
# ifdef CONFIG_X86_IO_APIC
/*
* If there are no explicit MP IRQ entries , then we are
* broken . We set up most of the low 16 IO - APIC pins to
* ISA defaults and hope it will work .
*/
if ( ! mp_irq_entries ) {
struct mpc_bus bus ;
printk ( KERN_ERR " BIOS bug, no explicit IRQ entries, "
" using default mptable. (tell your hw vendor) \n " ) ;
bus . type = MP_BUS ;
bus . busid = 0 ;
memcpy ( bus . bustype , " ISA " , 6 ) ;
MP_bus_info ( & bus ) ;
construct_default_ioirq_mptable ( 0 ) ;
}
# endif
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*
* Scan the memory blocks for an SMP configuration block .
*/
2009-08-20 13:11:52 +04:00
void __init default_get_smp_config ( unsigned int early )
2005-04-17 02:20:36 +04:00
{
2009-01-08 13:12:46 +03:00
struct mpf_intel * mpf = mpf_found ;
2005-04-17 02:20:36 +04:00
2008-12-06 09:45:50 +03:00
if ( ! mpf )
return ;
2008-04-04 23:42:09 +04:00
if ( acpi_lapic & & early )
return ;
2008-12-06 09:45:50 +03:00
2005-04-17 02:20:36 +04:00
/*
2008-12-06 09:45:50 +03:00
* MPS doesn ' t support hyperthreading , aka only have
* thread 0 apic id in MPS table
2005-04-17 02:20:36 +04:00
*/
2008-12-06 09:45:50 +03:00
if ( acpi_lapic & & acpi_ioapic )
2005-04-17 02:20:36 +04:00
return ;
2008-04-04 23:42:03 +04:00
printk ( KERN_INFO " Intel MultiProcessor Specification v1.%d \n " ,
2009-01-08 13:13:26 +03:00
mpf - > specification ) ;
2008-05-23 01:54:44 +04:00
# if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
2009-01-08 13:13:26 +03:00
if ( mpf - > feature2 & ( 1 < < 7 ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " IMCR and PIC compatibility mode. \n " ) ;
pic_mode = 1 ;
} else {
printk ( KERN_INFO " Virtual Wire compatibility mode. \n " ) ;
pic_mode = 0 ;
}
2008-04-04 23:42:40 +04:00
# endif
2005-04-17 02:20:36 +04:00
/*
* Now see if we need to read further .
*/
2009-01-08 13:13:26 +03:00
if ( mpf - > feature1 ! = 0 ) {
2008-04-04 23:42:09 +04:00
if ( early ) {
/*
* local APIC has default address
*/
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE ;
return ;
}
2005-04-17 02:20:36 +04:00
2008-04-04 23:42:03 +04:00
printk ( KERN_INFO " Default MP configuration #%d \n " ,
2009-01-08 13:13:26 +03:00
mpf - > feature1 ) ;
construct_default_ISA_mptable ( mpf - > feature1 ) ;
2005-04-17 02:20:36 +04:00
2009-01-08 13:13:26 +03:00
} else if ( mpf - > physptr ) {
2009-03-21 11:13:20 +03:00
if ( check_physptr ( mpf , early ) )
2005-04-17 02:20:36 +04:00
return ;
} else
BUG ( ) ;
2008-04-04 23:42:09 +04:00
if ( ! early )
printk ( KERN_INFO " Processors: %d \n " , num_processors ) ;
2005-04-17 02:20:36 +04:00
/*
* Only use the first configuration found .
*/
}
2009-11-24 13:48:18 +03:00
static void __init smp_reserve_memory ( struct mpf_intel * mpf )
2009-03-18 18:12:28 +03:00
{
2011-07-12 13:16:06 +04:00
memblock_reserve ( mpf - > physptr , get_mpc_size ( mpf - > physptr ) ) ;
2009-03-18 18:12:28 +03:00
}
2009-11-24 13:48:18 +03:00
static int __init smp_scan_config ( unsigned long base , unsigned long length )
2005-04-17 02:20:36 +04:00
{
2008-04-04 23:42:46 +04:00
unsigned int * bp = phys_to_virt ( base ) ;
2009-01-08 13:12:46 +03:00
struct mpf_intel * mpf ;
2009-11-24 13:48:18 +03:00
unsigned long mem ;
2005-04-17 02:20:36 +04:00
2008-08-11 19:44:57 +04:00
apic_printk ( APIC_VERBOSE , " Scan SMP from %p for %ld bytes. \n " ,
bp , length ) ;
2008-04-19 18:55:11 +04:00
BUILD_BUG_ON ( sizeof ( * mpf ) ! = 16 ) ;
2005-04-17 02:20:36 +04:00
while ( length > 0 ) {
2009-01-08 13:12:46 +03:00
mpf = ( struct mpf_intel * ) bp ;
2005-04-17 02:20:36 +04:00
if ( ( * bp = = SMP_MAGIC_IDENT ) & &
2009-01-08 13:13:26 +03:00
( mpf - > length = = 1 ) & &
2008-04-04 23:42:03 +04:00
! mpf_checksum ( ( unsigned char * ) bp , 16 ) & &
2009-01-08 13:13:26 +03:00
( ( mpf - > specification = = 1 )
| | ( mpf - > specification = = 4 ) ) ) {
2008-05-19 19:47:03 +04:00
# ifdef CONFIG_X86_LOCAL_APIC
2005-04-17 02:20:36 +04:00
smp_found_config = 1 ;
2008-05-19 19:47:03 +04:00
# endif
2008-04-04 23:42:46 +04:00
mpf_found = mpf ;
2008-06-10 05:11:36 +04:00
2009-02-11 21:08:25 +03:00
printk ( KERN_INFO " found SMP MP-table at [%p] %llx \n " ,
mpf , ( u64 ) virt_to_phys ( mpf ) ) ;
2008-06-10 05:11:36 +04:00
2009-11-24 13:48:18 +03:00
mem = virt_to_phys ( mpf ) ;
2011-07-12 13:16:06 +04:00
memblock_reserve ( mem , sizeof ( * mpf ) ) ;
2009-03-18 18:12:28 +03:00
if ( mpf - > physptr )
2009-11-24 13:48:18 +03:00
smp_reserve_memory ( mpf ) ;
2005-04-17 02:20:36 +04:00
2008-06-13 13:00:56 +04:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
bp + = 4 ;
length - = 16 ;
}
return 0 ;
}
2009-11-24 13:48:18 +03:00
void __init default_find_smp_config ( void )
2005-04-17 02:20:36 +04:00
{
unsigned int address ;
/*
* FIXME : Linux assumes you have 640 K of base ram . .
* this continues the error . . .
*
* 1 ) Scan the bottom 1 K for a signature
* 2 ) Scan the top 1 K of base RAM
* 3 ) Scan the 64 K of bios
*/
2009-11-24 13:48:18 +03:00
if ( smp_scan_config ( 0x0 , 0x400 ) | |
smp_scan_config ( 639 * 0x400 , 0x400 ) | |
smp_scan_config ( 0xF0000 , 0x10000 ) )
2005-04-17 02:20:36 +04:00
return ;
/*
* If it is an SMP machine we should know now , unless the
* configuration is in an EISA / MCA bus machine with an
* extended bios data area .
*
* there is a real - mode segmented pointer pointing to the
* 4 K EBDA area at 0x40E , calculate and scan it here .
*
* NOTE ! There are Linux loaders that will corrupt the EBDA
* area , and as such this kind of SMP config may be less
* trustworthy , simply because the SMP table may have been
* stomped on during early boot . These loaders are buggy and
* should be fixed .
*
* MP1 .4 SPEC states to only scan first 1 K of 4 K EBDA .
*/
address = get_bios_ebda ( ) ;
if ( address )
2009-11-24 13:48:18 +03:00
smp_scan_config ( address , 0x400 ) ;
2008-04-04 23:42:09 +04:00
}
2008-06-02 00:17:38 +04:00
# ifdef CONFIG_X86_IO_APIC
static u8 __initdata irq_used [ MAX_IRQ_SOURCES ] ;
2009-01-03 13:20:52 +03:00
static int __init get_MP_intsrc_index ( struct mpc_intsrc * m )
2008-06-02 00:17:38 +04:00
{
int i ;
2009-01-04 19:26:44 +03:00
if ( m - > irqtype ! = mp_INT )
2008-06-02 00:17:38 +04:00
return 0 ;
2009-01-04 19:26:44 +03:00
if ( m - > irqflag ! = 0x0f )
2008-06-02 00:17:38 +04:00
return 0 ;
/* not legacy */
for ( i = 0 ; i < mp_irq_entries ; i + + ) {
2009-01-12 15:17:22 +03:00
if ( mp_irqs [ i ] . irqtype ! = mp_INT )
2008-06-02 00:17:38 +04:00
continue ;
2009-01-12 15:17:22 +03:00
if ( mp_irqs [ i ] . irqflag ! = 0x0f )
2008-06-02 00:17:38 +04:00
continue ;
2009-01-12 15:17:22 +03:00
if ( mp_irqs [ i ] . srcbus ! = m - > srcbus )
2008-06-02 00:17:38 +04:00
continue ;
2009-01-12 15:17:22 +03:00
if ( mp_irqs [ i ] . srcbusirq ! = m - > srcbusirq )
2008-06-02 00:17:38 +04:00
continue ;
if ( irq_used [ i ] ) {
/* already claimed */
return - 2 ;
}
irq_used [ i ] = 1 ;
return i ;
}
/* not found */
return - 1 ;
}
# define SPARE_SLOT_NUM 20
2009-01-03 13:20:52 +03:00
static struct mpc_intsrc __initdata * m_spare [ SPARE_SLOT_NUM ] ;
2009-03-18 18:12:28 +03:00
2009-04-11 07:04:59 +04:00
static void __init check_irq_src ( struct mpc_intsrc * m , int * nr_m_spare )
2009-03-18 18:12:28 +03:00
{
int i ;
apic_printk ( APIC_VERBOSE , " OLD " ) ;
2010-12-08 10:18:57 +03:00
print_mp_irq_info ( m ) ;
2009-03-18 18:12:28 +03:00
i = get_MP_intsrc_index ( m ) ;
if ( i > 0 ) {
2010-12-08 10:18:57 +03:00
memcpy ( m , & mp_irqs [ i ] , sizeof ( * m ) ) ;
2009-03-18 18:12:28 +03:00
apic_printk ( APIC_VERBOSE , " NEW " ) ;
print_mp_irq_info ( & mp_irqs [ i ] ) ;
return ;
}
if ( ! i ) {
/* legacy, do nothing */
return ;
}
if ( * nr_m_spare < SPARE_SLOT_NUM ) {
/*
* not found ( - 1 ) , or duplicated ( - 2 ) are invalid entries ,
* we need to use the slot later
*/
m_spare [ * nr_m_spare ] = m ;
* nr_m_spare + = 1 ;
}
}
2011-04-02 11:17:48 +04:00
static int __init
2009-05-06 21:07:07 +04:00
check_slot ( unsigned long mpc_new_phys , unsigned long mpc_new_length , int count )
2009-03-18 18:12:28 +03:00
{
2009-05-06 21:07:07 +04:00
if ( ! mpc_new_phys | | count < = mpc_new_length ) {
WARN ( 1 , " update_mptable: No spare slots (length: %x) \n " , count ) ;
return - 1 ;
2009-03-18 18:12:28 +03:00
}
2011-03-23 18:31:40 +03:00
return 0 ;
2009-03-18 18:12:28 +03:00
}
2011-03-22 12:24:54 +03:00
# else /* CONFIG_X86_IO_APIC */
static
inline void __init check_irq_src ( struct mpc_intsrc * m , int * nr_m_spare ) { }
# endif /* CONFIG_X86_IO_APIC */
2008-06-02 00:17:38 +04:00
2009-01-03 13:16:57 +03:00
static int __init replace_intsrc_all ( struct mpc_table * mpc ,
2008-06-02 00:17:38 +04:00
unsigned long mpc_new_phys ,
unsigned long mpc_new_length )
{
# ifdef CONFIG_X86_IO_APIC
int i ;
# endif
int count = sizeof ( * mpc ) ;
2009-03-18 18:12:28 +03:00
int nr_m_spare = 0 ;
2008-06-02 00:17:38 +04:00
unsigned char * mpt = ( ( unsigned char * ) mpc ) + count ;
2009-01-04 19:52:56 +03:00
printk ( KERN_INFO " mpc_length %x \n " , mpc - > length ) ;
while ( count < mpc - > length ) {
2008-06-02 00:17:38 +04:00
switch ( * mpt ) {
case MP_PROCESSOR :
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_cpu ) ) ;
break ;
2008-06-02 00:17:38 +04:00
case MP_BUS :
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_bus ) ) ;
break ;
2008-06-02 00:17:38 +04:00
case MP_IOAPIC :
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_ioapic ) ) ;
break ;
2008-06-02 00:17:38 +04:00
case MP_INTSRC :
2009-03-19 10:50:35 +03:00
check_irq_src ( ( struct mpc_intsrc * ) mpt , & nr_m_spare ) ;
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_intsrc ) ) ;
break ;
2008-06-02 00:17:38 +04:00
case MP_LINTSRC :
2009-03-18 18:12:28 +03:00
skip_entry ( & mpt , & count , sizeof ( struct mpc_lintsrc ) ) ;
break ;
2008-06-02 00:17:38 +04:00
default :
/* wrong mptable */
2009-03-21 10:58:39 +03:00
smp_dump_mptable ( mpc , mpt ) ;
2008-06-02 00:17:38 +04:00
goto out ;
}
}
# ifdef CONFIG_X86_IO_APIC
for ( i = 0 ; i < mp_irq_entries ; i + + ) {
if ( irq_used [ i ] )
continue ;
2009-01-12 15:17:22 +03:00
if ( mp_irqs [ i ] . irqtype ! = mp_INT )
2008-06-02 00:17:38 +04:00
continue ;
2009-01-12 15:17:22 +03:00
if ( mp_irqs [ i ] . irqflag ! = 0x0f )
2008-06-02 00:17:38 +04:00
continue ;
if ( nr_m_spare > 0 ) {
2009-03-12 15:57:10 +03:00
apic_printk ( APIC_VERBOSE , " *NEW* found \n " ) ;
2008-06-02 00:17:38 +04:00
nr_m_spare - - ;
2010-12-08 10:18:57 +03:00
memcpy ( m_spare [ nr_m_spare ] , & mp_irqs [ i ] , sizeof ( mp_irqs [ i ] ) ) ;
2008-06-02 00:17:38 +04:00
m_spare [ nr_m_spare ] = NULL ;
} else {
2009-01-03 13:20:52 +03:00
struct mpc_intsrc * m = ( struct mpc_intsrc * ) mpt ;
count + = sizeof ( struct mpc_intsrc ) ;
2009-05-06 21:07:07 +04:00
if ( check_slot ( mpc_new_phys , mpc_new_length , count ) < 0 )
2009-03-18 18:12:28 +03:00
goto out ;
2010-12-08 10:18:57 +03:00
memcpy ( m , & mp_irqs [ i ] , sizeof ( * m ) ) ;
2009-01-04 19:52:56 +03:00
mpc - > length = count ;
2009-01-03 13:20:52 +03:00
mpt + = sizeof ( struct mpc_intsrc ) ;
2008-06-02 00:17:38 +04:00
}
print_mp_irq_info ( & mp_irqs [ i ] ) ;
}
# endif
out :
/* update checksum */
2009-01-04 19:52:56 +03:00
mpc - > checksum = 0 ;
mpc - > checksum - = mpf_checksum ( ( unsigned char * ) mpc , mpc - > length ) ;
2008-06-02 00:17:38 +04:00
return 0 ;
}
2009-05-16 00:05:16 +04:00
int enable_update_mptable ;
2008-06-19 04:29:31 +04:00
2008-06-02 00:17:38 +04:00
static int __init update_mptable_setup ( char * str )
{
enable_update_mptable = 1 ;
2009-05-16 00:05:16 +04:00
# ifdef CONFIG_PCI
pci_routeirq = 1 ;
# endif
2008-06-02 00:17:38 +04:00
return 0 ;
}
early_param ( " update_mptable " , update_mptable_setup ) ;
static unsigned long __initdata mpc_new_phys ;
static unsigned long mpc_new_length __initdata = 4096 ;
/* alloc_mptable or alloc_mptable=4k */
static int __initdata alloc_mptable ;
static int __init parse_alloc_mptable_opt ( char * p )
{
enable_update_mptable = 1 ;
2009-05-16 00:05:16 +04:00
# ifdef CONFIG_PCI
pci_routeirq = 1 ;
# endif
2008-06-02 00:17:38 +04:00
alloc_mptable = 1 ;
if ( ! p )
return 0 ;
mpc_new_length = memparse ( p , & p ) ;
return 0 ;
}
early_param ( " alloc_mptable " , parse_alloc_mptable_opt ) ;
void __init early_reserve_e820_mpc_new ( void )
{
2011-07-12 13:15:58 +04:00
if ( enable_update_mptable & & alloc_mptable )
mpc_new_phys = early_reserve_e820 ( mpc_new_length , 4 ) ;
2008-06-02 00:17:38 +04:00
}
static int __init update_mp_table ( void )
{
char str [ 16 ] ;
char oem [ 10 ] ;
2009-01-08 13:12:46 +03:00
struct mpf_intel * mpf ;
2009-01-03 13:16:57 +03:00
struct mpc_table * mpc , * mpc_new ;
2008-06-02 00:17:38 +04:00
if ( ! enable_update_mptable )
return 0 ;
mpf = mpf_found ;
if ( ! mpf )
return 0 ;
/*
* Now see if we need to go further .
*/
2009-01-08 13:13:26 +03:00
if ( mpf - > feature1 ! = 0 )
2008-06-02 00:17:38 +04:00
return 0 ;
2009-01-08 13:13:26 +03:00
if ( ! mpf - > physptr )
2008-06-02 00:17:38 +04:00
return 0 ;
2009-01-08 13:13:26 +03:00
mpc = phys_to_virt ( mpf - > physptr ) ;
2008-06-02 00:17:38 +04:00
if ( ! smp_check_mpc ( mpc , oem , str ) )
return 0 ;
2009-02-11 21:08:25 +03:00
printk ( KERN_INFO " mpf: %llx \n " , ( u64 ) virt_to_phys ( mpf ) ) ;
2009-01-08 13:13:26 +03:00
printk ( KERN_INFO " physptr: %x \n " , mpf - > physptr ) ;
2008-06-02 00:17:38 +04:00
2009-01-04 19:52:56 +03:00
if ( mpc_new_phys & & mpc - > length > mpc_new_length ) {
2008-06-02 00:17:38 +04:00
mpc_new_phys = 0 ;
printk ( KERN_INFO " mpc_new_length is %ld, please use alloc_mptable=8k \n " ,
mpc_new_length ) ;
}
if ( ! mpc_new_phys ) {
unsigned char old , new ;
2011-03-17 22:24:16 +03:00
/* check if we can change the position */
2009-01-04 19:52:56 +03:00
mpc - > checksum = 0 ;
old = mpf_checksum ( ( unsigned char * ) mpc , mpc - > length ) ;
mpc - > checksum = 0xff ;
new = mpf_checksum ( ( unsigned char * ) mpc , mpc - > length ) ;
2008-06-02 00:17:38 +04:00
if ( old = = new ) {
printk ( KERN_INFO " mpc is readonly, please try alloc_mptable instead \n " ) ;
return 0 ;
}
2011-03-17 22:24:16 +03:00
printk ( KERN_INFO " use in-position replacing \n " ) ;
2008-06-02 00:17:38 +04:00
} else {
2009-01-08 13:13:26 +03:00
mpf - > physptr = mpc_new_phys ;
2008-06-02 00:17:38 +04:00
mpc_new = phys_to_virt ( mpc_new_phys ) ;
2009-01-04 19:52:56 +03:00
memcpy ( mpc_new , mpc , mpc - > length ) ;
2008-06-02 00:17:38 +04:00
mpc = mpc_new ;
/* check if we can modify that */
2009-01-08 13:13:26 +03:00
if ( mpc_new_phys - mpf - > physptr ) {
2009-01-08 13:12:46 +03:00
struct mpf_intel * mpf_new ;
2008-06-02 00:17:38 +04:00
/* steal 16 bytes from [0, 1k) */
printk ( KERN_INFO " mpf new: %x \n " , 0x400 - 16 ) ;
mpf_new = phys_to_virt ( 0x400 - 16 ) ;
memcpy ( mpf_new , mpf , 16 ) ;
mpf = mpf_new ;
2009-01-08 13:13:26 +03:00
mpf - > physptr = mpc_new_phys ;
2008-06-02 00:17:38 +04:00
}
2009-01-08 13:13:26 +03:00
mpf - > checksum = 0 ;
mpf - > checksum - = mpf_checksum ( ( unsigned char * ) mpf , 16 ) ;
printk ( KERN_INFO " physptr new: %x \n " , mpf - > physptr ) ;
2008-06-02 00:17:38 +04:00
}
/*
* only replace the one with mp_INT and
* MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW ,
* already in mp_irqs , stored by . . . and mp_config_acpi_gsi ,
* may need pci = routeirq for all coverage
*/
replace_intsrc_all ( mpc , mpc_new_phys , mpc_new_length ) ;
return 0 ;
}
late_initcall ( update_mp_table ) ;