linux/arch/x86/kernel/apic/apic_flat_64.c
<<
>>
Prefs
   1/*
   2 * Copyright 2004 James Cleverdon, IBM.
   3 * Subject to the GNU Public License, v.2
   4 *
   5 * Flat APIC subarch code.
   6 *
   7 * Hacked for x86-64 by James Cleverdon from i386 architecture code by
   8 * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
   9 * James Cleverdon.
  10 */
  11#include <linux/errno.h>
  12#include <linux/threads.h>
  13#include <linux/cpumask.h>
  14#include <linux/string.h>
  15#include <linux/kernel.h>
  16#include <linux/ctype.h>
  17#include <linux/hardirq.h>
  18#include <linux/module.h>
  19#include <asm/smp.h>
  20#include <asm/apic.h>
  21#include <asm/ipi.h>
  22
  23#ifdef CONFIG_ACPI
  24#include <acpi/acpi_bus.h>
  25#endif
  26
  27static struct apic apic_physflat;
  28static struct apic apic_flat;
  29
  30struct apic __read_mostly *apic = &apic_flat;
  31EXPORT_SYMBOL_GPL(apic);
  32
  33static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  34{
  35        return 1;
  36}
  37
  38/*
  39 * Set up the logical destination ID.
  40 *
  41 * Intel recommends to set DFR, LDR and TPR before enabling
  42 * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
  43 * document number 292116).  So here it goes...
  44 */
  45void flat_init_apic_ldr(void)
  46{
  47        unsigned long val;
  48        unsigned long num, id;
  49
  50        num = smp_processor_id();
  51        id = 1UL << num;
  52        apic_write(APIC_DFR, APIC_DFR_FLAT);
  53        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
  54        val |= SET_APIC_LOGICAL_ID(id);
  55        apic_write(APIC_LDR, val);
  56}
  57
  58static inline void _flat_send_IPI_mask(unsigned long mask, int vector)
  59{
  60        unsigned long flags;
  61
  62        local_irq_save(flags);
  63        __default_send_IPI_dest_field(mask, vector, apic->dest_logical);
  64        local_irq_restore(flags);
  65}
  66
  67static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)
  68{
  69        unsigned long mask = cpumask_bits(cpumask)[0];
  70
  71        _flat_send_IPI_mask(mask, vector);
  72}
  73
  74static void
  75flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
  76{
  77        unsigned long mask = cpumask_bits(cpumask)[0];
  78        int cpu = smp_processor_id();
  79
  80        if (cpu < BITS_PER_LONG)
  81                clear_bit(cpu, &mask);
  82
  83        _flat_send_IPI_mask(mask, vector);
  84}
  85
  86static void flat_send_IPI_allbutself(int vector)
  87{
  88        int cpu = smp_processor_id();
  89#ifdef  CONFIG_HOTPLUG_CPU
  90        int hotplug = 1;
  91#else
  92        int hotplug = 0;
  93#endif
  94        if (hotplug || vector == NMI_VECTOR) {
  95                if (!cpumask_equal(cpu_online_mask, cpumask_of(cpu))) {
  96                        unsigned long mask = cpumask_bits(cpu_online_mask)[0];
  97
  98                        if (cpu < BITS_PER_LONG)
  99                                clear_bit(cpu, &mask);
 100
 101                        _flat_send_IPI_mask(mask, vector);
 102                }
 103        } else if (num_online_cpus() > 1) {
 104                __default_send_IPI_shortcut(APIC_DEST_ALLBUT,
 105                                            vector, apic->dest_logical);
 106        }
 107}
 108
 109static void flat_send_IPI_all(int vector)
 110{
 111        if (vector == NMI_VECTOR) {
 112                flat_send_IPI_mask(cpu_online_mask, vector);
 113        } else {
 114                __default_send_IPI_shortcut(APIC_DEST_ALLINC,
 115                                            vector, apic->dest_logical);
 116        }
 117}
 118
 119static unsigned int flat_get_apic_id(unsigned long x)
 120{
 121        unsigned int id;
 122
 123        id = (((x)>>24) & 0xFFu);
 124
 125        return id;
 126}
 127
 128static unsigned long set_apic_id(unsigned int id)
 129{
 130        unsigned long x;
 131
 132        x = ((id & 0xFFu)<<24);
 133        return x;
 134}
 135
 136static unsigned int read_xapic_id(void)
 137{
 138        unsigned int id;
 139
 140        id = flat_get_apic_id(apic_read(APIC_ID));
 141        return id;
 142}
 143
 144static int flat_apic_id_registered(void)
 145{
 146        return physid_isset(read_xapic_id(), phys_cpu_present_map);
 147}
 148
 149static int flat_phys_pkg_id(int initial_apic_id, int index_msb)
 150{
 151        return initial_apic_id >> index_msb;
 152}
 153
 154static int flat_probe(void)
 155{
 156        return 1;
 157}
 158
 159static struct apic apic_flat =  {
 160        .name                           = "flat",
 161        .probe                          = flat_probe,
 162        .acpi_madt_oem_check            = flat_acpi_madt_oem_check,
 163        .apic_id_valid                  = default_apic_id_valid,
 164        .apic_id_registered             = flat_apic_id_registered,
 165
 166        .irq_delivery_mode              = dest_LowestPrio,
 167        .irq_dest_mode                  = 1, /* logical */
 168
 169        .target_cpus                    = online_target_cpus,
 170        .disable_esr                    = 0,
 171        .dest_logical                   = APIC_DEST_LOGICAL,
 172        .check_apicid_used              = NULL,
 173        .check_apicid_present           = NULL,
 174
 175        .vector_allocation_domain       = flat_vector_allocation_domain,
 176        .init_apic_ldr                  = flat_init_apic_ldr,
 177
 178        .ioapic_phys_id_map             = NULL,
 179        .setup_apic_routing             = NULL,
 180        .multi_timer_check              = NULL,
 181        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 182        .apicid_to_cpu_present          = NULL,
 183        .setup_portio_remap             = NULL,
 184        .check_phys_apicid_present      = default_check_phys_apicid_present,
 185        .enable_apic_mode               = NULL,
 186        .phys_pkg_id                    = flat_phys_pkg_id,
 187        .mps_oem_check                  = NULL,
 188
 189        .get_apic_id                    = flat_get_apic_id,
 190        .set_apic_id                    = set_apic_id,
 191        .apic_id_mask                   = 0xFFu << 24,
 192
 193        .cpu_mask_to_apicid_and         = flat_cpu_mask_to_apicid_and,
 194
 195        .send_IPI_mask                  = flat_send_IPI_mask,
 196        .send_IPI_mask_allbutself       = flat_send_IPI_mask_allbutself,
 197        .send_IPI_allbutself            = flat_send_IPI_allbutself,
 198        .send_IPI_all                   = flat_send_IPI_all,
 199        .send_IPI_self                  = apic_send_IPI_self,
 200
 201        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
 202        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
 203        .wait_for_init_deassert         = NULL,
 204        .smp_callin_clear_local_apic    = NULL,
 205        .inquire_remote_apic            = default_inquire_remote_apic,
 206
 207        .read                           = native_apic_mem_read,
 208        .write                          = native_apic_mem_write,
 209        .eoi_write                      = native_apic_mem_write,
 210        .icr_read                       = native_apic_icr_read,
 211        .icr_write                      = native_apic_icr_write,
 212        .wait_icr_idle                  = native_apic_wait_icr_idle,
 213        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 214};
 215
 216/*
 217 * Physflat mode is used when there are more than 8 CPUs on a system.
 218 * We cannot use logical delivery in this case because the mask
 219 * overflows, so use physical mode.
 220 */
 221static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 222{
 223#ifdef CONFIG_ACPI
 224        /*
 225         * Quirk: some x86_64 machines can only use physical APIC mode
 226         * regardless of how many processors are present (x86_64 ES7000
 227         * is an example).
 228         */
 229        if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
 230                (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
 231                printk(KERN_DEBUG "system APIC only can use physical flat");
 232                return 1;
 233        }
 234
 235        if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) {
 236                printk(KERN_DEBUG "IBM Summit detected, will use apic physical");
 237                return 1;
 238        }
 239#endif
 240
 241        return 0;
 242}
 243
 244static void physflat_send_IPI_mask(const struct cpumask *cpumask, int vector)
 245{
 246        default_send_IPI_mask_sequence_phys(cpumask, vector);
 247}
 248
 249static void physflat_send_IPI_mask_allbutself(const struct cpumask *cpumask,
 250                                              int vector)
 251{
 252        default_send_IPI_mask_allbutself_phys(cpumask, vector);
 253}
 254
 255static void physflat_send_IPI_allbutself(int vector)
 256{
 257        default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
 258}
 259
 260static void physflat_send_IPI_all(int vector)
 261{
 262        physflat_send_IPI_mask(cpu_online_mask, vector);
 263}
 264
 265static int physflat_probe(void)
 266{
 267        if (apic == &apic_physflat || num_possible_cpus() > 8)
 268                return 1;
 269
 270        return 0;
 271}
 272
 273static struct apic apic_physflat =  {
 274
 275        .name                           = "physical flat",
 276        .probe                          = physflat_probe,
 277        .acpi_madt_oem_check            = physflat_acpi_madt_oem_check,
 278        .apic_id_valid                  = default_apic_id_valid,
 279        .apic_id_registered             = flat_apic_id_registered,
 280
 281        .irq_delivery_mode              = dest_Fixed,
 282        .irq_dest_mode                  = 0, /* physical */
 283
 284        .target_cpus                    = online_target_cpus,
 285        .disable_esr                    = 0,
 286        .dest_logical                   = 0,
 287        .check_apicid_used              = NULL,
 288        .check_apicid_present           = NULL,
 289
 290        .vector_allocation_domain       = default_vector_allocation_domain,
 291        /* not needed, but shouldn't hurt: */
 292        .init_apic_ldr                  = flat_init_apic_ldr,
 293
 294        .ioapic_phys_id_map             = NULL,
 295        .setup_apic_routing             = NULL,
 296        .multi_timer_check              = NULL,
 297        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 298        .apicid_to_cpu_present          = NULL,
 299        .setup_portio_remap             = NULL,
 300        .check_phys_apicid_present      = default_check_phys_apicid_present,
 301        .enable_apic_mode               = NULL,
 302        .phys_pkg_id                    = flat_phys_pkg_id,
 303        .mps_oem_check                  = NULL,
 304
 305        .get_apic_id                    = flat_get_apic_id,
 306        .set_apic_id                    = set_apic_id,
 307        .apic_id_mask                   = 0xFFu << 24,
 308
 309        .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 310
 311        .send_IPI_mask                  = physflat_send_IPI_mask,
 312        .send_IPI_mask_allbutself       = physflat_send_IPI_mask_allbutself,
 313        .send_IPI_allbutself            = physflat_send_IPI_allbutself,
 314        .send_IPI_all                   = physflat_send_IPI_all,
 315        .send_IPI_self                  = apic_send_IPI_self,
 316
 317        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
 318        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
 319        .wait_for_init_deassert         = NULL,
 320        .smp_callin_clear_local_apic    = NULL,
 321        .inquire_remote_apic            = default_inquire_remote_apic,
 322
 323        .read                           = native_apic_mem_read,
 324        .write                          = native_apic_mem_write,
 325        .eoi_write                      = native_apic_mem_write,
 326        .icr_read                       = native_apic_icr_read,
 327        .icr_write                      = native_apic_icr_write,
 328        .wait_icr_idle                  = native_apic_wait_icr_idle,
 329        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 330};
 331
 332/*
 333 * We need to check for physflat first, so this order is important.
 334 */
 335apic_drivers(apic_physflat, apic_flat);
 336