2008-03-28 14:12:16 -05:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* SGI UV APIC functions ( note : not an Intel compatible APIC )
*
2008-05-28 09:51:18 -05:00
* Copyright ( C ) 2007 - 2008 Silicon Graphics , Inc . All rights reserved .
2008-03-28 14:12:16 -05:00
*/
2008-07-01 14:45:38 -05:00
# include <linux/kernel.h>
2008-03-28 14:12:16 -05:00
# include <linux/threads.h>
2008-10-24 15:24:29 -07:00
# include <linux/cpu.h>
2008-03-28 14:12:16 -05:00
# include <linux/cpumask.h>
# include <linux/string.h>
# include <linux/ctype.h>
# include <linux/init.h>
# include <linux/sched.h>
# include <linux/module.h>
2008-07-10 11:16:48 -07:00
# include <linux/hardirq.h>
2008-10-24 15:24:29 -07:00
# include <linux/timer.h>
2008-11-10 16:16:31 -06:00
# include <linux/proc_fs.h>
2008-10-24 15:24:29 -07:00
# include <asm/current.h>
2008-03-28 14:12:16 -05:00
# include <asm/smp.h>
2009-02-17 13:58:15 +01:00
# include <asm/apic.h>
2009-02-16 23:02:14 -08:00
# include <asm/ipi.h>
2008-07-01 14:45:38 -05:00
# include <asm/pgtable.h>
2009-01-21 17:26:06 +09:00
# include <asm/uv/uv.h>
2008-03-28 14:12:16 -05:00
# include <asm/uv/uv_mmrs.h>
# include <asm/uv/uv_hub.h>
2008-07-09 15:27:19 -05:00
# include <asm/uv/bios.h>
2008-03-28 14:12:16 -05:00
2008-07-22 13:20:22 -07:00
DEFINE_PER_CPU ( int , x2apic_extra_bits ) ;
2008-07-21 22:08:21 -07:00
static enum uv_system_type uv_system_type ;
2008-10-12 11:44:10 +02:00
static int uv_acpi_madt_oem_check ( char * oem_id , char * oem_table_id )
2008-07-21 22:08:21 -07:00
{
if ( ! strcmp ( oem_id , " SGI " ) ) {
if ( ! strcmp ( oem_table_id , " UVL " ) )
uv_system_type = UV_LEGACY_APIC ;
else if ( ! strcmp ( oem_table_id , " UVX " ) )
uv_system_type = UV_X2APIC ;
else if ( ! strcmp ( oem_table_id , " UVH " ) ) {
uv_system_type = UV_NON_UNIQUE_APIC ;
return 1 ;
}
}
return 0 ;
}
enum uv_system_type get_uv_system_type ( void )
{
return uv_system_type ;
}
int is_uv_system ( void )
{
return uv_system_type ! = UV_NONE ;
}
2008-08-11 11:19:20 +02:00
EXPORT_SYMBOL_GPL ( is_uv_system ) ;
2008-07-21 22:08:21 -07:00
2008-03-28 14:12:16 -05:00
DEFINE_PER_CPU ( struct uv_hub_info_s , __uv_hub_info ) ;
EXPORT_PER_CPU_SYMBOL_GPL ( __uv_hub_info ) ;
struct uv_blade_info * uv_blade_info ;
EXPORT_SYMBOL_GPL ( uv_blade_info ) ;
short * uv_node_to_blade ;
EXPORT_SYMBOL_GPL ( uv_node_to_blade ) ;
short * uv_cpu_to_blade ;
EXPORT_SYMBOL_GPL ( uv_cpu_to_blade ) ;
short uv_possible_blades ;
EXPORT_SYMBOL_GPL ( uv_possible_blades ) ;
2008-07-09 15:27:19 -05:00
unsigned long sn_rtc_cycles_per_second ;
EXPORT_SYMBOL ( sn_rtc_cycles_per_second ) ;
2008-03-28 14:12:16 -05:00
/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */
2008-12-16 17:33:59 -08:00
static const struct cpumask * uv_target_cpus ( void )
2008-03-28 14:12:16 -05:00
{
2008-12-16 17:33:59 -08:00
return cpumask_of ( 0 ) ;
2008-03-28 14:12:16 -05:00
}
2008-12-16 17:33:59 -08:00
static void uv_vector_allocation_domain ( int cpu , struct cpumask * retmask )
2008-03-28 14:12:16 -05:00
{
2008-12-16 17:33:59 -08:00
cpumask_clear ( retmask ) ;
cpumask_set_cpu ( cpu , retmask ) ;
2008-03-28 14:12:16 -05:00
}
2009-02-25 20:50:49 -08:00
static int uv_wakeup_secondary ( int phys_apicid , unsigned long start_rip )
2008-03-28 14:12:16 -05:00
{
unsigned long val ;
2008-05-28 09:51:18 -05:00
int pnode ;
2008-03-28 14:12:16 -05:00
2008-05-28 09:51:18 -05:00
pnode = uv_apicid_to_pnode ( phys_apicid ) ;
2008-03-28 14:12:16 -05:00
val = ( 1UL < < UVH_IPI_INT_SEND_SHFT ) |
( phys_apicid < < UVH_IPI_INT_APIC_ID_SHFT ) |
2009-02-25 20:50:49 -08:00
( ( start_rip < < UVH_IPI_INT_VECTOR_SHFT ) > > 12 ) |
2008-04-16 11:45:15 -05:00
APIC_DM_INIT ;
2008-05-28 09:51:18 -05:00
uv_write_global_mmr64 ( pnode , UVH_IPI_INT , val ) ;
2008-04-16 11:45:15 -05:00
mdelay ( 10 ) ;
val = ( 1UL < < UVH_IPI_INT_SEND_SHFT ) |
( phys_apicid < < UVH_IPI_INT_APIC_ID_SHFT ) |
2009-02-25 20:50:49 -08:00
( ( start_rip < < UVH_IPI_INT_VECTOR_SHFT ) > > 12 ) |
2008-04-16 11:45:15 -05:00
APIC_DM_STARTUP ;
2008-05-28 09:51:18 -05:00
uv_write_global_mmr64 ( pnode , UVH_IPI_INT , val ) ;
2009-02-25 20:50:49 -08:00
atomic_set ( & init_deasserted , 1 ) ;
2008-03-28 14:12:16 -05:00
return 0 ;
}
static void uv_send_IPI_one ( int cpu , int vector )
{
2009-02-13 08:40:55 -06:00
unsigned long val , apicid ;
2008-05-28 09:51:18 -05:00
int pnode ;
2008-03-28 14:12:16 -05:00
2008-09-29 08:45:29 -05:00
apicid = per_cpu ( x86_cpu_to_apicid , cpu ) ;
2008-05-28 09:51:18 -05:00
pnode = uv_apicid_to_pnode ( apicid ) ;
2009-01-28 15:42:24 +01:00
2009-02-13 08:40:55 -06:00
val = ( 1UL < < UVH_IPI_INT_SEND_SHFT ) |
( apicid < < UVH_IPI_INT_APIC_ID_SHFT ) |
( vector < < UVH_IPI_INT_VECTOR_SHFT ) ;
2009-01-28 15:42:24 +01:00
2008-05-28 09:51:18 -05:00
uv_write_global_mmr64 ( pnode , UVH_IPI_INT , val ) ;
2008-03-28 14:12:16 -05:00
}
2008-12-16 17:33:59 -08:00
static void uv_send_IPI_mask ( const struct cpumask * mask , int vector )
2008-03-28 14:12:16 -05:00
{
unsigned int cpu ;
2008-12-16 17:33:59 -08:00
for_each_cpu ( cpu , mask )
2008-12-16 17:33:52 -08:00
uv_send_IPI_one ( cpu , vector ) ;
}
2008-12-16 17:33:59 -08:00
static void uv_send_IPI_mask_allbutself ( const struct cpumask * mask , int vector )
2008-12-16 17:33:52 -08:00
{
unsigned int this_cpu = smp_processor_id ( ) ;
2009-01-28 15:42:24 +01:00
unsigned int cpu ;
2008-12-16 17:33:52 -08:00
2009-01-28 15:42:24 +01:00
for_each_cpu ( cpu , mask ) {
2008-12-16 17:33:52 -08:00
if ( cpu ! = this_cpu )
2008-03-28 14:12:16 -05:00
uv_send_IPI_one ( cpu , vector ) ;
2009-01-28 15:42:24 +01:00
}
2008-03-28 14:12:16 -05:00
}
static void uv_send_IPI_allbutself ( int vector )
{
2008-12-16 17:33:52 -08:00
unsigned int this_cpu = smp_processor_id ( ) ;
2009-01-28 15:42:24 +01:00
unsigned int cpu ;
2008-03-28 14:12:16 -05:00
2009-01-28 15:42:24 +01:00
for_each_online_cpu ( cpu ) {
2008-12-16 17:33:52 -08:00
if ( cpu ! = this_cpu )
uv_send_IPI_one ( cpu , vector ) ;
2009-01-28 15:42:24 +01:00
}
2008-03-28 14:12:16 -05:00
}
static void uv_send_IPI_all ( int vector )
{
2008-12-16 17:33:59 -08:00
uv_send_IPI_mask ( cpu_online_mask , vector ) ;
2008-03-28 14:12:16 -05:00
}
static int uv_apic_id_registered ( void )
{
return 1 ;
}
2008-07-11 13:11:55 -07:00
static void uv_init_apic_ldr ( void )
2008-07-10 11:16:55 -07:00
{
}
2008-12-16 17:33:59 -08:00
static unsigned int uv_cpu_mask_to_apicid ( const struct cpumask * cpumask )
2008-03-28 14:12:16 -05:00
{
/*
* We ' re using fixed IRQ delivery , can only return one phys APIC ID .
* May as well be the first .
*/
2009-01-28 15:20:18 +01:00
int cpu = cpumask_first ( cpumask ) ;
2008-07-18 18:11:29 -07:00
if ( ( unsigned ) cpu < nr_cpu_ids )
2008-03-28 14:12:16 -05:00
return per_cpu ( x86_cpu_to_apicid , cpu ) ;
else
return BAD_APICID ;
}
2009-01-28 15:20:18 +01:00
static unsigned int
uv_cpu_mask_to_apicid_and ( const struct cpumask * cpumask ,
const struct cpumask * andmask )
2008-12-16 17:33:54 -08: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 15:20:18 +01:00
for_each_cpu_and ( cpu , cpumask , andmask ) {
2008-12-17 15:21:39 -08:00
if ( cpumask_test_cpu ( cpu , cpu_online_mask ) )
break ;
2009-01-28 15:20:18 +01:00
}
2008-12-16 17:33:55 -08:00
if ( cpu < nr_cpu_ids )
return per_cpu ( x86_cpu_to_apicid , cpu ) ;
2009-01-28 15:20:18 +01:00
2008-12-16 17:33:54 -08:00
return BAD_APICID ;
}
2009-01-28 14:08:38 +01:00
static unsigned int x2apic_get_apic_id ( unsigned long x )
2008-07-10 11:16:48 -07:00
{
unsigned int id ;
WARN_ON ( preemptible ( ) & & num_online_cpus ( ) > 1 ) ;
2008-07-12 01:01:20 -07:00
id = x | __get_cpu_var ( x2apic_extra_bits ) ;
2008-07-10 11:16:48 -07:00
return id ;
}
2008-07-21 22:08:21 -07:00
static unsigned long set_apic_id ( unsigned int id )
2008-07-12 01:01:20 -07:00
{
unsigned long x ;
/* maskout x2apic_extra_bits ? */
x = id ;
return x ;
}
static unsigned int uv_read_apic_id ( void )
{
2009-01-28 14:08:38 +01:00
return x2apic_get_apic_id ( apic_read ( APIC_ID ) ) ;
2008-07-12 01:01:20 -07:00
}
2009-01-28 13:31:22 +01:00
static int uv_phys_pkg_id ( int initial_apicid , int index_msb )
2008-03-28 14:12:16 -05:00
{
2008-07-10 11:16:48 -07:00
return uv_read_apic_id ( ) > > index_msb ;
2008-03-28 14:12:16 -05:00
}
static void uv_send_IPI_self ( int vector )
{
apic_write ( APIC_SELF_IPI , vector ) ;
}
2009-02-17 16:28:46 +01:00
struct apic apic_x2apic_uv_x = {
2009-01-28 02:37:01 +01:00
. name = " UV large system " ,
. probe = NULL ,
. acpi_madt_oem_check = uv_acpi_madt_oem_check ,
. apic_id_registered = uv_apic_id_registered ,
2009-01-28 04:02:31 +01:00
. irq_delivery_mode = dest_Fixed ,
2009-01-28 05:13:04 +01:00
. irq_dest_mode = 1 , /* logical */
2009-01-28 02:37:01 +01:00
. target_cpus = uv_target_cpus ,
2009-01-28 05:08:44 +01:00
. disable_esr = 0 ,
2009-01-28 05:29:25 +01:00
. dest_logical = APIC_DEST_LOGICAL ,
2009-01-28 02:37:01 +01:00
. check_apicid_used = NULL ,
. check_apicid_present = NULL ,
. vector_allocation_domain = uv_vector_allocation_domain ,
. init_apic_ldr = uv_init_apic_ldr ,
. ioapic_phys_id_map = NULL ,
. setup_apic_routing = NULL ,
. multi_timer_check = NULL ,
. apicid_to_node = NULL ,
. cpu_to_logical_apicid = NULL ,
2009-01-28 06:50:47 +01:00
. cpu_present_to_apicid = default_cpu_present_to_apicid ,
2009-01-28 02:37:01 +01:00
. apicid_to_cpu_present = NULL ,
. setup_portio_remap = NULL ,
2009-01-28 12:43:18 +01:00
. check_phys_apicid_present = default_check_phys_apicid_present ,
2009-01-28 02:37:01 +01:00
. enable_apic_mode = NULL ,
2009-01-28 13:31:22 +01:00
. phys_pkg_id = uv_phys_pkg_id ,
2009-01-28 02:37:01 +01:00
. mps_oem_check = NULL ,
2009-01-28 14:08:38 +01:00
. get_apic_id = x2apic_get_apic_id ,
2009-01-28 02:37:01 +01:00
. set_apic_id = set_apic_id ,
. apic_id_mask = 0xFFFFFFFFu ,
. cpu_mask_to_apicid = uv_cpu_mask_to_apicid ,
. cpu_mask_to_apicid_and = uv_cpu_mask_to_apicid_and ,
. send_IPI_mask = uv_send_IPI_mask ,
. send_IPI_mask_allbutself = uv_send_IPI_mask_allbutself ,
. send_IPI_allbutself = uv_send_IPI_allbutself ,
. send_IPI_all = uv_send_IPI_all ,
. send_IPI_self = uv_send_IPI_self ,
2009-02-26 13:51:40 +01:00
. wakeup_secondary_cpu = uv_wakeup_secondary ,
2009-01-28 16:15:16 +01:00
. trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW ,
. trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH ,
2009-01-28 02:37:01 +01:00
. wait_for_init_deassert = NULL ,
. smp_callin_clear_local_apic = NULL ,
. inquire_remote_apic = NULL ,
2009-02-16 23:02:14 -08:00
. read = native_apic_msr_read ,
. write = native_apic_msr_write ,
. icr_read = native_x2apic_icr_read ,
. icr_write = native_x2apic_icr_write ,
. wait_icr_idle = native_x2apic_wait_icr_idle ,
. safe_wait_icr_idle = native_safe_x2apic_wait_icr_idle ,
2008-03-28 14:12:16 -05:00
} ;
2008-05-28 09:51:18 -05:00
static __cpuinit void set_x2apic_extra_bits ( int pnode )
2008-03-28 14:12:16 -05:00
{
2008-05-28 09:51:18 -05:00
__get_cpu_var ( x2apic_extra_bits ) = ( pnode < < 6 ) ;
2008-03-28 14:12:16 -05:00
}
/*
* Called on boot cpu .
*/
2008-05-28 09:51:18 -05:00
static __init int boot_pnode_to_blade ( int pnode )
{
int blade ;
for ( blade = 0 ; blade < uv_num_possible_blades ( ) ; blade + + )
if ( pnode = = uv_blade_info [ blade ] . pnode )
return blade ;
BUG ( ) ;
}
struct redir_addr {
unsigned long redirect ;
unsigned long alias ;
} ;
# define DEST_SHIFT UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT
static __initdata struct redir_addr redir_addrs [ ] = {
{ UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR , UVH_SI_ALIAS0_OVERLAY_CONFIG } ,
{ UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR , UVH_SI_ALIAS1_OVERLAY_CONFIG } ,
{ UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR , UVH_SI_ALIAS2_OVERLAY_CONFIG } ,
} ;
static __init void get_lowmem_redirect ( unsigned long * base , unsigned long * size )
{
union uvh_si_alias0_overlay_config_u alias ;
union uvh_rh_gam_alias210_redirect_config_2_mmr_u redirect ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( redir_addrs ) ; i + + ) {
alias . v = uv_read_local_mmr ( redir_addrs [ i ] . alias ) ;
if ( alias . s . base = = 0 ) {
* size = ( 1UL < < alias . s . m_alias ) ;
redirect . v = uv_read_local_mmr ( redir_addrs [ i ] . redirect ) ;
* base = ( unsigned long ) redirect . s . dest_base < < DEST_SHIFT ;
return ;
}
}
BUG ( ) ;
}
2008-07-01 14:45:38 -05:00
static __init void map_low_mmrs ( void )
{
init_extra_mapping_uc ( UV_GLOBAL_MMR32_BASE , UV_GLOBAL_MMR32_SIZE ) ;
init_extra_mapping_uc ( UV_LOCAL_MMR_BASE , UV_LOCAL_MMR_SIZE ) ;
}
enum map_type { map_wb , map_uc } ;
2008-09-25 07:52:10 -05:00
static __init void map_high ( char * id , unsigned long base , int shift ,
int max_pnode , enum map_type map_type )
2008-07-01 14:45:38 -05:00
{
unsigned long bytes , paddr ;
paddr = base < < shift ;
2008-09-25 07:52:10 -05:00
bytes = ( 1UL < < shift ) * ( max_pnode + 1 ) ;
2008-07-01 14:45:38 -05:00
printk ( KERN_INFO " UV: Map %s_HI 0x%lx - 0x%lx \n " , id , paddr ,
paddr + bytes ) ;
if ( map_type = = map_uc )
init_extra_mapping_uc ( paddr , bytes ) ;
else
init_extra_mapping_wb ( paddr , bytes ) ;
}
static __init void map_gru_high ( int max_pnode )
{
union uvh_rh_gam_gru_overlay_config_mmr_u gru ;
int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT ;
gru . v = uv_read_local_mmr ( UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR ) ;
if ( gru . s . enable )
2008-09-25 07:52:10 -05:00
map_high ( " GRU " , gru . s . base , shift , max_pnode , map_wb ) ;
2008-07-01 14:45:38 -05:00
}
static __init void map_config_high ( int max_pnode )
{
union uvh_rh_gam_cfg_overlay_config_mmr_u cfg ;
int shift = UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR_BASE_SHFT ;
cfg . v = uv_read_local_mmr ( UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR ) ;
if ( cfg . s . enable )
2008-09-25 07:52:10 -05:00
map_high ( " CONFIG " , cfg . s . base , shift , max_pnode , map_uc ) ;
2008-07-01 14:45:38 -05:00
}
static __init void map_mmr_high ( int max_pnode )
{
union uvh_rh_gam_mmr_overlay_config_mmr_u mmr ;
int shift = UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT ;
mmr . v = uv_read_local_mmr ( UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR ) ;
if ( mmr . s . enable )
2008-09-25 07:52:10 -05:00
map_high ( " MMR " , mmr . s . base , shift , max_pnode , map_uc ) ;
2008-07-01 14:45:38 -05:00
}
static __init void map_mmioh_high ( int max_pnode )
{
union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh ;
int shift = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT ;
mmioh . v = uv_read_local_mmr ( UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR ) ;
if ( mmioh . s . enable )
2008-09-25 07:52:10 -05:00
map_high ( " MMIOH " , mmioh . s . base , shift , max_pnode , map_uc ) ;
2008-07-01 14:45:38 -05:00
}
2008-07-09 15:27:19 -05:00
static __init void uv_rtc_init ( void )
{
2008-10-03 11:59:33 -05:00
long status ;
u64 ticks_per_sec ;
2008-07-09 15:27:19 -05:00
2008-10-03 11:59:33 -05:00
status = uv_bios_freq_base ( BIOS_FREQ_BASE_REALTIME_CLOCK ,
& ticks_per_sec ) ;
if ( status ! = BIOS_STATUS_SUCCESS | | ticks_per_sec < 100000 ) {
2008-07-09 15:27:19 -05:00
printk ( KERN_WARNING
" unable to determine platform RTC clock frequency, "
" guessing. \n " ) ;
/* BIOS gives wrong value for clock freq. so guess */
sn_rtc_cycles_per_second = 1000000000000UL / 30000UL ;
} else
sn_rtc_cycles_per_second = ticks_per_sec ;
}
2008-10-24 15:24:29 -07:00
/*
* percpu heartbeat timer
*/
static void uv_heartbeat ( unsigned long ignored )
{
struct timer_list * timer = & uv_hub_info - > scir . timer ;
unsigned char bits = uv_hub_info - > scir . state ;
/* flip heartbeat bit */
bits ^ = SCIR_CPU_HEARTBEAT ;
2008-10-27 07:51:20 -07:00
/* is this cpu idle? */
if ( idle_cpu ( raw_smp_processor_id ( ) ) )
2008-10-24 15:24:29 -07:00
bits & = ~ SCIR_CPU_ACTIVITY ;
else
bits | = SCIR_CPU_ACTIVITY ;
/* update system controller interface reg */
uv_set_scir_bits ( bits ) ;
/* enable next timer period */
mod_timer ( timer , jiffies + SCIR_CPU_HB_INTERVAL ) ;
}
static void __cpuinit uv_heartbeat_enable ( int cpu )
{
if ( ! uv_cpu_hub_info ( cpu ) - > scir . enabled ) {
struct timer_list * timer = & uv_cpu_hub_info ( cpu ) - > scir . timer ;
uv_set_cpu_scir_bits ( cpu , SCIR_CPU_HEARTBEAT | SCIR_CPU_ACTIVITY ) ;
setup_timer ( timer , uv_heartbeat , cpu ) ;
timer - > expires = jiffies + SCIR_CPU_HB_INTERVAL ;
add_timer_on ( timer , cpu ) ;
uv_cpu_hub_info ( cpu ) - > scir . enabled = 1 ;
}
/* check boot cpu */
if ( ! uv_cpu_hub_info ( 0 ) - > scir . enabled )
uv_heartbeat_enable ( 0 ) ;
}
2008-11-19 16:05:14 -07:00
# ifdef CONFIG_HOTPLUG_CPU
2008-10-24 15:24:29 -07:00
static void __cpuinit uv_heartbeat_disable ( int cpu )
{
if ( uv_cpu_hub_info ( cpu ) - > scir . enabled ) {
uv_cpu_hub_info ( cpu ) - > scir . enabled = 0 ;
del_timer ( & uv_cpu_hub_info ( cpu ) - > scir . timer ) ;
}
uv_set_cpu_scir_bits ( cpu , 0xff ) ;
}
/*
* cpu hotplug notifier
*/
static __cpuinit int uv_scir_cpu_notify ( struct notifier_block * self ,
unsigned long action , void * hcpu )
{
long cpu = ( long ) hcpu ;
switch ( action ) {
case CPU_ONLINE :
uv_heartbeat_enable ( cpu ) ;
break ;
case CPU_DOWN_PREPARE :
uv_heartbeat_disable ( cpu ) ;
break ;
default :
break ;
}
return NOTIFY_OK ;
}
static __init void uv_scir_register_cpu_notifier ( void )
{
hotcpu_notifier ( uv_scir_cpu_notify , 0 ) ;
}
# else /* !CONFIG_HOTPLUG_CPU */
static __init void uv_scir_register_cpu_notifier ( void )
{
}
static __init int uv_init_heartbeat ( void )
{
int cpu ;
if ( is_uv_system ( ) )
for_each_online_cpu ( cpu )
uv_heartbeat_enable ( cpu ) ;
return 0 ;
}
late_initcall ( uv_init_heartbeat ) ;
# endif /* !CONFIG_HOTPLUG_CPU */
2008-09-23 08:42:05 -05:00
/*
* Called on each cpu to initialize the per_cpu UV data area .
* ZZZ hotplug not supported yet
*/
void __cpuinit uv_cpu_init ( void )
{
/* CPU 0 initilization will be done via uv_system_init. */
if ( ! uv_blade_info )
return ;
uv_blade_info [ uv_numa_blade_id ( ) ] . nr_online_cpus + + ;
if ( get_uv_system_type ( ) = = UV_NON_UNIQUE_APIC )
set_x2apic_extra_bits ( uv_hub_info - > pnode ) ;
}
2008-08-21 20:49:05 +02:00
void __init uv_system_init ( void )
2008-03-28 14:12:16 -05:00
{
union uvh_si_addr_map_config_u m_n_config ;
2008-05-28 09:51:18 -05:00
union uvh_node_id_u node_id ;
unsigned long gnode_upper , lowmem_redir_base , lowmem_redir_size ;
int bytes , nid , cpu , lcpu , pnode , blade , i , j , m_val , n_val ;
2008-07-01 14:45:38 -05:00
int max_pnode = 0 ;
2008-05-28 09:51:18 -05:00
unsigned long mmr_base , present ;
2008-03-28 14:12:16 -05:00
2008-07-01 14:45:38 -05:00
map_low_mmrs ( ) ;
2008-03-28 14:12:16 -05:00
m_n_config . v = uv_read_local_mmr ( UVH_SI_ADDR_MAP_CONFIG ) ;
2008-05-28 09:51:18 -05:00
m_val = m_n_config . s . m_skt ;
n_val = m_n_config . s . n_skt ;
2008-03-28 14:12:16 -05:00
mmr_base =
uv_read_local_mmr ( UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR ) &
~ UV_MMR_ENABLE ;
printk ( KERN_DEBUG " UV: global MMR base 0x%lx \n " , mmr_base ) ;
2008-05-28 09:51:18 -05:00
for ( i = 0 ; i < UVH_NODE_PRESENT_TABLE_DEPTH ; i + + )
uv_possible_blades + =
hweight64 ( uv_read_local_mmr ( UVH_NODE_PRESENT_TABLE + i * 8 ) ) ;
2008-03-28 14:12:16 -05:00
printk ( KERN_DEBUG " UV: Found %d blades \n " , uv_num_possible_blades ( ) ) ;
bytes = sizeof ( struct uv_blade_info ) * uv_num_possible_blades ( ) ;
2008-10-23 17:54:05 -05:00
uv_blade_info = kmalloc ( bytes , GFP_KERNEL ) ;
2008-03-28 14:12:16 -05:00
2008-05-28 09:51:18 -05:00
get_lowmem_redirect ( & lowmem_redir_base , & lowmem_redir_size ) ;
2008-03-28 14:12:16 -05:00
bytes = sizeof ( uv_node_to_blade [ 0 ] ) * num_possible_nodes ( ) ;
2008-10-23 17:54:05 -05:00
uv_node_to_blade = kmalloc ( bytes , GFP_KERNEL ) ;
2008-03-28 14:12:16 -05:00
memset ( uv_node_to_blade , 255 , bytes ) ;
bytes = sizeof ( uv_cpu_to_blade [ 0 ] ) * num_possible_cpus ( ) ;
2008-10-23 17:54:05 -05:00
uv_cpu_to_blade = kmalloc ( bytes , GFP_KERNEL ) ;
2008-03-28 14:12:16 -05:00
memset ( uv_cpu_to_blade , 255 , bytes ) ;
2008-05-28 09:51:18 -05:00
blade = 0 ;
for ( i = 0 ; i < UVH_NODE_PRESENT_TABLE_DEPTH ; i + + ) {
present = uv_read_local_mmr ( UVH_NODE_PRESENT_TABLE + i * 8 ) ;
for ( j = 0 ; j < 64 ; j + + ) {
if ( ! test_bit ( j , & present ) )
continue ;
uv_blade_info [ blade ] . pnode = ( i * 64 + j ) ;
uv_blade_info [ blade ] . nr_possible_cpus = 0 ;
2008-03-28 14:12:16 -05:00
uv_blade_info [ blade ] . nr_online_cpus = 0 ;
2008-05-28 09:51:18 -05:00
blade + + ;
2008-03-28 14:12:16 -05:00
}
2008-05-28 09:51:18 -05:00
}
2008-03-28 14:12:16 -05:00
2008-05-28 09:51:18 -05:00
node_id . v = uv_read_local_mmr ( UVH_NODE_ID ) ;
gnode_upper = ( ( ( unsigned long ) node_id . s . node_id ) &
~ ( ( 1 < < n_val ) - 1 ) ) < < m_val ;
2008-10-03 11:59:15 -05:00
uv_bios_init ( ) ;
2008-10-03 11:59:33 -05:00
uv_bios_get_sn_info ( 0 , & uv_type , & sn_partition_id ,
2008-10-21 14:09:51 -05:00
& sn_coherency_id , & sn_region_size ) ;
2008-07-09 15:27:19 -05:00
uv_rtc_init ( ) ;
2008-05-28 09:51:18 -05:00
for_each_present_cpu ( cpu ) {
nid = cpu_to_node ( cpu ) ;
pnode = uv_apicid_to_pnode ( per_cpu ( x86_cpu_to_apicid , cpu ) ) ;
blade = boot_pnode_to_blade ( pnode ) ;
lcpu = uv_blade_info [ blade ] . nr_possible_cpus ;
uv_blade_info [ blade ] . nr_possible_cpus + + ;
uv_cpu_hub_info ( cpu ) - > lowmem_remap_base = lowmem_redir_base ;
2008-12-12 14:50:40 -06:00
uv_cpu_hub_info ( cpu ) - > lowmem_remap_top = lowmem_redir_size ;
2008-05-28 09:51:18 -05:00
uv_cpu_hub_info ( cpu ) - > m_val = m_val ;
uv_cpu_hub_info ( cpu ) - > n_val = m_val ;
2008-03-28 14:12:16 -05:00
uv_cpu_hub_info ( cpu ) - > numa_blade_id = blade ;
uv_cpu_hub_info ( cpu ) - > blade_processor_id = lcpu ;
2008-05-28 09:51:18 -05:00
uv_cpu_hub_info ( cpu ) - > pnode = pnode ;
uv_cpu_hub_info ( cpu ) - > pnode_mask = ( 1 < < n_val ) - 1 ;
uv_cpu_hub_info ( cpu ) - > gpa_mask = ( 1 < < ( m_val + n_val ) ) - 1 ;
uv_cpu_hub_info ( cpu ) - > gnode_upper = gnode_upper ;
2008-03-28 14:12:16 -05:00
uv_cpu_hub_info ( cpu ) - > global_mmr_base = mmr_base ;
2008-10-21 14:09:51 -05:00
uv_cpu_hub_info ( cpu ) - > coherency_domain_number = sn_coherency_id ;
2008-10-24 15:24:29 -07:00
uv_cpu_hub_info ( cpu ) - > scir . offset = SCIR_LOCAL_MMR_BASE + lcpu ;
2008-03-28 14:12:16 -05:00
uv_node_to_blade [ nid ] = blade ;
uv_cpu_to_blade [ cpu ] = blade ;
2008-07-01 14:45:38 -05:00
max_pnode = max ( pnode , max_pnode ) ;
2008-03-28 14:12:16 -05:00
2008-07-01 14:45:38 -05:00
printk ( KERN_DEBUG " UV: cpu %d, apicid 0x%x, pnode %d, nid %d, "
2008-05-28 09:51:18 -05:00
" lcpu %d, blade %d \n " ,
cpu , per_cpu ( x86_cpu_to_apicid , cpu ) , pnode , nid ,
lcpu , blade ) ;
2008-03-28 14:12:16 -05:00
}
2008-07-01 14:45:38 -05:00
map_gru_high ( max_pnode ) ;
map_mmr_high ( max_pnode ) ;
map_config_high ( max_pnode ) ;
map_mmioh_high ( max_pnode ) ;
2008-03-28 14:12:16 -05:00
2008-09-23 08:42:05 -05:00
uv_cpu_init ( ) ;
2008-10-24 15:24:29 -07:00
uv_scir_register_cpu_notifier ( ) ;
2008-11-10 16:16:31 -06:00
proc_mkdir ( " sgi_uv " , NULL ) ;
2008-03-28 14:12:16 -05:00
}