linux/arch/x86/kernel/apic/x2apic_cluster.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/threads.h>
   3#include <linux/cpumask.h>
   4#include <linux/string.h>
   5#include <linux/kernel.h>
   6#include <linux/ctype.h>
   7#include <linux/dmar.h>
   8#include <linux/irq.h>
   9#include <linux/cpu.h>
  10
  11#include <asm/smp.h>
  12#include "x2apic.h"
  13
  14struct cluster_mask {
  15        unsigned int    clusterid;
  16        int             node;
  17        struct cpumask  mask;
  18};
  19
  20static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
  21static DEFINE_PER_CPU(cpumask_var_t, ipi_mask);
  22static DEFINE_PER_CPU(struct cluster_mask *, cluster_masks);
  23static struct cluster_mask *cluster_hotplug_mask;
  24
  25static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  26{
  27        return x2apic_enabled();
  28}
  29
  30static void x2apic_send_IPI(int cpu, int vector)
  31{
  32        u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
  33
  34        x2apic_wrmsr_fence();
  35        __x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
  36}
  37
  38static void
  39__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
  40{
  41        unsigned int cpu, clustercpu;
  42        struct cpumask *tmpmsk;
  43        unsigned long flags;
  44        u32 dest;
  45
  46        x2apic_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_mask(cpu_online_mask, vector, APIC_DEST_ALLBUT);
  88}
  89
  90static void x2apic_send_IPI_all(int vector)
  91{
  92        __x2apic_send_IPI_mask(cpu_online_mask, 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        cpumask_clear_cpu(dead_cpu, &cmsk->mask);
 162        free_cpumask_var(per_cpu(ipi_mask, dead_cpu));
 163        return 0;
 164}
 165
 166static int x2apic_cluster_probe(void)
 167{
 168        if (!x2apic_mode)
 169                return 0;
 170
 171        if (cpuhp_setup_state(CPUHP_X2APIC_PREPARE, "x86/x2apic:prepare",
 172                              x2apic_prepare_cpu, x2apic_dead_cpu) < 0) {
 173                pr_err("Failed to register X2APIC_PREPARE\n");
 174                return 0;
 175        }
 176        init_x2apic_ldr();
 177        return 1;
 178}
 179
 180static struct apic apic_x2apic_cluster __ro_after_init = {
 181
 182        .name                           = "cluster x2apic",
 183        .probe                          = x2apic_cluster_probe,
 184        .acpi_madt_oem_check            = x2apic_acpi_madt_oem_check,
 185        .apic_id_valid                  = x2apic_apic_id_valid,
 186        .apic_id_registered             = x2apic_apic_id_registered,
 187
 188        .irq_delivery_mode              = dest_Fixed,
 189        .irq_dest_mode                  = 1, /* logical */
 190
 191        .disable_esr                    = 0,
 192        .dest_logical                   = APIC_DEST_LOGICAL,
 193        .check_apicid_used              = NULL,
 194
 195        .init_apic_ldr                  = init_x2apic_ldr,
 196
 197        .ioapic_phys_id_map             = NULL,
 198        .setup_apic_routing             = NULL,
 199        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 200        .apicid_to_cpu_present          = NULL,
 201        .check_phys_apicid_present      = default_check_phys_apicid_present,
 202        .phys_pkg_id                    = x2apic_phys_pkg_id,
 203
 204        .get_apic_id                    = x2apic_get_apic_id,
 205        .set_apic_id                    = x2apic_set_apic_id,
 206
 207        .calc_dest_apicid               = x2apic_calc_apicid,
 208
 209        .send_IPI                       = x2apic_send_IPI,
 210        .send_IPI_mask                  = x2apic_send_IPI_mask,
 211        .send_IPI_mask_allbutself       = x2apic_send_IPI_mask_allbutself,
 212        .send_IPI_allbutself            = x2apic_send_IPI_allbutself,
 213        .send_IPI_all                   = x2apic_send_IPI_all,
 214        .send_IPI_self                  = x2apic_send_IPI_self,
 215
 216        .inquire_remote_apic            = NULL,
 217
 218        .read                           = native_apic_msr_read,
 219        .write                          = native_apic_msr_write,
 220        .eoi_write                      = native_apic_msr_eoi_write,
 221        .icr_read                       = native_x2apic_icr_read,
 222        .icr_write                      = native_x2apic_icr_write,
 223        .wait_icr_idle                  = native_x2apic_wait_icr_idle,
 224        .safe_wait_icr_idle             = native_safe_x2apic_wait_icr_idle,
 225};
 226
 227apic_driver(apic_x2apic_cluster);
 228