probe_32.c 6.0 KB
Newer Older
1
/*
2 3
 * Default generic APIC driver. This handles up to 8 CPUs.
 *
4 5 6
 * Copyright 2003 Andi Kleen, SuSE Labs.
 * Subject to the GNU Public License, v.2
 *
L
Linus Torvalds 已提交
7
 * Generic x86 APIC driver probe layer.
8
 */
L
Linus Torvalds 已提交
9 10 11 12 13 14
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/init.h>
15
#include <linux/errno.h>
L
Linus Torvalds 已提交
16 17 18 19
#include <asm/fixmap.h>
#include <asm/mpspec.h>
#include <asm/apicdef.h>
#include <asm/genapic.h>
20
#include <asm/setup.h>
L
Linus Torvalds 已提交
21

22 23 24 25 26 27 28 29 30 31 32 33 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 75 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 103 104 105 106 107 108 109 110 111
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <asm/mpspec.h>
#include <asm/genapic.h>
#include <asm/fixmap.h>
#include <asm/apicdef.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/smp.h>
#include <linux/init.h>
#include <asm/genapic.h>
#include <asm/ipi.h>

static void default_vector_allocation_domain(int cpu, struct cpumask *retmask)
{
	/*
	 * 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.
	 */
	*retmask = (cpumask_t) { { [0] = APIC_ALL_CPUS } };
}

/* should be called last. */
static int probe_default(void)
{
	return 1;
}

struct genapic apic_default = {

	.name				= "default",
	.probe				= probe_default,
	.acpi_madt_oem_check		= NULL,
	.apic_id_registered		= default_apic_id_registered,

	.irq_delivery_mode		= dest_LowestPrio,
	/* logical delivery broadcast to all CPUs: */
	.irq_dest_mode			= 1,

	.target_cpus			= default_target_cpus,
	.disable_esr			= 0,
	.dest_logical			= APIC_DEST_LOGICAL,
	.check_apicid_used		= default_check_apicid_used,
	.check_apicid_present		= default_check_apicid_present,

	.vector_allocation_domain	= default_vector_allocation_domain,
	.init_apic_ldr			= default_init_apic_ldr,

	.ioapic_phys_id_map		= default_ioapic_phys_id_map,
	.setup_apic_routing		= default_setup_apic_routing,
	.multi_timer_check		= NULL,
	.apicid_to_node			= default_apicid_to_node,
	.cpu_to_logical_apicid		= default_cpu_to_logical_apicid,
	.cpu_present_to_apicid		= default_cpu_present_to_apicid,
	.apicid_to_cpu_present		= default_apicid_to_cpu_present,
	.setup_portio_remap		= NULL,
	.check_phys_apicid_present	= default_check_phys_apicid_present,
	.enable_apic_mode		= NULL,
	.phys_pkg_id			= default_phys_pkg_id,
	.mps_oem_check			= NULL,

	.get_apic_id			= default_get_apic_id,
	.set_apic_id			= NULL,
	.apic_id_mask			= 0x0F << 24,

	.cpu_mask_to_apicid		= default_cpu_mask_to_apicid,
	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,

	.send_IPI_mask			= default_send_IPI_mask,
	.send_IPI_mask_allbutself	= NULL,
	.send_IPI_allbutself		= default_send_IPI_allbutself,
	.send_IPI_all			= default_send_IPI_all,
	.send_IPI_self			= NULL,

	.wakeup_cpu			= NULL,
	.trampoline_phys_low		= DEFAULT_TRAMPOLINE_PHYS_LOW,
	.trampoline_phys_high		= DEFAULT_TRAMPOLINE_PHYS_HIGH,

	.wait_for_init_deassert		= default_wait_for_init_deassert,

	.smp_callin_clear_local_apic	= NULL,
	.store_NMI_vector		= NULL,
	.inquire_remote_apic		= default_inquire_remote_apic,
};

112
extern struct genapic apic_numaq;
L
Linus Torvalds 已提交
113 114 115 116 117
extern struct genapic apic_summit;
extern struct genapic apic_bigsmp;
extern struct genapic apic_es7000;
extern struct genapic apic_default;

I
Ingo Molnar 已提交
118
struct genapic *apic = &apic_default;
L
Linus Torvalds 已提交
119

A
Adrian Bunk 已提交
120
static struct genapic *apic_probe[] __initdata = {
121 122 123 124
#ifdef CONFIG_X86_NUMAQ
	&apic_numaq,
#endif
#ifdef CONFIG_X86_SUMMIT
L
Linus Torvalds 已提交
125
	&apic_summit,
126 127
#endif
#ifdef CONFIG_X86_BIGSMP
128
	&apic_bigsmp,
129 130
#endif
#ifdef CONFIG_X86_ES7000
L
Linus Torvalds 已提交
131
	&apic_es7000,
132
#endif
L
Linus Torvalds 已提交
133 134 135 136
	&apic_default,	/* must be last */
	NULL,
};

137 138 139 140 141 142 143 144 145 146
static int cmdline_apic __initdata;
static int __init parse_apic(char *arg)
{
	int i;

	if (!arg)
		return -EINVAL;

	for (i = 0; apic_probe[i]; i++) {
		if (!strcmp(apic_probe[i]->name, arg)) {
I
Ingo Molnar 已提交
147
			apic = apic_probe[i];
148 149 150 151
			cmdline_apic = 1;
			return 0;
		}
	}
152

153 154 155
	if (x86_quirks->update_genapic)
		x86_quirks->update_genapic();

156 157
	/* Parsed again by __setup for debug/verbose */
	return 0;
158 159
}
early_param("apic", parse_apic);
160 161 162

void __init generic_bigsmp_probe(void)
{
163
#ifdef CONFIG_X86_BIGSMP
164 165 166
	/*
	 * This routine is used to switch to bigsmp mode when
	 * - There is no apic= option specified by the user
S
Simon Arlott 已提交
167
	 * - generic_apic_probe() has chosen apic_default as the sub_arch
168 169 170
	 * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
	 */

I
Ingo Molnar 已提交
171
	if (!cmdline_apic && apic == &apic_default) {
172
		if (apic_bigsmp.probe()) {
I
Ingo Molnar 已提交
173
			apic = &apic_bigsmp;
174 175
			if (x86_quirks->update_genapic)
				x86_quirks->update_genapic();
176
			printk(KERN_INFO "Overriding APIC driver with %s\n",
I
Ingo Molnar 已提交
177
			       apic->name);
178
		}
179
	}
180
#endif
181 182
}

183
void __init generic_apic_probe(void)
184
{
185 186 187 188
	if (!cmdline_apic) {
		int i;
		for (i = 0; apic_probe[i]; i++) {
			if (apic_probe[i]->probe()) {
I
Ingo Molnar 已提交
189
				apic = apic_probe[i];
190
				break;
L
Linus Torvalds 已提交
191 192
			}
		}
193 194 195
		/* Not visible without early console */
		if (!apic_probe[i])
			panic("Didn't find an APIC driver");
196 197 198

		if (x86_quirks->update_genapic)
			x86_quirks->update_genapic();
L
Linus Torvalds 已提交
199
	}
I
Ingo Molnar 已提交
200
	printk(KERN_INFO "Using APIC driver %s\n", apic->name);
201
}
L
Linus Torvalds 已提交
202 203 204

/* These functions can switch the APIC even after the initial ->probe() */

205 206
int __init
generic_mps_oem_check(struct mpc_table *mpc, char *oem, char *productid)
207
{
L
Linus Torvalds 已提交
208
	int i;
I
Ingo Molnar 已提交
209

210
	for (i = 0; apic_probe[i]; ++i) {
I
Ingo Molnar 已提交
211 212 213 214 215 216 217 218 219 220 221
		if (!apic_probe[i]->mps_oem_check)
			continue;
		if (!apic_probe[i]->mps_oem_check(mpc, oem, productid))
			continue;

		if (!cmdline_apic) {
			apic = apic_probe[i];
			if (x86_quirks->update_genapic)
				x86_quirks->update_genapic();
			printk(KERN_INFO "Switched to APIC driver `%s'.\n",
			       apic->name);
222
		}
I
Ingo Molnar 已提交
223
		return 1;
224
	}
L
Linus Torvalds 已提交
225
	return 0;
226
}
L
Linus Torvalds 已提交
227

228
int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
L
Linus Torvalds 已提交
229 230
{
	int i;
231

232
	for (i = 0; apic_probe[i]; ++i) {
233 234 235 236 237 238 239 240 241 242 243
		if (!apic_probe[i]->acpi_madt_oem_check)
			continue;
		if (!apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id))
			continue;

		if (!cmdline_apic) {
			apic = apic_probe[i];
			if (x86_quirks->update_genapic)
				x86_quirks->update_genapic();
			printk(KERN_INFO "Switched to APIC driver `%s'.\n",
			       apic->name);
244
		}
245
		return 1;
246 247
	}
	return 0;
L
Linus Torvalds 已提交
248
}