144b111b5SSteffen Persvold /*
244b111b5SSteffen Persvold * This file is subject to the terms and conditions of the GNU General Public
344b111b5SSteffen Persvold * License. See the file "COPYING" in the main directory of this archive
444b111b5SSteffen Persvold * for more details.
544b111b5SSteffen Persvold *
644b111b5SSteffen Persvold * Numascale NumaConnect-Specific APIC Code
744b111b5SSteffen Persvold *
844b111b5SSteffen Persvold * Copyright (C) 2011 Numascale AS. All rights reserved.
944b111b5SSteffen Persvold *
1044b111b5SSteffen Persvold * Send feedback to <support@numascale.com>
1144b111b5SSteffen Persvold *
1244b111b5SSteffen Persvold */
13521b82feSThomas Gleixner #include <linux/types.h>
1444b111b5SSteffen Persvold #include <linux/init.h>
1565fddcfcSMike Rapoport #include <linux/pgtable.h>
1644b111b5SSteffen Persvold
17f9726bfdSDaniel J Blueman #include <asm/numachip/numachip.h>
1844b111b5SSteffen Persvold #include <asm/numachip/numachip_csr.h>
19521b82feSThomas Gleixner
208b542da3SThomas Gleixner
21c94f0718SThomas Gleixner #include "local.h"
2244b111b5SSteffen Persvold
23db1003a7SDaniel J Blueman u8 numachip_system __read_mostly;
24db1003a7SDaniel J Blueman static const struct apic apic_numachip1;
25d9d4dee6SDaniel J Blueman static const struct apic apic_numachip2;
26db1003a7SDaniel J Blueman static void (*numachip_apic_icr_write)(int apicid, unsigned int val) __read_mostly;
2744b111b5SSteffen Persvold
numachip1_get_apic_id(u32 x)2859f7928cSThomas Gleixner static u32 numachip1_get_apic_id(u32 x)
2944b111b5SSteffen Persvold {
3044b111b5SSteffen Persvold unsigned long value;
31c8a470caSDaniel J Blueman unsigned int id = (x >> 24) & 0xff;
3244b111b5SSteffen Persvold
33bc696ca0SBorislav Petkov if (static_cpu_has(X86_FEATURE_NODEID_MSR)) {
3444b111b5SSteffen Persvold rdmsrl(MSR_FAM10H_NODE_ID, value);
35c8a470caSDaniel J Blueman id |= (value << 2) & 0xff00;
36c8a470caSDaniel J Blueman }
3744b111b5SSteffen Persvold
3844b111b5SSteffen Persvold return id;
3944b111b5SSteffen Persvold }
4044b111b5SSteffen Persvold
numachip2_get_apic_id(u32 x)4159f7928cSThomas Gleixner static u32 numachip2_get_apic_id(u32 x)
42d9d4dee6SDaniel J Blueman {
43d9d4dee6SDaniel J Blueman u64 mcfg;
44d9d4dee6SDaniel J Blueman
45d9d4dee6SDaniel J Blueman rdmsrl(MSR_FAM10H_MMIO_CONF_BASE, mcfg);
46d9d4dee6SDaniel J Blueman return ((mcfg >> (28 - 8)) & 0xfff00) | (x >> 24);
47d9d4dee6SDaniel J Blueman }
48d9d4dee6SDaniel J Blueman
numachip1_apic_icr_write(int apicid,unsigned int val)49db1003a7SDaniel J Blueman static void numachip1_apic_icr_write(int apicid, unsigned int val)
50db1003a7SDaniel J Blueman {
51db1003a7SDaniel J Blueman write_lcsr(CSR_G3_EXT_IRQ_GEN, (apicid << 16) | val);
52db1003a7SDaniel J Blueman }
53db1003a7SDaniel J Blueman
numachip2_apic_icr_write(int apicid,unsigned int val)54d9d4dee6SDaniel J Blueman static void numachip2_apic_icr_write(int apicid, unsigned int val)
55d9d4dee6SDaniel J Blueman {
56d9d4dee6SDaniel J Blueman numachip2_write32_lcsr(NUMACHIP2_APIC_ICR, (apicid << 12) | val);
57d9d4dee6SDaniel J Blueman }
58d9d4dee6SDaniel J Blueman
numachip_wakeup_secondary(u32 phys_apicid,unsigned long start_rip)59*db4a4086SThomas Gleixner static int numachip_wakeup_secondary(u32 phys_apicid, unsigned long start_rip)
6044b111b5SSteffen Persvold {
61db1003a7SDaniel J Blueman numachip_apic_icr_write(phys_apicid, APIC_DM_INIT);
62db1003a7SDaniel J Blueman numachip_apic_icr_write(phys_apicid, APIC_DM_STARTUP |
63db1003a7SDaniel J Blueman (start_rip >> 12));
6444b111b5SSteffen Persvold
6544b111b5SSteffen Persvold return 0;
6644b111b5SSteffen Persvold }
6744b111b5SSteffen Persvold
numachip_send_IPI_one(int cpu,int vector)6844b111b5SSteffen Persvold static void numachip_send_IPI_one(int cpu, int vector)
6944b111b5SSteffen Persvold {
70ad03a9c2SDaniel J Blueman int local_apicid, apicid = per_cpu(x86_cpu_to_apicid, cpu);
71db1003a7SDaniel J Blueman unsigned int dmode;
7244b111b5SSteffen Persvold
73ad03a9c2SDaniel J Blueman preempt_disable();
74ad03a9c2SDaniel J Blueman local_apicid = __this_cpu_read(x86_cpu_to_apicid);
75ad03a9c2SDaniel J Blueman
76ad03a9c2SDaniel J Blueman /* Send via local APIC where non-local part matches */
77ad03a9c2SDaniel J Blueman if (!((apicid ^ local_apicid) >> NUMACHIP_LAPIC_BITS)) {
78ad03a9c2SDaniel J Blueman unsigned long flags;
79ad03a9c2SDaniel J Blueman
80ad03a9c2SDaniel J Blueman local_irq_save(flags);
81ad03a9c2SDaniel J Blueman __default_send_IPI_dest_field(apicid, vector,
82ad03a9c2SDaniel J Blueman APIC_DEST_PHYSICAL);
83ad03a9c2SDaniel J Blueman local_irq_restore(flags);
84ad03a9c2SDaniel J Blueman preempt_enable();
85ad03a9c2SDaniel J Blueman return;
86ad03a9c2SDaniel J Blueman }
87ad03a9c2SDaniel J Blueman preempt_enable();
88ad03a9c2SDaniel J Blueman
89db1003a7SDaniel J Blueman dmode = (vector == NMI_VECTOR) ? APIC_DM_NMI : APIC_DM_FIXED;
90db1003a7SDaniel J Blueman numachip_apic_icr_write(apicid, dmode | vector);
9144b111b5SSteffen Persvold }
9244b111b5SSteffen Persvold
numachip_send_IPI_mask(const struct cpumask * mask,int vector)9344b111b5SSteffen Persvold static void numachip_send_IPI_mask(const struct cpumask *mask, int vector)
9444b111b5SSteffen Persvold {
9544b111b5SSteffen Persvold unsigned int cpu;
9644b111b5SSteffen Persvold
9744b111b5SSteffen Persvold for_each_cpu(cpu, mask)
9844b111b5SSteffen Persvold numachip_send_IPI_one(cpu, vector);
9944b111b5SSteffen Persvold }
10044b111b5SSteffen Persvold
numachip_send_IPI_mask_allbutself(const struct cpumask * mask,int vector)10144b111b5SSteffen Persvold static void numachip_send_IPI_mask_allbutself(const struct cpumask *mask,
10244b111b5SSteffen Persvold int vector)
10344b111b5SSteffen Persvold {
10444b111b5SSteffen Persvold unsigned int this_cpu = smp_processor_id();
10544b111b5SSteffen Persvold unsigned int cpu;
10644b111b5SSteffen Persvold
10744b111b5SSteffen Persvold for_each_cpu(cpu, mask) {
10844b111b5SSteffen Persvold if (cpu != this_cpu)
10944b111b5SSteffen Persvold numachip_send_IPI_one(cpu, vector);
11044b111b5SSteffen Persvold }
11144b111b5SSteffen Persvold }
11244b111b5SSteffen Persvold
numachip_send_IPI_allbutself(int vector)11344b111b5SSteffen Persvold static void numachip_send_IPI_allbutself(int vector)
11444b111b5SSteffen Persvold {
11544b111b5SSteffen Persvold unsigned int this_cpu = smp_processor_id();
11644b111b5SSteffen Persvold unsigned int cpu;
11744b111b5SSteffen Persvold
11844b111b5SSteffen Persvold for_each_online_cpu(cpu) {
11944b111b5SSteffen Persvold if (cpu != this_cpu)
12044b111b5SSteffen Persvold numachip_send_IPI_one(cpu, vector);
12144b111b5SSteffen Persvold }
12244b111b5SSteffen Persvold }
12344b111b5SSteffen Persvold
numachip_send_IPI_all(int vector)12444b111b5SSteffen Persvold static void numachip_send_IPI_all(int vector)
12544b111b5SSteffen Persvold {
12644b111b5SSteffen Persvold numachip_send_IPI_mask(cpu_online_mask, vector);
12744b111b5SSteffen Persvold }
12844b111b5SSteffen Persvold
numachip_send_IPI_self(int vector)12944b111b5SSteffen Persvold static void numachip_send_IPI_self(int vector)
13044b111b5SSteffen Persvold {
13125e5a76bSDaniel J Blueman apic_write(APIC_SELF_IPI, vector);
13244b111b5SSteffen Persvold }
13344b111b5SSteffen Persvold
numachip1_probe(void)134db1003a7SDaniel J Blueman static int __init numachip1_probe(void)
13544b111b5SSteffen Persvold {
136db1003a7SDaniel J Blueman return apic == &apic_numachip1;
13744b111b5SSteffen Persvold }
13844b111b5SSteffen Persvold
numachip2_probe(void)139d9d4dee6SDaniel J Blueman static int __init numachip2_probe(void)
140d9d4dee6SDaniel J Blueman {
141d9d4dee6SDaniel J Blueman return apic == &apic_numachip2;
142d9d4dee6SDaniel J Blueman }
143d9d4dee6SDaniel J Blueman
fixup_cpu_id(struct cpuinfo_x86 * c,int node)14444b111b5SSteffen Persvold static void fixup_cpu_id(struct cpuinfo_x86 *c, int node)
14544b111b5SSteffen Persvold {
146c8a470caSDaniel J Blueman u64 val;
147c8a470caSDaniel J Blueman u32 nodes = 1;
148c8a470caSDaniel J Blueman
1496e290323SThomas Gleixner c->topo.llc_id = node;
150c8a470caSDaniel J Blueman
151c8a470caSDaniel J Blueman /* Account for nodes per socket in multi-core-module processors */
15267e87d43SBorislav Petkov if (boot_cpu_has(X86_FEATURE_NODEID_MSR)) {
153c8a470caSDaniel J Blueman rdmsrl(MSR_FAM10H_NODE_ID, val);
154c8a470caSDaniel J Blueman nodes = ((val >> 3) & 7) + 1;
15544b111b5SSteffen Persvold }
156c8a470caSDaniel J Blueman
15702fb601dSThomas Gleixner c->topo.pkg_id = node / nodes;
15868894632SAndreas Herrmann }
15944b111b5SSteffen Persvold
numachip_system_init(void)16044b111b5SSteffen Persvold static int __init numachip_system_init(void)
16144b111b5SSteffen Persvold {
162db1003a7SDaniel J Blueman /* Map the LCSR area and set up the apic_icr_write function */
163db1003a7SDaniel J Blueman switch (numachip_system) {
164db1003a7SDaniel J Blueman case 1:
165b980dcf2SDaniel J Blueman init_extra_mapping_uc(NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_SIZE);
166db1003a7SDaniel J Blueman numachip_apic_icr_write = numachip1_apic_icr_write;
167db1003a7SDaniel J Blueman break;
168d9d4dee6SDaniel J Blueman case 2:
169d9d4dee6SDaniel J Blueman init_extra_mapping_uc(NUMACHIP2_LCSR_BASE, NUMACHIP2_LCSR_SIZE);
170d9d4dee6SDaniel J Blueman numachip_apic_icr_write = numachip2_apic_icr_write;
171d9d4dee6SDaniel J Blueman break;
172db1003a7SDaniel J Blueman default:
173db1003a7SDaniel J Blueman return 0;
174db1003a7SDaniel J Blueman }
175b980dcf2SDaniel J Blueman
17644b111b5SSteffen Persvold x86_cpuinit.fixup_cpu_id = fixup_cpu_id;
177dd7a5ab4SDaniel J Blueman x86_init.pci.arch_init = pci_numachip_init;
17844b111b5SSteffen Persvold
17944b111b5SSteffen Persvold return 0;
18044b111b5SSteffen Persvold }
18144b111b5SSteffen Persvold early_initcall(numachip_system_init);
18244b111b5SSteffen Persvold
numachip1_acpi_madt_oem_check(char * oem_id,char * oem_table_id)183db1003a7SDaniel J Blueman static int numachip1_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
18444b111b5SSteffen Persvold {
185db1003a7SDaniel J Blueman if ((strncmp(oem_id, "NUMASC", 6) != 0) ||
186db1003a7SDaniel J Blueman (strncmp(oem_table_id, "NCONNECT", 8) != 0))
187db1003a7SDaniel J Blueman return 0;
188db1003a7SDaniel J Blueman
18944b111b5SSteffen Persvold numachip_system = 1;
190db1003a7SDaniel J Blueman
19144b111b5SSteffen Persvold return 1;
19244b111b5SSteffen Persvold }
19344b111b5SSteffen Persvold
numachip2_acpi_madt_oem_check(char * oem_id,char * oem_table_id)194d9d4dee6SDaniel J Blueman static int numachip2_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
195d9d4dee6SDaniel J Blueman {
196d9d4dee6SDaniel J Blueman if ((strncmp(oem_id, "NUMASC", 6) != 0) ||
197d9d4dee6SDaniel J Blueman (strncmp(oem_table_id, "NCONECT2", 8) != 0))
198d9d4dee6SDaniel J Blueman return 0;
199d9d4dee6SDaniel J Blueman
200d9d4dee6SDaniel J Blueman numachip_system = 2;
201d9d4dee6SDaniel J Blueman
202d9d4dee6SDaniel J Blueman return 1;
203d9d4dee6SDaniel J Blueman }
204d9d4dee6SDaniel J Blueman
205db1003a7SDaniel J Blueman static const struct apic apic_numachip1 __refconst = {
20644b111b5SSteffen Persvold .name = "NumaConnect system",
207db1003a7SDaniel J Blueman .probe = numachip1_probe,
208db1003a7SDaniel J Blueman .acpi_madt_oem_check = numachip1_acpi_madt_oem_check,
20944b111b5SSteffen Persvold
2108c44963bSThomas Gleixner .dest_mode_logical = false,
21144b111b5SSteffen Persvold
21244b111b5SSteffen Persvold .disable_esr = 0,
213e57d04e5SThomas Gleixner
21444b111b5SSteffen Persvold .cpu_present_to_apicid = default_cpu_present_to_apicid,
21544b111b5SSteffen Persvold
216d92e5e7cSThomas Gleixner .max_apic_id = UINT_MAX,
217db1003a7SDaniel J Blueman .get_apic_id = numachip1_get_apic_id,
21844b111b5SSteffen Persvold
2199f9e3bb1SThomas Gleixner .calc_dest_apicid = apic_default_calc_apicid,
22044b111b5SSteffen Persvold
221c61a0d31SThomas Gleixner .send_IPI = numachip_send_IPI_one,
22244b111b5SSteffen Persvold .send_IPI_mask = numachip_send_IPI_mask,
22344b111b5SSteffen Persvold .send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself,
22444b111b5SSteffen Persvold .send_IPI_allbutself = numachip_send_IPI_allbutself,
22544b111b5SSteffen Persvold .send_IPI_all = numachip_send_IPI_all,
22644b111b5SSteffen Persvold .send_IPI_self = numachip_send_IPI_self,
22744b111b5SSteffen Persvold
22844b111b5SSteffen Persvold .wakeup_secondary_cpu = numachip_wakeup_secondary,
22944b111b5SSteffen Persvold
23044b111b5SSteffen Persvold .read = native_apic_mem_read,
23144b111b5SSteffen Persvold .write = native_apic_mem_write,
232185c8f33SThomas Gleixner .eoi = native_apic_mem_eoi,
23344b111b5SSteffen Persvold .icr_read = native_apic_icr_read,
23444b111b5SSteffen Persvold .icr_write = native_apic_icr_write,
23544b111b5SSteffen Persvold };
23644b111b5SSteffen Persvold
237db1003a7SDaniel J Blueman apic_driver(apic_numachip1);
238d9d4dee6SDaniel J Blueman
239d9d4dee6SDaniel J Blueman static const struct apic apic_numachip2 __refconst = {
240d9d4dee6SDaniel J Blueman .name = "NumaConnect2 system",
241d9d4dee6SDaniel J Blueman .probe = numachip2_probe,
242d9d4dee6SDaniel J Blueman .acpi_madt_oem_check = numachip2_acpi_madt_oem_check,
243d9d4dee6SDaniel J Blueman
2448c44963bSThomas Gleixner .dest_mode_logical = false,
245d9d4dee6SDaniel J Blueman
246d9d4dee6SDaniel J Blueman .disable_esr = 0,
247e57d04e5SThomas Gleixner
248d9d4dee6SDaniel J Blueman .cpu_present_to_apicid = default_cpu_present_to_apicid,
249d9d4dee6SDaniel J Blueman
250d92e5e7cSThomas Gleixner .max_apic_id = UINT_MAX,
251d9d4dee6SDaniel J Blueman .get_apic_id = numachip2_get_apic_id,
252d9d4dee6SDaniel J Blueman
2539f9e3bb1SThomas Gleixner .calc_dest_apicid = apic_default_calc_apicid,
254d9d4dee6SDaniel J Blueman
255c61a0d31SThomas Gleixner .send_IPI = numachip_send_IPI_one,
256d9d4dee6SDaniel J Blueman .send_IPI_mask = numachip_send_IPI_mask,
257d9d4dee6SDaniel J Blueman .send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself,
258d9d4dee6SDaniel J Blueman .send_IPI_allbutself = numachip_send_IPI_allbutself,
259d9d4dee6SDaniel J Blueman .send_IPI_all = numachip_send_IPI_all,
260d9d4dee6SDaniel J Blueman .send_IPI_self = numachip_send_IPI_self,
261d9d4dee6SDaniel J Blueman
262d9d4dee6SDaniel J Blueman .wakeup_secondary_cpu = numachip_wakeup_secondary,
263d9d4dee6SDaniel J Blueman
264d9d4dee6SDaniel J Blueman .read = native_apic_mem_read,
265d9d4dee6SDaniel J Blueman .write = native_apic_mem_write,
266185c8f33SThomas Gleixner .eoi = native_apic_mem_eoi,
267d9d4dee6SDaniel J Blueman .icr_read = native_apic_icr_read,
268d9d4dee6SDaniel J Blueman .icr_write = native_apic_icr_write,
269d9d4dee6SDaniel J Blueman };
270d9d4dee6SDaniel J Blueman
271d9d4dee6SDaniel J Blueman apic_driver(apic_numachip2);
272