2005-04-17 02:20:36 +04:00
/*
* Copyright 2004 James Cleverdon , IBM .
* Subject to the GNU Public License , v .2
*
2005-07-29 08:15:42 +04:00
* Flat APIC subarch code .
2005-04-17 02:20:36 +04:00
*
* Hacked for x86 - 64 by James Cleverdon from i386 architecture code by
* Martin Bligh , Andi Kleen , James Bottomley , John Stultz , and
* James Cleverdon .
*/
2007-05-02 21:27:21 +04:00
# include <linux/errno.h>
2005-04-17 02:20:36 +04:00
# include <linux/threads.h>
# include <linux/cpumask.h>
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/ctype.h>
# include <linux/init.h>
2008-07-10 22:16:48 +04:00
# include <linux/hardirq.h>
2011-05-23 21:43:00 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <asm/smp.h>
2009-02-17 15:58:15 +03:00
# include <asm/apic.h>
2009-02-17 10:02:14 +03:00
# include <asm/ipi.h>
2005-04-17 02:20:36 +04:00
2008-07-22 09:08:21 +04:00
# ifdef CONFIG_ACPI
# include <acpi/acpi_bus.h>
# endif
2011-05-21 04:51:20 +04:00
static struct apic apic_physflat ;
static struct apic apic_flat ;
struct apic __read_mostly * apic = & apic_flat ;
EXPORT_SYMBOL_GPL ( apic ) ;
2008-10-12 13:44:08 +04:00
static int flat_acpi_madt_oem_check ( char * oem_id , char * oem_table_id )
2008-07-22 09:08:21 +04:00
{
return 1 ;
}
2008-12-17 04:33:59 +03:00
static const struct cpumask * flat_target_cpus ( void )
2005-04-17 02:20:36 +04:00
{
2008-12-17 04:33:59 +03:00
return cpu_online_mask ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 04:33:59 +03:00
static void flat_vector_allocation_domain ( int cpu , struct cpumask * retmask )
2006-10-08 17:47:55 +04: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 .
*/
2008-12-17 04:33:59 +03:00
cpumask_clear ( retmask ) ;
cpumask_bits ( retmask ) [ 0 ] = APIC_ALL_CPUS ;
2006-10-08 17:47:55 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Set up the logical destination ID .
*
* Intel recommends to set DFR , LDR and TPR before enabling
* an APIC . See e . g . " AP-388 82489DX User's Manual " ( Intel
* document number 292116 ) . So here it goes . . .
*/
2011-12-05 12:20:36 +04:00
void flat_init_apic_ldr ( void )
2005-04-17 02:20:36 +04:00
{
unsigned long val ;
unsigned long num , id ;
num = smp_processor_id ( ) ;
id = 1UL < < num ;
2005-09-12 20:49:23 +04:00
apic_write ( APIC_DFR , APIC_DFR_FLAT ) ;
2005-04-17 02:20:36 +04:00
val = apic_read ( APIC_LDR ) & ~ APIC_LDR_MASK ;
val | = SET_APIC_LOGICAL_ID ( id ) ;
2005-09-12 20:49:23 +04:00
apic_write ( APIC_LDR , val ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 04:33:52 +03:00
static inline void _flat_send_IPI_mask ( unsigned long mask , int vector )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
2006-09-26 12:52:33 +04:00
local_irq_save ( flags ) ;
2009-01-28 17:42:24 +03:00
__default_send_IPI_dest_field ( mask , vector , apic - > dest_logical ) ;
2005-04-17 02:20:36 +04:00
local_irq_restore ( flags ) ;
}
2008-12-17 04:33:59 +03:00
static void flat_send_IPI_mask ( const struct cpumask * cpumask , int vector )
2008-12-17 04:33:52 +03:00
{
2008-12-17 04:33:59 +03:00
unsigned long mask = cpumask_bits ( cpumask ) [ 0 ] ;
2008-12-17 04:33:52 +03:00
_flat_send_IPI_mask ( mask , vector ) ;
}
2009-01-28 17:42:24 +03:00
static void
flat_send_IPI_mask_allbutself ( const struct cpumask * cpumask , int vector )
2008-12-17 04:33:52 +03:00
{
2008-12-17 04:33:59 +03:00
unsigned long mask = cpumask_bits ( cpumask ) [ 0 ] ;
2008-12-17 04:33:52 +03:00
int cpu = smp_processor_id ( ) ;
if ( cpu < BITS_PER_LONG )
clear_bit ( cpu , & mask ) ;
2009-01-28 17:42:24 +03:00
2008-12-17 04:33:52 +03:00
_flat_send_IPI_mask ( mask , vector ) ;
}
2005-06-26 01:55:03 +04:00
static void flat_send_IPI_allbutself ( int vector )
{
2008-12-17 04:33:52 +03:00
int cpu = smp_processor_id ( ) ;
2006-06-26 15:59:56 +04:00
# ifdef CONFIG_HOTPLUG_CPU
int hotplug = 1 ;
2005-09-10 00:01:52 +04:00
# else
2006-06-26 15:59:56 +04:00
int hotplug = 0 ;
# endif
if ( hotplug | | vector = = NMI_VECTOR ) {
2008-12-17 04:33:59 +03:00
if ( ! cpumask_equal ( cpu_online_mask , cpumask_of ( cpu ) ) ) {
unsigned long mask = cpumask_bits ( cpu_online_mask ) [ 0 ] ;
2006-01-12 00:43:09 +03:00
2008-12-17 04:33:52 +03:00
if ( cpu < BITS_PER_LONG )
clear_bit ( cpu , & mask ) ;
2005-09-10 00:01:52 +04:00
2008-12-17 04:33:52 +03:00
_flat_send_IPI_mask ( mask , vector ) ;
}
2006-06-26 15:59:56 +04:00
} else if ( num_online_cpus ( ) > 1 ) {
2009-01-28 17:42:24 +03:00
__default_send_IPI_shortcut ( APIC_DEST_ALLBUT ,
vector , apic - > dest_logical ) ;
2006-06-26 15:59:56 +04:00
}
2005-06-26 01:55:02 +04:00
}
static void flat_send_IPI_all ( int vector )
{
2009-01-28 17:42:24 +03:00
if ( vector = = NMI_VECTOR ) {
2008-12-17 04:33:59 +03:00
flat_send_IPI_mask ( cpu_online_mask , vector ) ;
2009-01-28 17:42:24 +03:00
} else {
__default_send_IPI_shortcut ( APIC_DEST_ALLINC ,
vector , apic - > dest_logical ) ;
}
2005-06-26 01:55:02 +04:00
}
2009-01-28 16:08:38 +03:00
static unsigned int flat_get_apic_id ( unsigned long x )
2008-07-12 12:01:20 +04:00
{
unsigned int id ;
id = ( ( ( x ) > > 24 ) & 0xFFu ) ;
2009-01-28 16:08:38 +03:00
2008-07-12 12:01:20 +04:00
return id ;
}
static unsigned long set_apic_id ( unsigned int id )
{
unsigned long x ;
x = ( ( id & 0xFFu ) < < 24 ) ;
return x ;
}
2008-07-10 22:16:48 +04:00
static unsigned int read_xapic_id ( void )
{
unsigned int id ;
2009-01-28 16:08:38 +03:00
id = flat_get_apic_id ( apic_read ( APIC_ID ) ) ;
2008-07-10 22:16:48 +04:00
return id ;
}
2005-04-17 02:20:36 +04:00
static int flat_apic_id_registered ( void )
{
2008-07-10 22:16:48 +04:00
return physid_isset ( read_xapic_id ( ) , phys_cpu_present_map ) ;
2005-04-17 02:20:36 +04:00
}
2009-01-28 15:31:22 +03:00
static int flat_phys_pkg_id ( int initial_apic_id , int index_msb )
2005-04-17 02:20:36 +04:00
{
2009-05-16 00:05:16 +04:00
return initial_apic_id > > index_msb ;
2005-04-17 02:20:36 +04:00
}
2011-12-22 05:45:15 +04:00
static int flat_probe ( void )
{
return 1 ;
}
2011-05-21 04:51:20 +04:00
static struct apic apic_flat = {
2009-01-28 04:37:01 +03:00
. name = " flat " ,
2011-12-22 05:45:15 +04:00
. probe = flat_probe ,
2009-01-28 04:37:01 +03:00
. acpi_madt_oem_check = flat_acpi_madt_oem_check ,
2012-03-14 11:17:34 +04:00
. apic_id_valid = default_apic_id_valid ,
2009-01-28 04:37:01 +03:00
. apic_id_registered = flat_apic_id_registered ,
2009-01-28 06:02:31 +03:00
. irq_delivery_mode = dest_LowestPrio ,
2009-01-28 07:13:04 +03:00
. irq_dest_mode = 1 , /* logical */
2009-01-28 04:37:01 +03:00
. target_cpus = flat_target_cpus ,
2009-01-28 07:08:44 +03:00
. disable_esr = 0 ,
2009-01-28 07:29:25 +03:00
. dest_logical = APIC_DEST_LOGICAL ,
2009-01-28 04:37:01 +03:00
. check_apicid_used = NULL ,
. check_apicid_present = NULL ,
. vector_allocation_domain = flat_vector_allocation_domain ,
. init_apic_ldr = flat_init_apic_ldr ,
. ioapic_phys_id_map = NULL ,
. setup_apic_routing = NULL ,
. multi_timer_check = NULL ,
2009-01-28 08:50:47 +03:00
. cpu_present_to_apicid = default_cpu_present_to_apicid ,
2009-01-28 04:37:01 +03:00
. apicid_to_cpu_present = NULL ,
. setup_portio_remap = NULL ,
2009-01-28 14:43:18 +03:00
. check_phys_apicid_present = default_check_phys_apicid_present ,
2009-01-28 04:37:01 +03:00
. enable_apic_mode = NULL ,
2009-01-28 15:31:22 +03:00
. phys_pkg_id = flat_phys_pkg_id ,
2009-01-28 04:37:01 +03:00
. mps_oem_check = NULL ,
2009-01-28 16:08:38 +03:00
. get_apic_id = flat_get_apic_id ,
2009-01-28 04:37:01 +03:00
. set_apic_id = set_apic_id ,
. apic_id_mask = 0xFFu < < 24 ,
2009-03-25 00:16:30 +03:00
. cpu_mask_to_apicid = default_cpu_mask_to_apicid ,
. cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and ,
2009-01-28 04:37:01 +03:00
. send_IPI_mask = flat_send_IPI_mask ,
. send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself ,
. send_IPI_allbutself = flat_send_IPI_allbutself ,
. send_IPI_all = flat_send_IPI_all ,
. send_IPI_self = apic_send_IPI_self ,
2009-01-28 18:15:16 +03:00
. trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW ,
. trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH ,
2009-01-28 04:37:01 +03:00
. wait_for_init_deassert = NULL ,
. smp_callin_clear_local_apic = NULL ,
2009-04-08 19:00:01 +04:00
. inquire_remote_apic = default_inquire_remote_apic ,
2009-02-17 10:02:14 +03: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 ,
2005-04-17 02:20:36 +04:00
} ;
2005-07-29 08:15:42 +04:00
/*
2009-11-20 16:20:05 +03:00
* Physflat mode is used when there are more than 8 CPUs on a system .
2005-07-29 08:15:42 +04:00
* We cannot use logical delivery in this case because the mask
* overflows , so use physical mode .
*/
2008-10-12 13:44:09 +04:00
static int physflat_acpi_madt_oem_check ( char * oem_id , char * oem_table_id )
2008-07-22 09:08:21 +04:00
{
# ifdef CONFIG_ACPI
/*
* Quirk : some x86_64 machines can only use physical APIC mode
* regardless of how many processors are present ( x86_64 ES7000
* is an example ) .
*/
2009-05-10 10:47:42 +04:00
if ( acpi_gbl_FADT . header . revision > = FADT2_REVISION_ID & &
2008-09-04 22:57:11 +04:00
( acpi_gbl_FADT . flags & ACPI_FADT_APIC_PHYSICAL ) ) {
printk ( KERN_DEBUG " system APIC only can use physical flat " ) ;
2008-07-22 09:08:21 +04:00
return 1 ;
2008-09-04 22:57:11 +04:00
}
2010-01-18 23:10:48 +03:00
if ( ! strncmp ( oem_id , " IBM " , 3 ) & & ! strncmp ( oem_table_id , " EXA " , 3 ) ) {
printk ( KERN_DEBUG " IBM Summit detected, will use apic physical " ) ;
return 1 ;
}
2008-07-22 09:08:21 +04:00
# endif
return 0 ;
}
2005-07-29 08:15:42 +04:00
2008-12-17 04:33:59 +03:00
static const struct cpumask * physflat_target_cpus ( void )
2005-07-29 08:15:42 +04:00
{
2008-12-17 04:33:59 +03:00
return cpu_online_mask ;
2005-07-29 08:15:42 +04:00
}
2008-12-17 04:33:59 +03:00
static void physflat_vector_allocation_domain ( int cpu , struct cpumask * retmask )
2006-10-08 17:47:55 +04:00
{
2008-12-17 04:33:59 +03:00
cpumask_clear ( retmask ) ;
cpumask_set_cpu ( cpu , retmask ) ;
2006-10-08 17:47:55 +04:00
}
2008-12-17 04:33:59 +03:00
static void physflat_send_IPI_mask ( const struct cpumask * cpumask , int vector )
2005-07-29 08:15:42 +04:00
{
2009-01-30 06:31:49 +03:00
default_send_IPI_mask_sequence_phys ( cpumask , vector ) ;
2005-07-29 08:15:42 +04:00
}
2008-12-17 04:33:59 +03:00
static void physflat_send_IPI_mask_allbutself ( const struct cpumask * cpumask ,
2008-12-17 04:33:52 +03:00
int vector )
2005-07-29 08:15:42 +04:00
{
2009-01-30 06:31:49 +03:00
default_send_IPI_mask_allbutself_phys ( cpumask , vector ) ;
2008-12-17 04:33:52 +03:00
}
2006-01-12 00:43:09 +03:00
2008-12-17 04:33:52 +03:00
static void physflat_send_IPI_allbutself ( int vector )
{
2009-01-30 06:31:49 +03:00
default_send_IPI_mask_allbutself_phys ( cpu_online_mask , vector ) ;
2005-07-29 08:15:42 +04:00
}
static void physflat_send_IPI_all ( int vector )
{
2008-12-17 04:33:59 +03:00
physflat_send_IPI_mask ( cpu_online_mask , vector ) ;
2005-07-29 08:15:42 +04:00
}
2008-12-17 04:33:59 +03:00
static unsigned int physflat_cpu_mask_to_apicid ( const struct cpumask * cpumask )
2005-07-29 08:15:42 +04:00
{
int cpu ;
/*
* We ' re using fixed IRQ delivery , can only return one phys APIC ID .
* May as well be the first .
*/
2008-12-17 04:33:59 +03:00
cpu = cpumask_first ( cpumask ) ;
2008-07-19 05:11:30 +04:00
if ( ( unsigned ) cpu < nr_cpu_ids )
2007-10-19 22:35:03 +04:00
return per_cpu ( x86_cpu_to_apicid , cpu ) ;
2005-07-29 08:15:42 +04:00
else
return BAD_APICID ;
}
2008-12-17 04:33:55 +03:00
static unsigned int
physflat_cpu_mask_to_apicid_and ( const struct cpumask * cpumask ,
const struct cpumask * andmask )
2008-12-17 04:33:54 +03:00
{
int cpu ;
/*
* We ' re using fixed IRQ delivery , can only return one phys APIC ID .
* May as well be the first .
*/
2009-01-28 17:20:18 +03:00
for_each_cpu_and ( cpu , cpumask , andmask ) {
2008-12-18 02:21:39 +03:00
if ( cpumask_test_cpu ( cpu , cpu_online_mask ) )
break ;
2009-01-28 17:20:18 +03:00
}
2009-12-18 05:29:46 +03:00
return per_cpu ( x86_cpu_to_apicid , cpu ) ;
2008-12-17 04:33:54 +03:00
}
2011-05-20 03:45:46 +04:00
static int physflat_probe ( void )
{
if ( apic = = & apic_physflat | | num_possible_cpus ( ) > 8 )
return 1 ;
return 0 ;
}
2011-05-21 04:51:20 +04:00
static struct apic apic_physflat = {
2009-01-28 04:37:01 +03:00
. name = " physical flat " ,
2011-05-20 03:45:46 +04:00
. probe = physflat_probe ,
2009-01-28 04:37:01 +03:00
. acpi_madt_oem_check = physflat_acpi_madt_oem_check ,
2012-03-14 11:17:34 +04:00
. apic_id_valid = default_apic_id_valid ,
2009-01-28 04:37:01 +03:00
. apic_id_registered = flat_apic_id_registered ,
2009-01-28 06:02:31 +03:00
. irq_delivery_mode = dest_Fixed ,
2009-01-28 07:13:04 +03:00
. irq_dest_mode = 0 , /* physical */
2009-01-28 04:37:01 +03:00
. target_cpus = physflat_target_cpus ,
2009-01-28 07:08:44 +03:00
. disable_esr = 0 ,
2009-01-28 07:29:25 +03:00
. dest_logical = 0 ,
2009-01-28 04:37:01 +03:00
. check_apicid_used = NULL ,
. check_apicid_present = NULL ,
. vector_allocation_domain = physflat_vector_allocation_domain ,
/* not needed, but shouldn't hurt: */
. init_apic_ldr = flat_init_apic_ldr ,
. ioapic_phys_id_map = NULL ,
. setup_apic_routing = NULL ,
. multi_timer_check = NULL ,
2009-01-28 08:50:47 +03:00
. cpu_present_to_apicid = default_cpu_present_to_apicid ,
2009-01-28 04:37:01 +03:00
. apicid_to_cpu_present = NULL ,
. setup_portio_remap = NULL ,
2009-01-28 14:43:18 +03:00
. check_phys_apicid_present = default_check_phys_apicid_present ,
2009-01-28 04:37:01 +03:00
. enable_apic_mode = NULL ,
2009-01-28 15:31:22 +03:00
. phys_pkg_id = flat_phys_pkg_id ,
2009-01-28 04:37:01 +03:00
. mps_oem_check = NULL ,
2009-01-28 16:08:38 +03:00
. get_apic_id = flat_get_apic_id ,
2009-01-28 04:37:01 +03:00
. set_apic_id = set_apic_id ,
2009-01-28 16:59:17 +03:00
. apic_id_mask = 0xFFu < < 24 ,
2009-01-28 04:37:01 +03:00
. cpu_mask_to_apicid = physflat_cpu_mask_to_apicid ,
. cpu_mask_to_apicid_and = physflat_cpu_mask_to_apicid_and ,
. send_IPI_mask = physflat_send_IPI_mask ,
. send_IPI_mask_allbutself = physflat_send_IPI_mask_allbutself ,
. send_IPI_allbutself = physflat_send_IPI_allbutself ,
. send_IPI_all = physflat_send_IPI_all ,
. send_IPI_self = apic_send_IPI_self ,
2009-01-28 18:15:16 +03:00
. trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW ,
. trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH ,
2009-01-28 04:37:01 +03:00
. wait_for_init_deassert = NULL ,
. smp_callin_clear_local_apic = NULL ,
2009-04-08 19:00:01 +04:00
. inquire_remote_apic = default_inquire_remote_apic ,
2009-02-17 10:02:14 +03: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 ,
2005-07-29 08:15:42 +04:00
} ;
2011-05-21 04:51:17 +04:00
/*
* We need to check for physflat first , so this order is important .
*/
apic_drivers ( apic_physflat , apic_flat ) ;