Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * APIC driver for "bigsmp" xAPIC machines with more than 8 virtual CPUs.
0004  *
0005  * Drives the local APIC in "clustered mode".
0006  */
0007 #include <linux/cpumask.h>
0008 #include <linux/dmi.h>
0009 #include <linux/smp.h>
0010 
0011 #include <asm/apic.h>
0012 #include <asm/io_apic.h>
0013 
0014 #include "local.h"
0015 
0016 static unsigned bigsmp_get_apic_id(unsigned long x)
0017 {
0018     return (x >> 24) & 0xFF;
0019 }
0020 
0021 static int bigsmp_apic_id_registered(void)
0022 {
0023     return 1;
0024 }
0025 
0026 static bool bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
0027 {
0028     return false;
0029 }
0030 
0031 static int bigsmp_early_logical_apicid(int cpu)
0032 {
0033     /* on bigsmp, logical apicid is the same as physical */
0034     return early_per_cpu(x86_cpu_to_apicid, cpu);
0035 }
0036 
0037 /*
0038  * bigsmp enables physical destination mode
0039  * and doesn't use LDR and DFR
0040  */
0041 static void bigsmp_init_apic_ldr(void)
0042 {
0043 }
0044 
0045 static void bigsmp_setup_apic_routing(void)
0046 {
0047     printk(KERN_INFO
0048         "Enabling APIC mode:  Physflat.  Using %d I/O APICs\n",
0049         nr_ioapics);
0050 }
0051 
0052 static int bigsmp_cpu_present_to_apicid(int mps_cpu)
0053 {
0054     if (mps_cpu < nr_cpu_ids)
0055         return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
0056 
0057     return BAD_APICID;
0058 }
0059 
0060 static void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
0061 {
0062     /* For clustered we don't have a good way to do this yet - hack */
0063     physids_promote(0xFFL, retmap);
0064 }
0065 
0066 static int bigsmp_check_phys_apicid_present(int phys_apicid)
0067 {
0068     return 1;
0069 }
0070 
0071 static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
0072 {
0073     return cpuid_apic >> index_msb;
0074 }
0075 
0076 static void bigsmp_send_IPI_allbutself(int vector)
0077 {
0078     default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
0079 }
0080 
0081 static void bigsmp_send_IPI_all(int vector)
0082 {
0083     default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
0084 }
0085 
0086 static int dmi_bigsmp; /* can be set by dmi scanners */
0087 
0088 static int hp_ht_bigsmp(const struct dmi_system_id *d)
0089 {
0090     printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident);
0091     dmi_bigsmp = 1;
0092 
0093     return 0;
0094 }
0095 
0096 
0097 static const struct dmi_system_id bigsmp_dmi_table[] = {
0098     { hp_ht_bigsmp, "HP ProLiant DL760 G2",
0099         {   DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
0100             DMI_MATCH(DMI_BIOS_VERSION, "P44-"),
0101         }
0102     },
0103 
0104     { hp_ht_bigsmp, "HP ProLiant DL740",
0105         {   DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
0106             DMI_MATCH(DMI_BIOS_VERSION, "P47-"),
0107         }
0108     },
0109     { } /* NULL entry stops DMI scanning */
0110 };
0111 
0112 static int probe_bigsmp(void)
0113 {
0114     if (def_to_bigsmp)
0115         dmi_bigsmp = 1;
0116     else
0117         dmi_check_system(bigsmp_dmi_table);
0118 
0119     return dmi_bigsmp;
0120 }
0121 
0122 static struct apic apic_bigsmp __ro_after_init = {
0123 
0124     .name               = "bigsmp",
0125     .probe              = probe_bigsmp,
0126     .acpi_madt_oem_check        = NULL,
0127     .apic_id_valid          = default_apic_id_valid,
0128     .apic_id_registered     = bigsmp_apic_id_registered,
0129 
0130     .delivery_mode          = APIC_DELIVERY_MODE_FIXED,
0131     .dest_mode_logical      = false,
0132 
0133     .disable_esr            = 1,
0134 
0135     .check_apicid_used      = bigsmp_check_apicid_used,
0136     .init_apic_ldr          = bigsmp_init_apic_ldr,
0137     .ioapic_phys_id_map     = bigsmp_ioapic_phys_id_map,
0138     .setup_apic_routing     = bigsmp_setup_apic_routing,
0139     .cpu_present_to_apicid      = bigsmp_cpu_present_to_apicid,
0140     .apicid_to_cpu_present      = physid_set_mask_of_physid,
0141     .check_phys_apicid_present  = bigsmp_check_phys_apicid_present,
0142     .phys_pkg_id            = bigsmp_phys_pkg_id,
0143 
0144     .get_apic_id            = bigsmp_get_apic_id,
0145     .set_apic_id            = NULL,
0146 
0147     .calc_dest_apicid       = apic_default_calc_apicid,
0148 
0149     .send_IPI           = default_send_IPI_single_phys,
0150     .send_IPI_mask          = default_send_IPI_mask_sequence_phys,
0151     .send_IPI_mask_allbutself   = NULL,
0152     .send_IPI_allbutself        = bigsmp_send_IPI_allbutself,
0153     .send_IPI_all           = bigsmp_send_IPI_all,
0154     .send_IPI_self          = default_send_IPI_self,
0155 
0156     .inquire_remote_apic        = default_inquire_remote_apic,
0157 
0158     .read               = native_apic_mem_read,
0159     .write              = native_apic_mem_write,
0160     .eoi_write          = native_apic_mem_write,
0161     .icr_read           = native_apic_icr_read,
0162     .icr_write          = native_apic_icr_write,
0163     .wait_icr_idle          = native_apic_wait_icr_idle,
0164     .safe_wait_icr_idle     = native_safe_apic_wait_icr_idle,
0165 
0166     .x86_32_early_logical_apicid    = bigsmp_early_logical_apicid,
0167 };
0168 
0169 void __init generic_bigsmp_probe(void)
0170 {
0171     unsigned int cpu;
0172 
0173     if (!probe_bigsmp())
0174         return;
0175 
0176     apic = &apic_bigsmp;
0177 
0178     for_each_possible_cpu(cpu) {
0179         if (early_per_cpu(x86_cpu_to_logical_apicid,
0180                   cpu) == BAD_APICID)
0181             continue;
0182         early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
0183             bigsmp_early_logical_apicid(cpu);
0184     }
0185 
0186     pr_info("Overriding APIC driver with %s\n", apic_bigsmp.name);
0187 }
0188 
0189 apic_driver(apic_bigsmp);