2008-10-22 22:26:29 -07:00
# ifndef _ASM_X86_IPI_H
# define _ASM_X86_IPI_H
2005-04-16 15:20:36 -07:00
2009-01-28 19:14:52 +01:00
# ifdef CONFIG_X86_LOCAL_APIC
2005-04-16 15:20:36 -07:00
/*
* Copyright 2004 James Cleverdon , IBM .
* Subject to the GNU Public License , v .2
*
* Generic APIC InterProcessor Interrupt code .
*
* Moved to include file by James Cleverdon from
* arch / x86 - 64 / kernel / smp . c
*
* Copyrights from kernel / smp . c :
*
* ( c ) 1995 Alan Cox , Building # 3 < alan @ redhat . com >
* ( c ) 1998 - 99 , 2000 Ingo Molnar < mingo @ redhat . com >
* ( c ) 2002 , 2003 Andi Kleen , SuSE Labs .
* Subject to the GNU Public License , v .2
*/
# include <asm/hw_irq.h>
2007-05-02 19:27:04 +02:00
# include <asm/apic.h>
2008-05-14 08:15:04 -07:00
# include <asm/smp.h>
2005-04-16 15:20:36 -07:00
/*
* the following functions deal with sending IPIs between CPUs .
*
* We use ' broadcast ' , CPU - > CPU IPIs and self - IPIs too .
*/
2008-03-23 01:02:27 -07:00
static inline unsigned int __prepare_ICR ( unsigned int shortcut , int vector ,
unsigned int dest )
2005-04-16 15:20:36 -07:00
{
2005-09-12 18:49:24 +02:00
unsigned int icr = shortcut | dest ;
switch ( vector ) {
default :
icr | = APIC_DM_FIXED | vector ;
break ;
case NMI_VECTOR :
icr | = APIC_DM_NMI ;
break ;
}
2005-04-16 15:20:36 -07:00
return icr ;
}
2008-03-23 01:02:27 -07:00
static inline int __prepare_ICR2 ( unsigned int mask )
2005-04-16 15:20:36 -07:00
{
return SET_APIC_DEST_FIELD ( mask ) ;
}
2008-07-10 11:16:49 -07:00
static inline void __xapic_wait_icr_idle ( void )
{
while ( native_apic_mem_read ( APIC_ICR ) & APIC_ICR_BUSY )
cpu_relax ( ) ;
}
2009-01-28 15:42:24 +01:00
static inline void
2009-01-28 19:14:52 +01:00
__default_send_IPI_shortcut ( unsigned int shortcut , int vector , unsigned int dest )
2005-04-16 15:20:36 -07:00
{
/*
* Subtle . In the case of the ' never do double writes ' workaround
* we have to lock out interrupts to be safe . As we don ' t care
* of the value read we use an atomic rmw access to avoid costly
* cli / sti . Otherwise we use an even cheaper single atomic write
* to the APIC .
*/
unsigned int cfg ;
/*
* Wait for idle .
*/
2008-07-10 11:16:49 -07:00
__xapic_wait_icr_idle ( ) ;
2005-04-16 15:20:36 -07:00
/*
* No need to touch the target chip field
*/
cfg = __prepare_ICR ( shortcut , vector , dest ) ;
/*
* Send the IPI . The write to APIC_ICR fires this off .
*/
2008-07-10 11:16:49 -07:00
native_apic_mem_write ( APIC_ICR , cfg ) ;
2005-04-16 15:20:36 -07:00
}
2007-05-02 19:27:18 +02:00
/*
* This is used to send an IPI with no shorthand notation ( the destination is
* specified in bits 56 to 63 of the ICR ) .
*/
2009-01-28 15:42:24 +01:00
static inline void
__default_send_IPI_dest_field ( unsigned int mask , int vector , unsigned int dest )
2007-05-02 19:27:18 +02:00
{
unsigned long cfg ;
/*
* Wait for idle .
*/
2007-05-02 19:27:18 +02:00
if ( unlikely ( vector = = NMI_VECTOR ) )
safe_apic_wait_icr_idle ( ) ;
else
2008-07-10 11:16:49 -07:00
__xapic_wait_icr_idle ( ) ;
2007-05-02 19:27:18 +02:00
/*
* prepare target chip field
*/
cfg = __prepare_ICR2 ( mask ) ;
2008-07-10 11:16:49 -07:00
native_apic_mem_write ( APIC_ICR2 , cfg ) ;
2007-05-02 19:27:18 +02:00
/*
* program the ICR
*/
cfg = __prepare_ICR ( 0 , vector , dest ) ;
/*
* Send the IPI . The write to APIC_ICR fires this off .
*/
2008-07-10 11:16:49 -07:00
native_apic_mem_write ( APIC_ICR , cfg ) ;
2007-05-02 19:27:18 +02:00
}
2005-04-16 15:20:36 -07:00
2009-01-30 17:29:27 -08:00
extern void default_send_IPI_mask_sequence_phys ( const struct cpumask * mask ,
int vector ) ;
extern void default_send_IPI_mask_allbutself_phys ( const struct cpumask * mask ,
int vector ) ;
extern void default_send_IPI_mask_sequence_logical ( const struct cpumask * mask ,
int vector ) ;
extern void default_send_IPI_mask_allbutself_logical ( const struct cpumask * mask ,
int vector ) ;
2009-01-28 19:14:52 +01:00
/* Avoid include hell */
# define NMI_VECTOR 0x02
extern int no_broadcast ;
static inline void __default_local_send_IPI_allbutself ( int vector )
{
if ( no_broadcast | | vector = = NMI_VECTOR )
apic - > send_IPI_mask_allbutself ( cpu_online_mask , vector ) ;
else
__default_send_IPI_shortcut ( APIC_DEST_ALLBUT , vector , apic - > dest_logical ) ;
}
static inline void __default_local_send_IPI_all ( int vector )
{
if ( no_broadcast | | vector = = NMI_VECTOR )
apic - > send_IPI_mask ( cpu_online_mask , vector ) ;
else
__default_send_IPI_shortcut ( APIC_DEST_ALLINC , vector , apic - > dest_logical ) ;
}
# ifdef CONFIG_X86_32
2009-01-30 17:29:27 -08:00
extern void default_send_IPI_mask_logical ( const struct cpumask * mask ,
int vector ) ;
extern void default_send_IPI_allbutself ( int vector ) ;
extern void default_send_IPI_all ( int vector ) ;
extern void default_send_IPI_self ( int vector ) ;
2009-01-28 19:14:52 +01:00
# endif
# endif
2008-10-22 22:26:29 -07:00
# endif /* _ASM_X86_IPI_H */