Merge branches 'amd-iommu/fixes' and 'dma-debug/fixes' into iommu/fixes
[linux-2.6-block.git] / arch / x86 / kernel / apic / bigsmp_32.c
CommitLineData
637cba02 1/*
77313190
IM
2 * APIC driver for "bigsmp" xAPIC machines with more than 8 virtual CPUs.
3 *
1da177e4
LT
4 * Drives the local APIC in "clustered mode".
5 */
1da177e4
LT
6#include <linux/threads.h>
7#include <linux/cpumask.h>
1da177e4 8#include <linux/kernel.h>
1da177e4
LT
9#include <linux/init.h>
10#include <linux/dmi.h>
4696ca5b 11#include <linux/smp.h>
9f4187f0 12
77313190
IM
13#include <asm/apicdef.h>
14#include <asm/fixmap.h>
15#include <asm/mpspec.h>
16#include <asm/apic.h>
17#include <asm/ipi.h>
9f4187f0 18
9694cd6c 19static unsigned bigsmp_get_apic_id(unsigned long x)
9f4187f0
IM
20{
21 return (x >> 24) & 0xFF;
22}
23
9694cd6c 24static int bigsmp_apic_id_registered(void)
9f4187f0
IM
25{
26 return 1;
27}
28
4f062896 29static const struct cpumask *bigsmp_target_cpus(void)
9f4187f0
IM
30{
31#ifdef CONFIG_SMP
4f062896 32 return cpu_online_mask;
9f4187f0 33#else
4f062896 34 return cpumask_of(0);
9f4187f0
IM
35#endif
36}
37
7abc0753 38static unsigned long bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
9f4187f0
IM
39{
40 return 0;
41}
42
9694cd6c 43static unsigned long bigsmp_check_apicid_present(int bit)
9f4187f0
IM
44{
45 return 1;
46}
47
48static inline unsigned long calculate_ldr(int cpu)
49{
50 unsigned long val, id;
77313190 51
9f4187f0 52 val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
77313190 53 id = per_cpu(x86_bios_cpu_apicid, cpu);
9f4187f0 54 val |= SET_APIC_LOGICAL_ID(id);
77313190 55
9f4187f0
IM
56 return val;
57}
58
59/*
60 * Set up the logical destination ID.
61 *
62 * Intel recommends to set DFR, LDR and TPR before enabling
63 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
64 * document number 292116). So here it goes...
65 */
9694cd6c 66static void bigsmp_init_apic_ldr(void)
9f4187f0
IM
67{
68 unsigned long val;
69 int cpu = smp_processor_id();
70
77313190 71 apic_write(APIC_DFR, APIC_DFR_FLAT);
9f4187f0
IM
72 val = calculate_ldr(cpu);
73 apic_write(APIC_LDR, val);
74}
75
9694cd6c 76static void bigsmp_setup_apic_routing(void)
9f4187f0 77{
77313190
IM
78 printk(KERN_INFO
79 "Enabling APIC mode: Physflat. Using %d I/O APICs\n",
80 nr_ioapics);
9f4187f0
IM
81}
82
9694cd6c 83static int bigsmp_apicid_to_node(int logical_apicid)
9f4187f0
IM
84{
85 return apicid_2_node[hard_smp_processor_id()];
86}
87
9694cd6c 88static int bigsmp_cpu_present_to_apicid(int mps_cpu)
9f4187f0
IM
89{
90 if (mps_cpu < nr_cpu_ids)
91 return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
92
93 return BAD_APICID;
94}
95
9f4187f0
IM
96/* Mapping from cpu number to logical apicid */
97static inline int bigsmp_cpu_to_logical_apicid(int cpu)
98{
99 if (cpu >= nr_cpu_ids)
100 return BAD_APICID;
101 return cpu_physical_id(cpu);
102}
103
7abc0753 104static void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
9f4187f0
IM
105{
106 /* For clustered we don't have a good way to do this yet - hack */
7abc0753 107 physids_promote(0xFFL, retmap);
9f4187f0
IM
108}
109
e11dadab 110static int bigsmp_check_phys_apicid_present(int phys_apicid)
9f4187f0
IM
111{
112 return 1;
113}
114
115/* As we are using single CPU as destination, pick only one CPU here */
4f062896 116static unsigned int bigsmp_cpu_mask_to_apicid(const struct cpumask *cpumask)
9f4187f0 117{
4f062896 118 return bigsmp_cpu_to_logical_apicid(cpumask_first(cpumask));
9f4187f0
IM
119}
120
9694cd6c 121static unsigned int bigsmp_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
9f4187f0
IM
122 const struct cpumask *andmask)
123{
124 int cpu;
125
126 /*
127 * We're using fixed IRQ delivery, can only return one phys APIC ID.
128 * May as well be the first.
129 */
130 for_each_cpu_and(cpu, cpumask, andmask) {
131 if (cpumask_test_cpu(cpu, cpu_online_mask))
132 break;
133 }
18374d89 134 return bigsmp_cpu_to_logical_apicid(cpu);
9f4187f0
IM
135}
136
9694cd6c 137static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
9f4187f0
IM
138{
139 return cpuid_apic >> index_msb;
140}
141
9f4187f0
IM
142static inline void bigsmp_send_IPI_mask(const struct cpumask *mask, int vector)
143{
43f39890 144 default_send_IPI_mask_sequence_phys(mask, vector);
9f4187f0
IM
145}
146
9694cd6c 147static void bigsmp_send_IPI_allbutself(int vector)
9f4187f0 148{
43f39890 149 default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
9f4187f0
IM
150}
151
9694cd6c 152static void bigsmp_send_IPI_all(int vector)
9f4187f0
IM
153{
154 bigsmp_send_IPI_mask(cpu_online_mask, vector);
155}
1da177e4
LT
156
157static int dmi_bigsmp; /* can be set by dmi scanners */
158
1855256c 159static int hp_ht_bigsmp(const struct dmi_system_id *d)
1da177e4 160{
1da177e4
LT
161 printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident);
162 dmi_bigsmp = 1;
77313190 163
1da177e4
LT
164 return 0;
165}
166
167
1855256c 168static const struct dmi_system_id bigsmp_dmi_table[] = {
637cba02 169 { hp_ht_bigsmp, "HP ProLiant DL760 G2",
77313190
IM
170 { DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
171 DMI_MATCH(DMI_BIOS_VERSION, "P44-"),
172 }
637cba02
PC
173 },
174
175 { hp_ht_bigsmp, "HP ProLiant DL740",
77313190
IM
176 { DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
177 DMI_MATCH(DMI_BIOS_VERSION, "P47-"),
178 }
637cba02 179 },
77313190 180 { } /* NULL entry stops DMI scanning */
1da177e4
LT
181};
182
4f062896 183static void bigsmp_vector_allocation_domain(int cpu, struct cpumask *retmask)
497c9a19 184{
4f062896
RR
185 cpumask_clear(retmask);
186 cpumask_set_cpu(cpu, retmask);
497c9a19 187}
1da177e4 188
af669c97 189static int probe_bigsmp(void)
637cba02 190{
911a62d4 191 if (def_to_bigsmp)
e0da3364 192 dmi_bigsmp = 1;
911a62d4
VP
193 else
194 dmi_check_system(bigsmp_dmi_table);
77313190 195
637cba02
PC
196 return dmi_bigsmp;
197}
1da177e4 198
be163a15 199struct apic apic_bigsmp = {
d26b6d66
IM
200
201 .name = "bigsmp",
202 .probe = probe_bigsmp,
306db03b 203 .acpi_madt_oem_check = NULL,
7ed248da 204 .apic_id_registered = bigsmp_apic_id_registered,
d26b6d66 205
d8a3539e
IM
206 .irq_delivery_mode = dest_Fixed,
207 /* phys delivery to target CPU: */
208 .irq_dest_mode = 0,
d26b6d66 209
0a9cc20b 210 .target_cpus = bigsmp_target_cpus,
08125d3e 211 .disable_esr = 1,
bdb1a9b6 212 .dest_logical = 0,
d1d7cae8
IM
213 .check_apicid_used = bigsmp_check_apicid_used,
214 .check_apicid_present = bigsmp_check_apicid_present,
d26b6d66 215
e2d40b18 216 .vector_allocation_domain = bigsmp_vector_allocation_domain,
a5c43296 217 .init_apic_ldr = bigsmp_init_apic_ldr,
d26b6d66 218
d190cb87 219 .ioapic_phys_id_map = bigsmp_ioapic_phys_id_map,
72ce0165 220 .setup_apic_routing = bigsmp_setup_apic_routing,
33a201fa 221 .multi_timer_check = NULL,
3f57a318 222 .apicid_to_node = bigsmp_apicid_to_node,
5257c511 223 .cpu_to_logical_apicid = bigsmp_cpu_to_logical_apicid,
a21769a4 224 .cpu_present_to_apicid = bigsmp_cpu_present_to_apicid,
7abc0753 225 .apicid_to_cpu_present = physid_set_mask_of_physid,
d83093b5 226 .setup_portio_remap = NULL,
a27a6210 227 .check_phys_apicid_present = bigsmp_check_phys_apicid_present,
49040333 228 .enable_apic_mode = NULL,
cb8cc442 229 .phys_pkg_id = bigsmp_phys_pkg_id,
9c764247 230 .mps_oem_check = NULL,
d26b6d66 231
ca6c8ed4 232 .get_apic_id = bigsmp_get_apic_id,
d26b6d66 233 .set_apic_id = NULL,
94af1875 234 .apic_id_mask = 0xFF << 24,
d26b6d66 235
debccb3e
IM
236 .cpu_mask_to_apicid = bigsmp_cpu_mask_to_apicid,
237 .cpu_mask_to_apicid_and = bigsmp_cpu_mask_to_apicid_and,
d26b6d66 238
9f4187f0 239 .send_IPI_mask = bigsmp_send_IPI_mask,
d26b6d66 240 .send_IPI_mask_allbutself = NULL,
dac5f412
IM
241 .send_IPI_allbutself = bigsmp_send_IPI_allbutself,
242 .send_IPI_all = bigsmp_send_IPI_all,
6b64ee02 243 .send_IPI_self = default_send_IPI_self,
d26b6d66 244
6f177c01
IM
245 .trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
246 .trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
a9659366
IM
247
248 .wait_for_init_deassert = default_wait_for_init_deassert,
249
333344d9 250 .smp_callin_clear_local_apic = NULL,
25dc0049 251 .inquire_remote_apic = default_inquire_remote_apic,
c1eeb2de
YL
252
253 .read = native_apic_mem_read,
254 .write = native_apic_mem_write,
255 .icr_read = native_apic_icr_read,
256 .icr_write = native_apic_icr_write,
257 .wait_icr_idle = native_apic_wait_icr_idle,
258 .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
d26b6d66 259};