1#ifndef __ASM_IPI_H 2#define __ASM_IPI_H 3 4/* 5 * Copyright 2004 James Cleverdon, IBM. 6 * Subject to the GNU Public License, v.2 7 * 8 * Generic APIC InterProcessor Interrupt code. 9 * 10 * Moved to include file by James Cleverdon from 11 * arch/x86-64/kernel/smp.c 12 * 13 * Copyrights from kernel/smp.c: 14 * 15 * (c) 1995 Alan Cox, Building #3 <alan@redhat.com> 16 * (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com> 17 * (c) 2002,2003 Andi Kleen, SuSE Labs. 18 * Subject to the GNU Public License, v.2 19 */ 20 21#include <asm/hw_irq.h> 22#include <asm/apic.h> 23 24/* 25 * the following functions deal with sending IPIs between CPUs. 26 * 27 * We use 'broadcast', CPU->CPU IPIs and self-IPIs too. 28 */ 29 30static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector, unsigned int dest) 31{ 32 unsigned int icr = shortcut | dest; 33 34 switch (vector) { 35 default: 36 icr |= APIC_DM_FIXED | vector; 37 break; 38 case NMI_VECTOR: 39 icr |= APIC_DM_NMI; 40 break; 41 } 42 return icr; 43} 44 45static inline int __prepare_ICR2 (unsigned int mask) 46{ 47 return SET_APIC_DEST_FIELD(mask); 48} 49 50static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest) 51{ 52 unsigned int cfg; 53 54 /* 55 * Wait for idle. 56 */ 57 apic_wait_icr_idle(); 58 59 /* 60 * No need to touch the target chip field 61 */ 62 cfg = __prepare_ICR(shortcut, vector, dest); 63 64 /* 65 * Send the IPI. The write to APIC_ICR fires this off. 66 */ 67 apic_write(APIC_ICR, cfg); 68} 69 70/* 71 * This is used to send an IPI with no shorthand notation (the destination is 72 * specified in bits 56 to 63 of the ICR). 73 */ 74static inline void __send_IPI_dest_field(unsigned int mask, int vector, unsigned int dest) 75{ 76 unsigned long cfg; 77 78 /* 79 * Wait for idle. 80 */ 81 if (unlikely(vector == NMI_VECTOR)) 82 safe_apic_wait_icr_idle(); 83 else 84 apic_wait_icr_idle(); 85 86 /* 87 * prepare target chip field 88 */ 89 cfg = __prepare_ICR2(mask); 90 apic_write(APIC_ICR2, cfg); 91 92 /* 93 * program the ICR 94 */ 95 cfg = __prepare_ICR(0, vector, dest); 96 97 /* 98 * Send the IPI. The write to APIC_ICR fires this off. 99 */ 100 apic_write(APIC_ICR, cfg); 101} 102 103static inline void send_IPI_mask_sequence(cpumask_t mask, int vector) 104{ 105 unsigned long flags; 106 unsigned long query_cpu; 107 108 /* 109 * Hack. The clustered APIC addressing mode doesn't allow us to send 110 * to an arbitrary mask, so I do a unicast to each CPU instead. 111 * - mbligh 112 */ 113 local_irq_save(flags); 114 for_each_cpu_mask(query_cpu, mask) { 115 __send_IPI_dest_field(x86_cpu_to_apicid[query_cpu], 116 vector, APIC_DEST_PHYSICAL); 117 } 118 local_irq_restore(flags); 119} 120 121#endif /* __ASM_IPI_H */ 122