ipi.c 3.9 KB
Newer Older
Glauber Costa's avatar
Glauber Costa committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#include <linux/cpumask.h>
#include <linux/interrupt.h>
#include <linux/init.h>

#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/cache.h>
#include <linux/cpu.h>
#include <linux/module.h>

#include <asm/smp.h>
#include <asm/mtrr.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
#include <asm/apic.h>
#include <asm/proto.h>

#ifdef CONFIG_X86_32
#include <mach_apic.h>
23 24
#include <mach_ipi.h>

Glauber Costa's avatar
Glauber Costa committed
25 26 27 28 29 30 31 32
/*
 * the following functions deal with sending IPIs between CPUs.
 *
 * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
 */

static inline int __prepare_ICR(unsigned int shortcut, int vector)
{
33
	unsigned int icr = shortcut | apic->dest_logical;
Glauber Costa's avatar
Glauber Costa committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

	switch (vector) {
	default:
		icr |= APIC_DM_FIXED | vector;
		break;
	case NMI_VECTOR:
		icr |= APIC_DM_NMI;
		break;
	}
	return icr;
}

static inline int __prepare_ICR2(unsigned int mask)
{
	return SET_APIC_DEST_FIELD(mask);
}

void __send_IPI_shortcut(unsigned int shortcut, int vector)
{
	/*
	 * 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.
	 */
	apic_wait_icr_idle();

	/*
	 * No need to touch the target chip field
	 */
	cfg = __prepare_ICR(shortcut, vector);

	/*
	 * Send the IPI. The write to APIC_ICR fires this off.
	 */
75
	apic_write(APIC_ICR, cfg);
Glauber Costa's avatar
Glauber Costa committed
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
}

void send_IPI_self(int vector)
{
	__send_IPI_shortcut(APIC_DEST_SELF, vector);
}

/*
 * This is used to send an IPI with no shorthand notation (the destination is
 * specified in bits 56 to 63 of the ICR).
 */
static inline void __send_IPI_dest_field(unsigned long mask, int vector)
{
	unsigned long cfg;

	/*
	 * Wait for idle.
	 */
	if (unlikely(vector == NMI_VECTOR))
		safe_apic_wait_icr_idle();
	else
		apic_wait_icr_idle();

	/*
	 * prepare target chip field
	 */
	cfg = __prepare_ICR2(mask);
103
	apic_write(APIC_ICR2, cfg);
Glauber Costa's avatar
Glauber Costa committed
104 105 106 107 108 109 110 111 112

	/*
	 * program the ICR
	 */
	cfg = __prepare_ICR(0, vector);

	/*
	 * Send the IPI. The write to APIC_ICR fires this off.
	 */
113
	apic_write(APIC_ICR, cfg);
Glauber Costa's avatar
Glauber Costa committed
114 115 116 117 118
}

/*
 * This is only used on smaller machines.
 */
119
void send_IPI_mask_bitmask(const struct cpumask *cpumask, int vector)
Glauber Costa's avatar
Glauber Costa committed
120
{
121
	unsigned long mask = cpumask_bits(cpumask)[0];
Glauber Costa's avatar
Glauber Costa committed
122 123 124
	unsigned long flags;

	local_irq_save(flags);
125
	WARN_ON(mask & ~cpumask_bits(cpu_online_mask)[0]);
Glauber Costa's avatar
Glauber Costa committed
126 127 128 129
	__send_IPI_dest_field(mask, vector);
	local_irq_restore(flags);
}

130
void send_IPI_mask_sequence(const struct cpumask *mask, int vector)
Glauber Costa's avatar
Glauber Costa committed
131 132 133 134 135 136 137 138 139 140 141
{
	unsigned long flags;
	unsigned int query_cpu;

	/*
	 * Hack. The clustered APIC addressing mode doesn't allow us to send
	 * to an arbitrary mask, so I do a unicasts to each CPU instead. This
	 * should be modified to do 1 message per cluster ID - mbligh
	 */

	local_irq_save(flags);
142
	for_each_cpu(query_cpu, mask)
143 144 145 146
		__send_IPI_dest_field(cpu_to_logical_apicid(query_cpu), vector);
	local_irq_restore(flags);
}

147
void send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
148 149 150 151 152 153 154 155
{
	unsigned long flags;
	unsigned int query_cpu;
	unsigned int this_cpu = smp_processor_id();

	/* See Hack comment above */

	local_irq_save(flags);
156
	for_each_cpu(query_cpu, mask)
157
		if (query_cpu != this_cpu)
Glauber Costa's avatar
Glauber Costa committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
			__send_IPI_dest_field(cpu_to_logical_apicid(query_cpu),
					      vector);
	local_irq_restore(flags);
}

/* must come after the send_IPI functions above for inlining */
static int convert_apicid_to_cpu(int apic_id)
{
	int i;

	for_each_possible_cpu(i) {
		if (per_cpu(x86_cpu_to_apicid, i) == apic_id)
			return i;
	}
	return -1;
}

int safe_smp_processor_id(void)
{
	int apicid, cpuid;

	if (!boot_cpu_has(X86_FEATURE_APIC))
		return 0;

	apicid = hard_smp_processor_id();
	if (apicid == BAD_APICID)
		return 0;

	cpuid = convert_apicid_to_cpu(apicid);

	return cpuid >= 0 ? cpuid : 0;
}
#endif