linux/arch/x86/kernel/genapic_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/init.h>
  18#include <linux/hardirq.h>
  19#include <asm/smp.h>
  20#include <asm/ipi.h>
  21#include <asm/genapic.h>
  22#include <mach_apicdef.h>
  23
  24#ifdef CONFIG_ACPI
  25#include <acpi/acpi_bus.h>
  26#endif
  27
  28static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  29{
  30        return 1;
  31}
  32
  33static cpumask_t flat_target_cpus(void)
  34{
  35        return cpu_online_map;
  36}
  37
  38static cpumask_t flat_vector_allocation_domain(int cpu)
  39{
  40        /* Careful. Some cpus do not strictly honor the set of cpus
  41         * specified in the interrupt destination when using lowest
  42         * priority interrupt delivery mode.
  43         *
  44         * In particular there was a hyperthreading cpu observed to
  45         * deliver interrupts to the wrong hyperthread when only one
  46         * hyperthread was specified in the interrupt desitination.
  47         */
  48        cpumask_t domain = { { [0] = APIC_ALL_CPUS, } };
  49        return domain;
  50}
  51
  52/*
  53 * Set up the logical destination ID.
  54 *
  55 * Intel recommends to set DFR, LDR and TPR before enabling
  56 * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
  57 * document number 292116).  So here it goes...
  58 */
  59static void flat_init_apic_ldr(void)
  60{
  61        unsigned long val;
  62        unsigned long num, id;
  63
  64        num = smp_processor_id();
  65        id = 1UL << num;
  66        apic_write(APIC_DFR, APIC_DFR_FLAT);
  67        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
  68        val |= SET_APIC_LOGICAL_ID(id);
  69        apic_write(APIC_LDR, val);
  70}
  71
  72static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
  73{
  74        unsigned long mask = cpus_addr(cpumask)[0];
  75        unsigned long flags;
  76
  77        local_irq_save(flags);
  78        __send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
  79        local_irq_restore(flags);
  80}
  81
  82static void flat_send_IPI_allbutself(int vector)
  83{
  84#ifdef  CONFIG_HOTPLUG_CPU
  85        int hotplug = 1;
  86#else
  87        int hotplug = 0;
  88#endif
  89        if (hotplug || vector == NMI_VECTOR) {
  90                cpumask_t allbutme = cpu_online_map;
  91
  92                cpu_clear(smp_processor_id(), allbutme);
  93
  94                if (!cpus_empty(allbutme))
  95                        flat_send_IPI_mask(allbutme, vector);
  96        } else if (num_online_cpus() > 1) {
  97                __send_IPI_shortcut(APIC_DEST_ALLBUT, vector,APIC_DEST_LOGICAL);
  98        }
  99}
 100
 101static void flat_send_IPI_all(int vector)
 102{
 103        if (vector == NMI_VECTOR)
 104                flat_send_IPI_mask(cpu_online_map, vector);
 105        else
 106                __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
 107}
 108
 109static unsigned int get_apic_id(unsigned long x)
 110{
 111        unsigned int id;
 112
 113        id = (((x)>>24) & 0xFFu);
 114        return id;
 115}
 116
 117static unsigned long set_apic_id(unsigned int id)
 118{
 119        unsigned long x;
 120
 121        x = ((id & 0xFFu)<<24);
 122        return x;
 123}
 124
 125static unsigned int read_xapic_id(void)
 126{
 127        unsigned int id;
 128
 129        id = get_apic_id(apic_read(APIC_ID));
 130        return id;
 131}
 132
 133static int flat_apic_id_registered(void)
 134{
 135        return physid_isset(read_xapic_id(), phys_cpu_present_map);
 136}
 137
 138static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask)
 139{
 140        return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
 141}
 142
 143static unsigned int phys_pkg_id(int index_msb)
 144{
 145        return hard_smp_processor_id() >> index_msb;
 146}
 147
 148struct genapic apic_flat =  {
 149        .name = "flat",
 150        .acpi_madt_oem_check = flat_acpi_madt_oem_check,
 151        .int_delivery_mode = dest_LowestPrio,
 152        .int_dest_mode = (APIC_DEST_LOGICAL != 0),
 153        .target_cpus = flat_target_cpus,
 154        .vector_allocation_domain = flat_vector_allocation_domain,
 155        .apic_id_registered = flat_apic_id_registered,
 156        .init_apic_ldr = flat_init_apic_ldr,
 157        .send_IPI_all = flat_send_IPI_all,
 158        .send_IPI_allbutself = flat_send_IPI_allbutself,
 159        .send_IPI_mask = flat_send_IPI_mask,
 160        .send_IPI_self = apic_send_IPI_self,
 161        .cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
 162        .phys_pkg_id = phys_pkg_id,
 163        .get_apic_id = get_apic_id,
 164        .set_apic_id = set_apic_id,
 165        .apic_id_mask = (0xFFu<<24),
 166};
 167
 168/*
 169 * Physflat mode is used when there are more than 8 CPUs on a AMD system.
 170 * We cannot use logical delivery in this case because the mask
 171 * overflows, so use physical mode.
 172 */
 173static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 174{
 175#ifdef CONFIG_ACPI
 176        /*
 177         * Quirk: some x86_64 machines can only use physical APIC mode
 178         * regardless of how many processors are present (x86_64 ES7000
 179         * is an example).
 180         */
 181        if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
 182                (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
 183                printk(KERN_DEBUG "system APIC only can use physical flat");
 184                return 1;
 185        }
 186#endif
 187
 188        return 0;
 189}
 190
 191static cpumask_t physflat_target_cpus(void)
 192{
 193        return cpu_online_map;
 194}
 195
 196static cpumask_t physflat_vector_allocation_domain(int cpu)
 197{
 198        return cpumask_of_cpu(cpu);
 199}
 200
 201static void physflat_send_IPI_mask(cpumask_t cpumask, int vector)
 202{
 203        send_IPI_mask_sequence(cpumask, vector);
 204}
 205
 206static void physflat_send_IPI_allbutself(int vector)
 207{
 208        cpumask_t allbutme = cpu_online_map;
 209
 210        cpu_clear(smp_processor_id(), allbutme);
 211        physflat_send_IPI_mask(allbutme, vector);
 212}
 213
 214static void physflat_send_IPI_all(int vector)
 215{
 216        physflat_send_IPI_mask(cpu_online_map, vector);
 217}
 218
 219static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask)
 220{
 221        int cpu;
 222
 223        /*
 224         * We're using fixed IRQ delivery, can only return one phys APIC ID.
 225         * May as well be the first.
 226         */
 227        cpu = first_cpu(cpumask);
 228        if ((unsigned)cpu < nr_cpu_ids)
 229                return per_cpu(x86_cpu_to_apicid, cpu);
 230        else
 231                return BAD_APICID;
 232}
 233
 234struct genapic apic_physflat =  {
 235        .name = "physical flat",
 236        .acpi_madt_oem_check = physflat_acpi_madt_oem_check,
 237        .int_delivery_mode = dest_Fixed,
 238        .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
 239        .target_cpus = physflat_target_cpus,
 240        .vector_allocation_domain = physflat_vector_allocation_domain,
 241        .apic_id_registered = flat_apic_id_registered,
 242        .init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/
 243        .send_IPI_all = physflat_send_IPI_all,
 244        .send_IPI_allbutself = physflat_send_IPI_allbutself,
 245        .send_IPI_mask = physflat_send_IPI_mask,
 246        .send_IPI_self = apic_send_IPI_self,
 247        .cpu_mask_to_apicid = physflat_cpu_mask_to_apicid,
 248        .phys_pkg_id = phys_pkg_id,
 249        .get_apic_id = get_apic_id,
 250        .set_apic_id = set_apic_id,
 251        .apic_id_mask = (0xFFu<<24),
 252};
 253
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.