18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * APIC driver for "bigsmp" xAPIC machines with more than 8 virtual CPUs. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Drives the local APIC in "clustered mode". 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 88c2ecf20Sopenharmony_ci#include <linux/dmi.h> 98c2ecf20Sopenharmony_ci#include <linux/smp.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <asm/apic.h> 128c2ecf20Sopenharmony_ci#include <asm/io_apic.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "local.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic unsigned bigsmp_get_apic_id(unsigned long x) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci return (x >> 24) & 0xFF; 198c2ecf20Sopenharmony_ci} 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int bigsmp_apic_id_registered(void) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci return 1; 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic bool bigsmp_check_apicid_used(physid_mask_t *map, int apicid) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci return false; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int bigsmp_early_logical_apicid(int cpu) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci /* on bigsmp, logical apicid is the same as physical */ 348c2ecf20Sopenharmony_ci return early_per_cpu(x86_cpu_to_apicid, cpu); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * bigsmp enables physical destination mode 398c2ecf20Sopenharmony_ci * and doesn't use LDR and DFR 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic void bigsmp_init_apic_ldr(void) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void bigsmp_setup_apic_routing(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci printk(KERN_INFO 488c2ecf20Sopenharmony_ci "Enabling APIC mode: Physflat. Using %d I/O APICs\n", 498c2ecf20Sopenharmony_ci nr_ioapics); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int bigsmp_cpu_present_to_apicid(int mps_cpu) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (mps_cpu < nr_cpu_ids) 558c2ecf20Sopenharmony_ci return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return BAD_APICID; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci /* For clustered we don't have a good way to do this yet - hack */ 638c2ecf20Sopenharmony_ci physids_promote(0xFFL, retmap); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int bigsmp_check_phys_apicid_present(int phys_apicid) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci return 1; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci return cpuid_apic >> index_msb; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic void bigsmp_send_IPI_allbutself(int vector) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic void bigsmp_send_IPI_all(int vector) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci default_send_IPI_mask_sequence_phys(cpu_online_mask, vector); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int dmi_bigsmp; /* can be set by dmi scanners */ 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int hp_ht_bigsmp(const struct dmi_system_id *d) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident); 918c2ecf20Sopenharmony_ci dmi_bigsmp = 1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const struct dmi_system_id bigsmp_dmi_table[] = { 988c2ecf20Sopenharmony_ci { hp_ht_bigsmp, "HP ProLiant DL760 G2", 998c2ecf20Sopenharmony_ci { DMI_MATCH(DMI_BIOS_VENDOR, "HP"), 1008c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_VERSION, "P44-"), 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci { hp_ht_bigsmp, "HP ProLiant DL740", 1058c2ecf20Sopenharmony_ci { DMI_MATCH(DMI_BIOS_VENDOR, "HP"), 1068c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_VERSION, "P47-"), 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci }, 1098c2ecf20Sopenharmony_ci { } /* NULL entry stops DMI scanning */ 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int probe_bigsmp(void) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci if (def_to_bigsmp) 1158c2ecf20Sopenharmony_ci dmi_bigsmp = 1; 1168c2ecf20Sopenharmony_ci else 1178c2ecf20Sopenharmony_ci dmi_check_system(bigsmp_dmi_table); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return dmi_bigsmp; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic struct apic apic_bigsmp __ro_after_init = { 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci .name = "bigsmp", 1258c2ecf20Sopenharmony_ci .probe = probe_bigsmp, 1268c2ecf20Sopenharmony_ci .acpi_madt_oem_check = NULL, 1278c2ecf20Sopenharmony_ci .apic_id_valid = default_apic_id_valid, 1288c2ecf20Sopenharmony_ci .apic_id_registered = bigsmp_apic_id_registered, 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci .irq_delivery_mode = dest_Fixed, 1318c2ecf20Sopenharmony_ci /* phys delivery to target CPU: */ 1328c2ecf20Sopenharmony_ci .irq_dest_mode = 0, 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci .disable_esr = 1, 1358c2ecf20Sopenharmony_ci .dest_logical = 0, 1368c2ecf20Sopenharmony_ci .check_apicid_used = bigsmp_check_apicid_used, 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci .init_apic_ldr = bigsmp_init_apic_ldr, 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci .ioapic_phys_id_map = bigsmp_ioapic_phys_id_map, 1418c2ecf20Sopenharmony_ci .setup_apic_routing = bigsmp_setup_apic_routing, 1428c2ecf20Sopenharmony_ci .cpu_present_to_apicid = bigsmp_cpu_present_to_apicid, 1438c2ecf20Sopenharmony_ci .apicid_to_cpu_present = physid_set_mask_of_physid, 1448c2ecf20Sopenharmony_ci .check_phys_apicid_present = bigsmp_check_phys_apicid_present, 1458c2ecf20Sopenharmony_ci .phys_pkg_id = bigsmp_phys_pkg_id, 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci .get_apic_id = bigsmp_get_apic_id, 1488c2ecf20Sopenharmony_ci .set_apic_id = NULL, 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci .calc_dest_apicid = apic_default_calc_apicid, 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci .send_IPI = default_send_IPI_single_phys, 1538c2ecf20Sopenharmony_ci .send_IPI_mask = default_send_IPI_mask_sequence_phys, 1548c2ecf20Sopenharmony_ci .send_IPI_mask_allbutself = NULL, 1558c2ecf20Sopenharmony_ci .send_IPI_allbutself = bigsmp_send_IPI_allbutself, 1568c2ecf20Sopenharmony_ci .send_IPI_all = bigsmp_send_IPI_all, 1578c2ecf20Sopenharmony_ci .send_IPI_self = default_send_IPI_self, 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci .inquire_remote_apic = default_inquire_remote_apic, 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci .read = native_apic_mem_read, 1628c2ecf20Sopenharmony_ci .write = native_apic_mem_write, 1638c2ecf20Sopenharmony_ci .eoi_write = native_apic_mem_write, 1648c2ecf20Sopenharmony_ci .icr_read = native_apic_icr_read, 1658c2ecf20Sopenharmony_ci .icr_write = native_apic_icr_write, 1668c2ecf20Sopenharmony_ci .wait_icr_idle = native_apic_wait_icr_idle, 1678c2ecf20Sopenharmony_ci .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci .x86_32_early_logical_apicid = bigsmp_early_logical_apicid, 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_civoid __init generic_bigsmp_probe(void) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci unsigned int cpu; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (!probe_bigsmp()) 1778c2ecf20Sopenharmony_ci return; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci apic = &apic_bigsmp; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 1828c2ecf20Sopenharmony_ci if (early_per_cpu(x86_cpu_to_logical_apicid, 1838c2ecf20Sopenharmony_ci cpu) == BAD_APICID) 1848c2ecf20Sopenharmony_ci continue; 1858c2ecf20Sopenharmony_ci early_per_cpu(x86_cpu_to_logical_apicid, cpu) = 1868c2ecf20Sopenharmony_ci bigsmp_early_logical_apicid(cpu); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci pr_info("Overriding APIC driver with %s\n", apic_bigsmp.name); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ciapic_driver(apic_bigsmp); 193