xref: /linux/arch/x86/kernel/apic/apic_numachip.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
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