linux/arch/x86/kernel/apic/x2apic_cluster.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <linux/cpuhotplug.h>
   4#include <linux/cpumask.h>
   5#include <linux/slab.h>
   6#include <linux/mm.h>
   7
   8#include <asm/apic.h>
   9
  10#include "local.h"
  11
  12struct cluster_mask {
  13        unsigned int    clusterid;
  14        int             node;
  15        struct cpumask  mask;
  16};
  17
  18static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
  19static DEFINE_PER_CPU(cpumask_var_t, ipi_mask);
  20static DEFINE_PER_CPU(struct cluster_mask *, cluster_masks);
  21static struct cluster_mask *cluster_hotplug_mask;
  22
  23static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  24{
  25        return x2apic_enabled();
  26}
  27
  28static void x2apic_send_IPI(int cpu, int vector)
  29{
  30        u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
  31
  32        /* x2apic MSRs are special and need a special fence: */
  33        weak_wrmsr_fence();
  34        __x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
  35}
  36
  37static void
  38__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
  39{
  40        unsigned int cpu, clustercpu;
  41        struct cpumask *tmpmsk;
  42        unsigned long flags;
  43        u32 dest;
  44
  45        /* x2apic MSRs are special and need a special fence: */
  46        weak_wrmsr_fence();
  47        local_irq_save(flags);
  48
  49        tmpmsk = this_cpu_cpumask_var_ptr(ipi_mask);
  50        cpumask_copy(tmpmsk, mask);
  51        /* If IPI should not be sent to self, clear current CPU */
  52        if (apic_dest != APIC_DEST_ALLINC)
  53                __cpumask_clear_cpu(smp_processor_id(), tmpmsk);
  54
  55        /* Collapse cpus in a cluster so a single IPI per cluster is sent */
  56        for_each_cpu(cpu, tmpmsk) {
  57                struct cluster_mask *cmsk = per_cpu(cluster_masks, cpu);
  58
  59                dest = 0;
  60                for_each_cpu_and(clustercpu, tmpmsk, &cmsk->mask)
  61                        dest |= per_cpu(x86_cpu_to_logical_apicid, clustercpu);
  62
  63                if (!dest)
  64                        continue;
  65
  66                __x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
  67                /* Remove cluster CPUs from tmpmask */
  68                cpumask_andnot(tmpmsk, tmpmsk, &cmsk->mask);
  69        }
  70
  71        local_irq_restore(flags);
  72}
  73
  74static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
  75{
  76        __x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLINC);
  77}
  78
  79static void
  80x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
  81{
  82        __x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);
  83}
  84
  85static void x2apic_send_IPI_allbutself(int vector)
  86{
  87        __x2apic_send_IPI_shorthand(vector, APIC_DEST_ALLBUT);
  88}
  89
  90static void x2apic_send_IPI_all(int vector)
  91{
  92        __x2apic_send_IPI_shorthand(vector, APIC_DEST_ALLINC);
  93}
  94
  95static u32 x2apic_calc_apicid(unsigned int cpu)
  96{
  97        return per_cpu(x86_cpu_to_logical_apicid, cpu);
  98}
  99
 100static void init_x2apic_ldr(void)
 101{
 102        struct cluster_mask *cmsk = this_cpu_read(cluster_masks);
 103        u32 cluster, apicid = apic_read(APIC_LDR);
 104        unsigned int cpu;
 105
 106        this_cpu_write(x86_cpu_to_logical_apicid, apicid);
 107
 108        if (cmsk)
 109                goto update;
 110
 111        cluster = apicid >> 16;
 112        for_each_online_cpu(cpu) {
 113                cmsk = per_cpu(cluster_masks, cpu);
 114                /* Matching cluster found. Link and update it. */
 115                if (cmsk && cmsk->clusterid == cluster)
 116                        goto update;
 117        }
 118        cmsk = cluster_hotplug_mask;
 119        cmsk->clusterid = cluster;
 120        cluster_hotplug_mask = NULL;
 121update:
 122        this_cpu_write(cluster_masks, cmsk);
 123        cpumask_set_cpu(smp_processor_id(), &cmsk->mask);
 124}
 125
 126static int alloc_clustermask(unsigned int cpu, int node)
 127{
 128        if (per_cpu(cluster_masks, cpu))
 129                return 0;
 130        /*
 131         * If a hotplug spare mask exists, check whether it's on the right
 132         * node. If not, free it and allocate a new one.
 133         */
 134        if (cluster_hotplug_mask) {
 135                if (cluster_hotplug_mask->node == node)
 136                        return 0;
 137                kfree(cluster_hotplug_mask);
 138        }
 139
 140        cluster_hotplug_mask = kzalloc_node(sizeof(*cluster_hotplug_mask),
 141                                            GFP_KERNEL, node);
 142        if (!cluster_hotplug_mask)
 143                return -ENOMEM;
 144        cluster_hotplug_mask->node = node;
 145        return 0;
 146}
 147
 148static int x2apic_prepare_cpu(unsigned int cpu)
 149{
 150        if (alloc_clustermask(cpu, cpu_to_node(cpu)) < 0)
 151                return -ENOMEM;
 152        if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL))
 153                return -ENOMEM;
 154        return 0;
 155}
 156
 157static int x2apic_dead_cpu(unsigned int dead_cpu)
 158{
 159        struct cluster_mask *cmsk = per_cpu(cluster_masks, dead_cpu);
 160
 161        if (cmsk)
 162                cpumask_clear_cpu(dead_cpu, &cmsk->mask);
 163        free_cpumask_var(per_cpu(ipi_mask, dead_cpu));
 164        return 0;
 165}
 166
 167static int x2apic_cluster_probe(void)
 168{
 169        if (!x2apic_mode)
 170                return 0;
 171
 172        if (cpuhp_setup_state(CPUHP_X2APIC_PREPARE, "x86/x2apic:prepare",
 173                              x2apic_prepare_cpu, x2apic_dead_cpu) < 0) {
 174                pr_err("Failed to register X2APIC_PREPARE\n");
 175                return 0;
 176        }
 177        init_x2apic_ldr();
 178        return 1;
 179}
 180
 181static struct apic apic_x2apic_cluster __ro_after_init = {
 182
 183        .name                           = "cluster x2apic",
 184        .probe                          = x2apic_cluster_probe,
 185        .acpi_madt_oem_check            = x2apic_acpi_madt_oem_check,
 186        .apic_id_valid                  = x2apic_apic_id_valid,
 187        .apic_id_registered             = x2apic_apic_id_registered,
 188
 189        .delivery_mode                  = APIC_DELIVERY_MODE_FIXED,
 190        .dest_mode_logical              = true,
 191
 192        .disable_esr                    = 0,
 193
 194        .check_apicid_used              = NULL,
 195        .init_apic_ldr                  = init_x2apic_ldr,
 196        .ioapic_phys_id_map             = NULL,
 197        .setup_apic_routing             = NULL,
 198        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 199        .apicid_to_cpu_present          = NULL,
 200        .check_phys_apicid_present      = default_check_phys_apicid_present,
 201        .phys_pkg_id                    = x2apic_phys_pkg_id,
 202
 203        .get_apic_id                    = x2apic_get_apic_id,
 204        .set_apic_id                    = x2apic_set_apic_id,
 205
 206        .calc_dest_apicid               = x2apic_calc_apicid,
 207
 208        .send_IPI                       = x2apic_send_IPI,
 209        .send_IPI_mask                  = x2apic_send_IPI_mask,
 210        .send_IPI_mask_allbutself       = x2apic_send_IPI_mask_allbutself,
 211        .send_IPI_allbutself            = x2apic_send_IPI_allbutself,
 212        .send_IPI_all                   = x2apic_send_IPI_all,
 213        .send_IPI_self                  = x2apic_send_IPI_self,
 214
 215        .inquire_remote_apic            = NULL,
 216
 217        .read                           = native_apic_msr_read,
 218        .write                          = native_apic_msr_write,
 219        .eoi_write                      = native_apic_msr_eoi_write,
 220        .icr_read                       = native_x2apic_icr_read,
 221        .icr_write                      = native_x2apic_icr_write,
 222        .wait_icr_idle                  = native_x2apic_wait_icr_idle,
 223        .safe_wait_icr_idle             = native_safe_x2apic_wait_icr_idle,
 224};
 225
 226apic_driver(apic_x2apic_cluster);
 227