12d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha#include <linux/threads.h>
22d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha#include <linux/cpumask.h>
32d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha#include <linux/string.h>
42d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha#include <linux/kernel.h>
52d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha#include <linux/ctype.h>
61b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu#include <linux/dmar.h>
71b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu
82d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha#include <asm/smp.h>
979deb8e511bd6fc8e40add4da75b19df085d9453Cyrill Gorcunov#include <asm/x2apic.h>
102d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha
11ef1f87aa7ba6224bef1b750b3272ba281d8f43edSuresh Siddhaint x2apic_phys;
121b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu
131a8880a14270814dae0d226a2ad065d30587e60aSuresh Siddhastatic struct apic apic_x2apic_phys;
141a8880a14270814dae0d226a2ad065d30587e60aSuresh Siddha
151b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lustatic int set_x2apic_phys_mode(char *arg)
161b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu{
171b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu	x2apic_phys = 1;
181b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu	return 0;
191b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu}
201b9b89e7f163336ad84200b66a17284dbf26acedYinghai Luearly_param("x2apic_phys", set_x2apic_phys_mode);
211b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu
22cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wangstatic bool x2apic_fadt_phys(void)
231b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu{
24cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang	if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
25cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang		(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
26ea0dcf903e7d76aa5d483d876215fedcfdfe140fGreg Pearson		printk(KERN_DEBUG "System requires x2apic physical mode\n");
27cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang		return true;
28ea0dcf903e7d76aa5d483d876215fedcfdfe140fGreg Pearson	}
29cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang	return false;
30cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang}
31cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang
32cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wangstatic int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
33cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang{
34cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang	return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys());
351b9b89e7f163336ad84200b66a17284dbf26acedYinghai Lu}
362d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha
37a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddhastatic void
38a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
392d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha{
402d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha	unsigned long query_cpu;
41a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha	unsigned long this_cpu;
42dac5f4121df3c39fdb2ea57acd669a0ae19e46f8Ingo Molnar	unsigned long flags;
432d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha
44ce4e240c279a31096f74afa6584a62d64a1ba8c8Suresh Siddha	x2apic_wrmsr_fence();
45ce4e240c279a31096f74afa6584a62d64a1ba8c8Suresh Siddha
462d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha	local_irq_save(flags);
47a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha
48a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha	this_cpu = smp_processor_id();
49bcda016eddd7a8b374bb371473c821a91ff1d8ccMike Travis	for_each_cpu(query_cpu, mask) {
50a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha		if (apic_dest == APIC_DEST_ALLBUT && this_cpu == query_cpu)
51a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha			continue;
522d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha		__x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu),
532d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha				       vector, APIC_DEST_PHYSICAL);
542d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha	}
552d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha	local_irq_restore(flags);
562d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha}
572d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha
58a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddhastatic void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
59a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha{
60a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha	__x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLINC);
61a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha}
62a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha
63dac5f4121df3c39fdb2ea57acd669a0ae19e46f8Ingo Molnarstatic void
64dac5f4121df3c39fdb2ea57acd669a0ae19e46f8Ingo Molnar x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
652d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha{
66a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha	__x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);
67e7986739a76cde5079da08809d8bbc6878387ae0Mike Travis}
682d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha
69e7986739a76cde5079da08809d8bbc6878387ae0Mike Travisstatic void x2apic_send_IPI_allbutself(int vector)
70e7986739a76cde5079da08809d8bbc6878387ae0Mike Travis{
71a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha	__x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLBUT);
722d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha}
732d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha
742d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddhastatic void x2apic_send_IPI_all(int vector)
752d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha{
76a27d0b5e7d913b38880678ac05690f1dc737c4fdSuresh Siddha	__x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
772d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha}
782d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha
794d08d97f5262dab4482af5bc91b30af4ca02269eJaswinder Singh Rajputstatic void init_x2apic_ldr(void)
802d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha{
812d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha}
822d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha
839ebd680bd029a9fc47399ca61c950f8b6730ac40Suresh Siddhastatic int x2apic_phys_probe(void)
849ebd680bd029a9fc47399ca61c950f8b6730ac40Suresh Siddha{
85cb214ede7657db458fd0b2a25ea0b28dbf900ebcStoney Wang	if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys()))
869ebd680bd029a9fc47399ca61c950f8b6730ac40Suresh Siddha		return 1;
879ebd680bd029a9fc47399ca61c950f8b6730ac40Suresh Siddha
889ebd680bd029a9fc47399ca61c950f8b6730ac40Suresh Siddha	return apic == &apic_x2apic_phys;
899ebd680bd029a9fc47399ca61c950f8b6730ac40Suresh Siddha}
909ebd680bd029a9fc47399ca61c950f8b6730ac40Suresh Siddha
911a8880a14270814dae0d226a2ad065d30587e60aSuresh Siddhastatic struct apic apic_x2apic_phys = {
9205c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
9305c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.name				= "physical x2apic",
949ebd680bd029a9fc47399ca61c950f8b6730ac40Suresh Siddha	.probe				= x2apic_phys_probe,
9505c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.acpi_madt_oem_check		= x2apic_acpi_madt_oem_check,
96b7157acf429e6aef690646ba964b9ebd25049ec2Steffen Persvold	.apic_id_valid			= x2apic_apic_id_valid,
9705c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.apic_id_registered		= x2apic_apic_id_registered,
9805c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
99f8987a1093cc7a896137e264c24e04d4048e9f95Ingo Molnar	.irq_delivery_mode		= dest_Fixed,
1000b06e734bff7554c31eac4aad2fc9be4adb7c1c1Ingo Molnar	.irq_dest_mode			= 0, /* physical */
10105c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
102bf721d3a3bc7a731add45c8078b142b494ab413eAlexander Gordeev	.target_cpus			= online_target_cpus,
10308125d3edab90644724652eedec3e219e3e0f2e7Ingo Molnar	.disable_esr			= 0,
104bdb1a9b62fc182d4da3143e346f7a0925d243352Ingo Molnar	.dest_logical			= 0,
10505c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.check_apicid_used		= NULL,
10605c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
1079d8e10667624ea6411f04495aef1fa4a8a778ee8Alexander Gordeev	.vector_allocation_domain	= default_vector_allocation_domain,
10805c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.init_apic_ldr			= init_x2apic_ldr,
10905c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
11005c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.ioapic_phys_id_map		= NULL,
11105c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.setup_apic_routing		= NULL,
112a21769a4461801454930a06bc18bd8249cd9e993Ingo Molnar	.cpu_present_to_apicid		= default_cpu_present_to_apicid,
11305c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.apicid_to_cpu_present		= NULL,
114a27a621001f4c3e57caf47feff4b014577fd01c6Ingo Molnar	.check_phys_apicid_present	= default_check_phys_apicid_present,
115d4c9a9f3d416cfa1f5ffbe09d864d069467fe693Ingo Molnar	.phys_pkg_id			= x2apic_phys_pkg_id,
11605c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
11779deb8e511bd6fc8e40add4da75b19df085d9453Cyrill Gorcunov	.get_apic_id			= x2apic_get_apic_id,
11879deb8e511bd6fc8e40add4da75b19df085d9453Cyrill Gorcunov	.set_apic_id			= x2apic_set_apic_id,
11905c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.apic_id_mask			= 0xFFFFFFFFu,
12005c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
1216398268d2bc454735f11e08705e858f9fdf5c750Alexander Gordeev	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,
12205c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
12305c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.send_IPI_mask			= x2apic_send_IPI_mask,
12405c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.send_IPI_mask_allbutself	= x2apic_send_IPI_mask_allbutself,
12505c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.send_IPI_allbutself		= x2apic_send_IPI_allbutself,
12605c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.send_IPI_all			= x2apic_send_IPI_all,
12705c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.send_IPI_self			= x2apic_send_IPI_self,
12805c155c235c757329ec89ad591516538ed8352c0Ingo Molnar
129465822cfc8cb850ba76046965cc7b6fd1f8c3d73David Rientjes	.wait_for_init_deassert		= false,
13005c155c235c757329ec89ad591516538ed8352c0Ingo Molnar	.inquire_remote_apic		= NULL,
131c1eeb2de41d7015678bdd412b48a5f071b84e29aYinghai Lu
132c1eeb2de41d7015678bdd412b48a5f071b84e29aYinghai Lu	.read				= native_apic_msr_read,
133c1eeb2de41d7015678bdd412b48a5f071b84e29aYinghai Lu	.write				= native_apic_msr_write,
1340ab711ae6ab0db7696b43c74f9ba9de4d7fc1debMichael S. Tsirkin	.eoi_write			= native_apic_msr_eoi_write,
135c1eeb2de41d7015678bdd412b48a5f071b84e29aYinghai Lu	.icr_read			= native_x2apic_icr_read,
136c1eeb2de41d7015678bdd412b48a5f071b84e29aYinghai Lu	.icr_write			= native_x2apic_icr_write,
137c1eeb2de41d7015678bdd412b48a5f071b84e29aYinghai Lu	.wait_icr_idle			= native_x2apic_wait_icr_idle,
138c1eeb2de41d7015678bdd412b48a5f071b84e29aYinghai Lu	.safe_wait_icr_idle		= native_safe_x2apic_wait_icr_idle,
1392d9579a124d746a3e0e0ba45e57d80800ee80807Suresh Siddha};
140107e0e0cd85beeee05af7ea374fda14d037ee500Suresh Siddha
141107e0e0cd85beeee05af7ea374fda14d037ee500Suresh Siddhaapic_driver(apic_x2apic_phys);
142