blob: 07352b74bda6dfaac343ef5caa5674c6fde77a9e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright 2004 James Cleverdon, IBM.
3 * Subject to the GNU Public License, v.2
4 *
Andi Kleenf8d31192005-07-28 21:15:42 -07005 * Flat APIC subarch code.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
7 * Hacked for x86-64 by James Cleverdon from i386 architecture code by
8 * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
9 * James Cleverdon.
10 */
Andi Kleenf19cccf2007-05-02 19:27:21 +020011#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/threads.h>
13#include <linux/cpumask.h>
14#include <linux/string.h>
15#include <linux/kernel.h>
16#include <linux/ctype.h>
17#include <linux/init.h>
18#include <asm/smp.h>
19#include <asm/ipi.h>
Jan Beulich00f1ea62007-05-02 19:27:04 +020020#include <asm/genapic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Linus Torvalds1da177e2005-04-16 15:20:36 -070022static cpumask_t flat_target_cpus(void)
23{
24 return cpu_online_map;
25}
26
Eric W. Biedermanc7111c132006-10-08 07:47:55 -060027static cpumask_t flat_vector_allocation_domain(int cpu)
28{
29 /* Careful. Some cpus do not strictly honor the set of cpus
30 * specified in the interrupt destination when using lowest
31 * priority interrupt delivery mode.
32 *
33 * In particular there was a hyperthreading cpu observed to
34 * deliver interrupts to the wrong hyperthread when only one
35 * hyperthread was specified in the interrupt desitination.
36 */
37 cpumask_t domain = { { [0] = APIC_ALL_CPUS, } };
38 return domain;
39}
40
Linus Torvalds1da177e2005-04-16 15:20:36 -070041/*
42 * Set up the logical destination ID.
43 *
44 * Intel recommends to set DFR, LDR and TPR before enabling
45 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
46 * document number 292116). So here it goes...
47 */
48static void flat_init_apic_ldr(void)
49{
50 unsigned long val;
51 unsigned long num, id;
52
53 num = smp_processor_id();
54 id = 1UL << num;
Andi Kleeneddfb4e2005-09-12 18:49:23 +020055 apic_write(APIC_DFR, APIC_DFR_FLAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
57 val |= SET_APIC_LOGICAL_ID(id);
Andi Kleeneddfb4e2005-09-12 18:49:23 +020058 apic_write(APIC_LDR, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059}
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
62{
63 unsigned long mask = cpus_addr(cpumask)[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 unsigned long flags;
65
Fernando Luis Vázquez Cao2b94ab22006-09-26 10:52:33 +020066 local_irq_save(flags);
Fernando Luis [** ISO-8859-1 charset **] VázquezCao9062d882007-05-02 19:27:18 +020067 __send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 local_irq_restore(flags);
69}
70
Ashok Raj884d9e42005-06-25 14:55:02 -070071static void flat_send_IPI_allbutself(int vector)
72{
Keith Owense77deac2006-06-26 13:59:56 +020073#ifdef CONFIG_HOTPLUG_CPU
74 int hotplug = 1;
Ashok Rajfdf26d92005-09-09 13:01:52 -070075#else
Keith Owense77deac2006-06-26 13:59:56 +020076 int hotplug = 0;
Ashok Rajfdf26d92005-09-09 13:01:52 -070077#endif
Keith Owense77deac2006-06-26 13:59:56 +020078 if (hotplug || vector == NMI_VECTOR) {
79 cpumask_t allbutme = cpu_online_map;
80
81 cpu_clear(smp_processor_id(), allbutme);
82
83 if (!cpus_empty(allbutme))
84 flat_send_IPI_mask(allbutme, vector);
85 } else if (num_online_cpus() > 1) {
86 __send_IPI_shortcut(APIC_DEST_ALLBUT, vector,APIC_DEST_LOGICAL);
87 }
Ashok Raj884d9e42005-06-25 14:55:02 -070088}
89
90static void flat_send_IPI_all(int vector)
91{
Keith Owense77deac2006-06-26 13:59:56 +020092 if (vector == NMI_VECTOR)
93 flat_send_IPI_mask(cpu_online_map, vector);
94 else
95 __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
Ashok Raj884d9e42005-06-25 14:55:02 -070096}
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static int flat_apic_id_registered(void)
99{
100 return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map);
101}
102
103static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask)
104{
105 return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
106}
107
108static unsigned int phys_pkg_id(int index_msb)
109{
ravikiran thirumalai0f4fdb72006-06-26 13:56:04 +0200110 return hard_smp_processor_id() >> index_msb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
113struct genapic apic_flat = {
114 .name = "flat",
115 .int_delivery_mode = dest_LowestPrio,
116 .int_dest_mode = (APIC_DEST_LOGICAL != 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 .target_cpus = flat_target_cpus,
Eric W. Biedermanc7111c132006-10-08 07:47:55 -0600118 .vector_allocation_domain = flat_vector_allocation_domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 .apic_id_registered = flat_apic_id_registered,
120 .init_apic_ldr = flat_init_apic_ldr,
121 .send_IPI_all = flat_send_IPI_all,
122 .send_IPI_allbutself = flat_send_IPI_allbutself,
123 .send_IPI_mask = flat_send_IPI_mask,
124 .cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
125 .phys_pkg_id = phys_pkg_id,
126};
Andi Kleenf8d31192005-07-28 21:15:42 -0700127
128/*
129 * Physflat mode is used when there are more than 8 CPUs on a AMD system.
130 * We cannot use logical delivery in this case because the mask
131 * overflows, so use physical mode.
132 */
133
134static cpumask_t physflat_target_cpus(void)
135{
Eric W. Biederman84f404f2006-10-21 18:37:02 +0200136 return cpu_online_map;
Andi Kleenf8d31192005-07-28 21:15:42 -0700137}
138
Eric W. Biedermanc7111c132006-10-08 07:47:55 -0600139static cpumask_t physflat_vector_allocation_domain(int cpu)
140{
141 cpumask_t domain = CPU_MASK_NONE;
142 cpu_set(cpu, domain);
143 return domain;
144}
145
146
Andi Kleenf8d31192005-07-28 21:15:42 -0700147static void physflat_send_IPI_mask(cpumask_t cpumask, int vector)
148{
149 send_IPI_mask_sequence(cpumask, vector);
150}
151
152static void physflat_send_IPI_allbutself(int vector)
153{
154 cpumask_t allbutme = cpu_online_map;
Zwane Mwaikambo329d4002006-01-11 22:43:09 +0100155
156 cpu_clear(smp_processor_id(), allbutme);
Andi Kleenf8d31192005-07-28 21:15:42 -0700157 physflat_send_IPI_mask(allbutme, vector);
Andi Kleenf8d31192005-07-28 21:15:42 -0700158}
159
160static void physflat_send_IPI_all(int vector)
161{
162 physflat_send_IPI_mask(cpu_online_map, vector);
163}
164
165static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask)
166{
167 int cpu;
168
169 /*
170 * We're using fixed IRQ delivery, can only return one phys APIC ID.
171 * May as well be the first.
172 */
173 cpu = first_cpu(cpumask);
174 if ((unsigned)cpu < NR_CPUS)
Mike Travis71fff5e2007-10-19 20:35:03 +0200175 return per_cpu(x86_cpu_to_apicid, cpu);
Andi Kleenf8d31192005-07-28 21:15:42 -0700176 else
177 return BAD_APICID;
178}
179
180struct genapic apic_physflat = {
181 .name = "physical flat",
Ashok Rajc1a71a12005-09-12 18:49:24 +0200182 .int_delivery_mode = dest_Fixed,
Andi Kleenf8d31192005-07-28 21:15:42 -0700183 .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
Andi Kleenf8d31192005-07-28 21:15:42 -0700184 .target_cpus = physflat_target_cpus,
Eric W. Biedermanc7111c132006-10-08 07:47:55 -0600185 .vector_allocation_domain = physflat_vector_allocation_domain,
Andi Kleenf8d31192005-07-28 21:15:42 -0700186 .apic_id_registered = flat_apic_id_registered,
187 .init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/
188 .send_IPI_all = physflat_send_IPI_all,
189 .send_IPI_allbutself = physflat_send_IPI_allbutself,
190 .send_IPI_mask = physflat_send_IPI_mask,
191 .cpu_mask_to_apicid = physflat_cpu_mask_to_apicid,
192 .phys_pkg_id = phys_pkg_id,
193};