2005-04-16 15:20:36 -07:00
/*
* Written by : Patricia Gaughen , IBM Corporation
*
* Copyright ( C ) 2002 , IBM Corp .
2009-02-17 17:53:54 +01:00
* Copyright ( C ) 2009 , Red Hat , Inc . , Ingo Molnar
2005-04-16 15:20:36 -07:00
*
2009-02-01 11:25:57 +01:00
* All rights reserved .
2005-04-16 15:20:36 -07:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for more
* details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
* Send feedback to < gone @ us . ibm . com >
*/
2009-02-01 11:25:57 +01:00
# include <linux/nodemask.h>
2009-02-17 17:53:54 +01:00
# include <linux/topology.h>
2005-04-16 15:20:36 -07:00
# include <linux/bootmem.h>
2009-02-17 15:50:25 +01:00
# include <linux/threads.h>
# include <linux/cpumask.h>
# include <linux/kernel.h>
2005-04-16 15:20:36 -07:00
# include <linux/mmzone.h>
# include <linux/module.h>
2009-02-17 15:50:25 +01:00
# include <linux/string.h>
# include <linux/init.h>
# include <linux/numa.h>
# include <linux/smp.h>
2009-02-17 17:53:54 +01:00
# include <linux/io.h>
2009-02-01 11:25:57 +01:00
# include <linux/mm.h>
2005-07-28 21:16:18 -07:00
# include <asm/processor.h>
2009-02-17 15:50:25 +01:00
# include <asm/fixmap.h>
# include <asm/mpspec.h>
2009-02-01 11:25:57 +01:00
# include <asm/numaq.h>
2008-07-19 18:01:16 -07:00
# include <asm/setup.h>
2009-02-17 15:50:25 +01:00
# include <asm/apic.h>
2009-02-01 11:25:57 +01:00
# include <asm/e820.h>
2009-02-17 15:50:25 +01:00
# include <asm/ipi.h>
2005-04-16 15:20:36 -07:00
2009-02-17 15:50:25 +01:00
# define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT))
2009-02-17 17:53:54 +01:00
int found_numaq ;
/*
* Have to match translation table entries to main table entries by counter
* hence the mpc_record variable . . . . can ' t see a less disgusting way of
* doing this . . . .
*/
struct mpc_trans {
unsigned char mpc_type ;
unsigned char trans_len ;
unsigned char trans_type ;
unsigned char trans_quad ;
unsigned char trans_global ;
unsigned char trans_local ;
unsigned short trans_reserved ;
} ;
static int mpc_record ;
2009-03-02 11:34:29 +01:00
static struct mpc_trans * translation_table [ MAX_MPC_ENTRY ] ;
2009-02-17 17:53:54 +01:00
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 ] ;
2009-02-17 15:50:25 +01:00
static inline void numaq_register_node ( int node , struct sys_cfg_data * scd )
{
struct eachquadmem * eq = scd - > eq + node ;
node_set_online ( node ) ;
/* Convert to pages */
node_start_pfn [ node ] =
MB_TO_PAGES ( eq - > hi_shrd_mem_start - eq - > priv_mem_size ) ;
node_end_pfn [ node ] =
MB_TO_PAGES ( eq - > hi_shrd_mem_start + eq - > hi_shrd_mem_size ) ;
e820_register_active_regions ( node , node_start_pfn [ node ] ,
node_end_pfn [ node ] ) ;
memory_present ( node , node_start_pfn [ node ] , node_end_pfn [ node ] ) ;
node_remap_size [ node ] = node_memmap_size_bytes ( node ,
node_start_pfn [ node ] ,
node_end_pfn [ node ] ) ;
}
2005-04-16 15:20:36 -07:00
/*
* Function : smp_dump_qct ( )
*
* Description : gets memory layout from the quad config table . This
* function also updates node_online_map with the nodes ( quads ) present .
*/
static void __init smp_dump_qct ( void )
{
2009-02-17 15:50:25 +01:00
struct sys_cfg_data * scd ;
2005-04-16 15:20:36 -07:00
int node ;
2009-02-17 15:50:25 +01:00
scd = ( void * ) __va ( SYS_CFG_DATA_PRIV_ADDR ) ;
2005-04-16 15:20:36 -07:00
nodes_clear ( node_online_map ) ;
for_each_node ( node ) {
2009-02-17 15:50:25 +01:00
if ( scd - > quads_present31_0 & ( 1 < < node ) )
numaq_register_node ( node , scd ) ;
2005-04-16 15:20:36 -07:00
}
}
2008-08-20 18:18:26 +02:00
void __cpuinit numaq_tsc_disable ( void )
2008-07-19 18:01:16 -07:00
{
if ( ! found_numaq )
return ;
if ( num_online_nodes ( ) > 1 ) {
printk ( KERN_DEBUG " NUMAQ: disabling TSC \n " ) ;
setup_clear_cpu_cap ( X86_FEATURE_TSC ) ;
}
}
2009-08-19 15:37:03 +02:00
static void __init numaq_tsc_init ( void )
2008-07-19 18:02:26 -07:00
{
numaq_tsc_disable ( ) ;
}
2008-07-19 18:01:16 -07:00
static inline int generate_logical_apicid ( int quad , int phys_apicid )
{
return ( quad < < 4 ) + ( phys_apicid ? phys_apicid < < 1 : 1 ) ;
}
/* x86_quirks member */
2009-01-03 15:48:52 +05:30
static int mpc_apic_id ( struct mpc_cpu * m )
2008-07-19 18:01:16 -07:00
{
int quad = translation_table [ mpc_record ] - > trans_quad ;
2009-01-04 21:58:25 +05:30
int logical_apicid = generate_logical_apicid ( quad , m - > apicid ) ;
2008-07-19 18:01:16 -07:00
2009-02-17 15:50:25 +01:00
printk ( KERN_DEBUG
" Processor #%d %u:%u APIC version %d (quad %d, apic %d) \n " ,
m - > apicid , ( m - > cpufeature & CPU_FAMILY_MASK ) > > 8 ,
( m - > cpufeature & CPU_MODEL_MASK ) > > 4 ,
m - > apicver , quad , logical_apicid ) ;
2008-07-19 18:01:16 -07:00
return logical_apicid ;
}
/* x86_quirks member */
2009-01-03 15:47:32 +05:30
static void mpc_oem_bus_info ( struct mpc_bus * m , char * name )
2008-07-19 18:01:16 -07:00
{
int quad = translation_table [ mpc_record ] - > trans_quad ;
int local = translation_table [ mpc_record ] - > trans_local ;
2009-01-04 21:59:26 +05:30
mp_bus_id_to_node [ m - > busid ] = quad ;
mp_bus_id_to_local [ m - > busid ] = local ;
2009-02-17 15:50:25 +01:00
printk ( KERN_INFO " Bus #%d is %s (node %d) \n " , m - > busid , name , quad ) ;
2008-07-19 18:01:16 -07:00
}
/* x86_quirks member */
2009-01-03 15:47:32 +05:30
static void mpc_oem_pci_bus ( struct mpc_bus * m )
2008-07-19 18:01:16 -07:00
{
int quad = translation_table [ mpc_record ] - > trans_quad ;
int local = translation_table [ mpc_record ] - > trans_local ;
2009-01-04 21:59:26 +05:30
quad_local_to_mp_bus_id [ quad ] [ local ] = m - > busid ;
2008-07-19 18:01:16 -07:00
}
2009-08-20 12:05:01 +02:00
/*
* Called from mpparse code .
* mode = 0 : prescan
* mode = 1 : one mpc entry scanned
*/
static void numaq_mpc_record ( unsigned int mode )
{
if ( ! mode )
mpc_record = 0 ;
else
mpc_record + + ;
}
2009-02-17 15:50:25 +01:00
static void __init MP_translation_info ( struct mpc_trans * m )
2008-07-19 18:01:16 -07:00
{
printk ( KERN_INFO
2009-02-17 17:53:54 +01:00
" Translation: record %d, type %d, quad %d, global %d, local %d \n " ,
2008-07-19 18:01:16 -07:00
mpc_record , m - > trans_type , m - > trans_quad , m - > trans_global ,
m - > trans_local ) ;
if ( mpc_record > = MAX_MPC_ENTRY )
printk ( KERN_ERR " MAX_MPC_ENTRY exceeded! \n " ) ;
else
2009-02-17 15:50:25 +01:00
translation_table [ mpc_record ] = m ; /* stash this for later */
2008-07-19 18:01:16 -07:00
if ( m - > trans_quad < MAX_NUMNODES & & ! node_online ( m - > trans_quad ) )
node_set_online ( m - > trans_quad ) ;
}
static int __init mpf_checksum ( unsigned char * mp , int len )
{
int sum = 0 ;
while ( len - - )
sum + = * mp + + ;
return sum & 0xFF ;
}
/*
* Read / parse the MPC oem tables
*/
2009-08-20 12:18:32 +02:00
static void __init smp_read_mpc_oem ( struct mpc_table * mpc )
2008-07-19 18:01:16 -07:00
{
2009-08-20 12:18:32 +02:00
struct mpc_oemtable * oemtable = ( void * ) ( long ) mpc - > oemptr ;
2008-07-19 18:01:16 -07:00
int count = sizeof ( * oemtable ) ; /* the header size */
unsigned char * oemptr = ( ( unsigned char * ) oemtable ) + count ;
mpc_record = 0 ;
2009-02-17 15:50:25 +01:00
printk ( KERN_INFO
" Found an OEM MPC table at %8p - parsing it ... \n " , oemtable ) ;
2009-01-04 22:00:46 +05:30
if ( memcmp ( oemtable - > signature , MPC_OEM_SIGNATURE , 4 ) ) {
2008-07-19 18:01:16 -07:00
printk ( KERN_WARNING
" SMP mpc oemtable: bad signature [%c%c%c%c]! \n " ,
2009-01-04 22:00:46 +05:30
oemtable - > signature [ 0 ] , oemtable - > signature [ 1 ] ,
oemtable - > signature [ 2 ] , oemtable - > signature [ 3 ] ) ;
2008-07-19 18:01:16 -07:00
return ;
}
2009-02-17 15:50:25 +01:00
2009-01-04 22:00:46 +05:30
if ( mpf_checksum ( ( unsigned char * ) oemtable , oemtable - > length ) ) {
2008-07-19 18:01:16 -07:00
printk ( KERN_WARNING " SMP oem mptable: checksum error! \n " ) ;
return ;
}
2009-02-17 15:50:25 +01:00
2009-01-04 22:00:46 +05:30
while ( count < oemtable - > length ) {
2008-07-19 18:01:16 -07:00
switch ( * oemptr ) {
case MP_TRANSLATION :
{
2009-02-17 15:50:25 +01:00
struct mpc_trans * m = ( void * ) oemptr ;
2008-07-19 18:01:16 -07:00
MP_translation_info ( m ) ;
oemptr + = sizeof ( * m ) ;
count + = sizeof ( * m ) ;
+ + mpc_record ;
break ;
}
default :
2009-02-17 15:50:25 +01:00
printk ( KERN_WARNING
" Unrecognised OEM table entry type! - %d \n " ,
( int ) * oemptr ) ;
return ;
2008-07-19 18:01:16 -07:00
}
}
}
2008-06-03 10:25:54 -07:00
static __init void early_check_numaq ( void )
{
/*
* get boot - time SMP configuration :
*/
if ( smp_found_config )
early_get_smp_config ( ) ;
2008-07-19 18:01:16 -07:00
2009-08-20 12:05:01 +02:00
if ( found_numaq ) {
x86_init . mpparse . mpc_record = numaq_mpc_record ;
2009-08-20 09:27:29 +02:00
x86_init . mpparse . setup_ioapic_ids = x86_init_noop ;
2009-08-20 10:41:58 +02:00
x86_init . mpparse . mpc_apic_id = mpc_apic_id ;
2009-08-20 12:18:32 +02:00
x86_init . mpparse . smp_read_mpc_oem = smp_read_mpc_oem ;
2009-08-20 12:45:33 +02:00
x86_init . mpparse . mpc_oem_pci_bus = mpc_oem_pci_bus ;
2009-08-20 12:34:47 +02:00
x86_init . mpparse . mpc_oem_bus_info = mpc_oem_bus_info ;
2009-08-19 15:37:03 +02:00
x86_init . timers . tsc_pre_init = numaq_tsc_init ;
2009-08-20 12:05:01 +02:00
}
2008-06-03 10:25:54 -07:00
}
2005-04-16 15:20:36 -07:00
int __init get_memcfg_numaq ( void )
{
2008-06-03 10:25:54 -07:00
early_check_numaq ( ) ;
if ( ! found_numaq )
return 0 ;
2005-04-16 15:20:36 -07:00
smp_dump_qct ( ) ;
2009-02-17 15:50:25 +01:00
2005-04-16 15:20:36 -07:00
return 1 ;
}
2009-01-28 19:01:05 +01:00
# define NUMAQ_APIC_DFR_VALUE (APIC_DFR_CLUSTER)
static inline unsigned int numaq_get_apic_id ( unsigned long x )
{
return ( x > > 24 ) & 0x0F ;
}
static inline void numaq_send_IPI_mask ( const struct cpumask * mask , int vector )
{
2009-01-29 19:31:49 -08:00
default_send_IPI_mask_sequence_logical ( mask , vector ) ;
2009-01-28 19:01:05 +01:00
}
static inline void numaq_send_IPI_allbutself ( int vector )
{
2009-01-29 19:31:49 -08:00
default_send_IPI_mask_allbutself_logical ( cpu_online_mask , vector ) ;
2009-01-28 19:01:05 +01:00
}
static inline void numaq_send_IPI_all ( int vector )
{
numaq_send_IPI_mask ( cpu_online_mask , vector ) ;
}
2009-02-17 15:50:25 +01:00
# define NUMAQ_TRAMPOLINE_PHYS_LOW (0x8)
# define NUMAQ_TRAMPOLINE_PHYS_HIGH (0xa)
2009-01-28 19:01:05 +01:00
/*
* Because we use NMIs rather than the INIT - STARTUP sequence to
* bootstrap the CPUs , the APIC may be in a weird state . Kick it :
*/
static inline void numaq_smp_callin_clear_local_apic ( void )
{
clear_local_APIC ( ) ;
}
2009-03-13 14:49:57 +10:30
static inline const struct cpumask * numaq_target_cpus ( void )
2009-01-28 19:01:05 +01:00
{
2009-03-13 14:49:47 +10:30
return cpu_all_mask ;
2009-01-28 19:01:05 +01:00
}
2009-11-10 01:06:59 +03:00
static unsigned long numaq_check_apicid_used ( physid_mask_t * map , int apicid )
2009-01-28 19:01:05 +01:00
{
2009-11-10 01:06:59 +03:00
return physid_isset ( apicid , * map ) ;
2009-01-28 19:01:05 +01:00
}
static inline unsigned long numaq_check_apicid_present ( int bit )
{
return physid_isset ( bit , phys_cpu_present_map ) ;
}
static inline int numaq_apic_id_registered ( void )
{
return 1 ;
}
static inline void numaq_init_apic_ldr ( void )
{
/* Already done in NUMA-Q firmware */
}
static inline void numaq_setup_apic_routing ( void )
{
2009-02-17 17:53:54 +01:00
printk ( KERN_INFO
" Enabling APIC mode: NUMA-Q. Using %d I/O APICs \n " ,
nr_ioapics ) ;
2009-01-28 19:01:05 +01:00
}
/*
* Skip adding the timer int on secondary nodes , which causes
* a small but painful rift in the time - space continuum .
*/
static inline int numaq_multi_timer_check ( int apic , int irq )
{
return apic ! = 0 & & irq = = 0 ;
}
2009-11-10 01:06:59 +03:00
static inline void numaq_ioapic_phys_id_map ( physid_mask_t * phys_map , physid_mask_t * retmap )
2009-01-28 19:01:05 +01:00
{
/* We don't have a good way to do this yet - hack */
2009-11-10 01:06:59 +03:00
return physids_promote ( 0xFUL , retmap ) ;
2009-01-28 19:01:05 +01:00
}
static inline int numaq_cpu_to_logical_apicid ( int cpu )
{
if ( cpu > = nr_cpu_ids )
return BAD_APICID ;
2009-02-17 14:45:30 +01:00
return cpu_2_logical_apicid [ cpu ] ;
2009-01-28 19:01:05 +01:00
}
/*
* Supporting over 60 cpus on NUMA - Q requires a locality - dependent
* cpu to APIC ID relation to properly interact with the intelligent
* mode of the cluster controller .
*/
static inline int numaq_cpu_present_to_apicid ( int mps_cpu )
{
if ( mps_cpu < 60 )
return ( ( mps_cpu > > 2 ) < < 4 ) | ( 1 < < ( mps_cpu & 0x3 ) ) ;
else
return BAD_APICID ;
}
2009-02-17 15:50:25 +01:00
static inline int numaq_apicid_to_node ( int logical_apicid )
2009-01-28 19:01:05 +01:00
{
return logical_apicid > > 4 ;
}
2009-11-10 01:06:59 +03:00
static void numaq_apicid_to_cpu_present ( int logical_apicid , physid_mask_t * retmap )
2009-01-28 19:01:05 +01:00
{
int node = numaq_apicid_to_node ( logical_apicid ) ;
int cpu = __ffs ( logical_apicid & 0xf ) ;
2009-11-10 01:06:59 +03:00
physid_set_mask_of_physid ( cpu + 4 * node , retmap ) ;
2009-01-28 19:01:05 +01:00
}
2009-02-01 11:25:57 +01:00
/* Where the IO area was mapped on multiquad, always 0 otherwise */
void * xquad_portio ;
2009-01-28 19:01:05 +01:00
2009-08-31 15:18:40 +02:00
static inline int numaq_check_phys_apicid_present ( int phys_apicid )
2009-01-28 19:01:05 +01:00
{
return 1 ;
}
/*
* We use physical apicids here , not logical , so just return the default
* physical broadcast to stop people from breaking us
*/
2009-03-13 14:49:57 +10:30
static unsigned int numaq_cpu_mask_to_apicid ( const struct cpumask * cpumask )
2009-01-28 19:01:05 +01:00
{
return 0x0F ;
}
static inline unsigned int
numaq_cpu_mask_to_apicid_and ( const struct cpumask * cpumask ,
const struct cpumask * andmask )
{
return 0x0F ;
}
/* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */
static inline int numaq_phys_pkg_id ( int cpuid_apic , int index_msb )
{
return cpuid_apic > > index_msb ;
}
2009-02-17 15:50:25 +01:00
static int
2009-02-17 17:53:54 +01:00
numaq_mps_oem_check ( struct mpc_table * mpc , char * oem , char * productid )
2009-01-28 19:01:05 +01:00
{
2009-02-17 17:53:54 +01:00
if ( strncmp ( oem , " IBM NUMA " , 8 ) )
printk ( KERN_ERR " Warning! Not a NUMA-Q system! \n " ) ;
else
found_numaq = 1 ;
2009-01-28 19:01:05 +01:00
return found_numaq ;
}
static int probe_numaq ( void )
{
/* already know from get_memcfg_numaq() */
return found_numaq ;
}
2009-03-13 14:49:57 +10:30
static void numaq_vector_allocation_domain ( int cpu , struct cpumask * retmask )
2009-01-28 19:01:05 +01:00
{
/* Careful. Some cpus do not strictly honor the set of cpus
* specified in the interrupt destination when using lowest
* priority interrupt delivery mode .
*
* In particular there was a hyperthreading cpu observed to
* deliver interrupts to the wrong hyperthread when only one
* hyperthread was specified in the interrupt desitination .
*/
2009-03-13 14:49:56 +10:30
cpumask_clear ( retmask ) ;
cpumask_bits ( retmask ) [ 0 ] = APIC_ALL_CPUS ;
2009-01-28 19:01:05 +01:00
}
static void numaq_setup_portio_remap ( void )
{
int num_quads = num_online_nodes ( ) ;
if ( num_quads < = 1 )
2009-02-01 11:25:57 +01:00
return ;
2009-01-28 19:01:05 +01:00
2009-02-17 17:53:54 +01:00
printk ( KERN_INFO
" Remapping cross-quad port I/O for %d quads \n " , num_quads ) ;
2009-01-28 19:01:05 +01:00
xquad_portio = ioremap ( XQUAD_PORTIO_BASE , num_quads * XQUAD_PORTIO_QUAD ) ;
2009-02-17 17:53:54 +01:00
printk ( KERN_INFO
" xquad_portio vaddr 0x%08lx, len %08lx \n " ,
2009-01-28 19:01:05 +01:00
( u_long ) xquad_portio , ( u_long ) num_quads * XQUAD_PORTIO_QUAD ) ;
}
2009-07-12 17:07:19 +06:00
/* Use __refdata to keep false positive warning calm. */
struct apic __refdata apic_numaq = {
2009-01-28 19:01:05 +01:00
. name = " NUMAQ " ,
. probe = probe_numaq ,
. acpi_madt_oem_check = NULL ,
. apic_id_registered = numaq_apic_id_registered ,
. irq_delivery_mode = dest_LowestPrio ,
/* physical delivery on LOCAL quad: */
. irq_dest_mode = 0 ,
. target_cpus = numaq_target_cpus ,
. disable_esr = 1 ,
. dest_logical = APIC_DEST_LOGICAL ,
. check_apicid_used = numaq_check_apicid_used ,
. check_apicid_present = numaq_check_apicid_present ,
. vector_allocation_domain = numaq_vector_allocation_domain ,
. init_apic_ldr = numaq_init_apic_ldr ,
. ioapic_phys_id_map = numaq_ioapic_phys_id_map ,
. setup_apic_routing = numaq_setup_apic_routing ,
. multi_timer_check = numaq_multi_timer_check ,
. apicid_to_node = numaq_apicid_to_node ,
. cpu_to_logical_apicid = numaq_cpu_to_logical_apicid ,
. cpu_present_to_apicid = numaq_cpu_present_to_apicid ,
. apicid_to_cpu_present = numaq_apicid_to_cpu_present ,
. setup_portio_remap = numaq_setup_portio_remap ,
. check_phys_apicid_present = numaq_check_phys_apicid_present ,
. enable_apic_mode = NULL ,
. phys_pkg_id = numaq_phys_pkg_id ,
2009-02-17 17:53:54 +01:00
. mps_oem_check = numaq_mps_oem_check ,
2009-01-28 19:01:05 +01:00
. get_apic_id = numaq_get_apic_id ,
. set_apic_id = NULL ,
. apic_id_mask = 0x0F < < 24 ,
. cpu_mask_to_apicid = numaq_cpu_mask_to_apicid ,
. cpu_mask_to_apicid_and = numaq_cpu_mask_to_apicid_and ,
. send_IPI_mask = numaq_send_IPI_mask ,
. send_IPI_mask_allbutself = NULL ,
. send_IPI_allbutself = numaq_send_IPI_allbutself ,
. send_IPI_all = numaq_send_IPI_all ,
2009-01-30 23:42:18 +01:00
. send_IPI_self = default_send_IPI_self ,
2009-01-28 19:01:05 +01:00
2009-02-26 13:51:40 +01:00
. wakeup_secondary_cpu = wakeup_secondary_cpu_via_nmi ,
2009-01-28 19:01:05 +01:00
. trampoline_phys_low = NUMAQ_TRAMPOLINE_PHYS_LOW ,
. trampoline_phys_high = NUMAQ_TRAMPOLINE_PHYS_HIGH ,
/* We don't do anything here because we use NMI's to boot instead */
. wait_for_init_deassert = NULL ,
. smp_callin_clear_local_apic = numaq_smp_callin_clear_local_apic ,
. inquire_remote_apic = NULL ,
2009-02-16 23:02:14 -08:00
. read = native_apic_mem_read ,
. write = native_apic_mem_write ,
. icr_read = native_apic_icr_read ,
. icr_write = native_apic_icr_write ,
. wait_icr_idle = native_apic_wait_icr_idle ,
. safe_wait_icr_idle = native_safe_apic_wait_icr_idle ,
2009-01-28 19:01:05 +01:00
} ;