linux/arch/x86/kernel/apic/bigsmp_32.c
<<
>>
Prefs
   1/*
   2 * APIC driver for "bigsmp" xAPIC machines with more than 8 virtual CPUs.
   3 *
   4 * Drives the local APIC in "clustered mode".
   5 */
   6#include <linux/threads.h>
   7#include <linux/cpumask.h>
   8#include <linux/kernel.h>
   9#include <linux/init.h>
  10#include <linux/dmi.h>
  11#include <linux/smp.h>
  12
  13#include <asm/apicdef.h>
  14#include <asm/fixmap.h>
  15#include <asm/mpspec.h>
  16#include <asm/apic.h>
  17#include <asm/ipi.h>
  18
  19static unsigned bigsmp_get_apic_id(unsigned long x)
  20{
  21        return (x >> 24) & 0xFF;
  22}
  23
  24static int bigsmp_apic_id_registered(void)
  25{
  26        return 1;
  27}
  28
  29static unsigned long bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
  30{
  31        return 0;
  32}
  33
  34static unsigned long bigsmp_check_apicid_present(int bit)
  35{
  36        return 1;
  37}
  38
  39static int bigsmp_early_logical_apicid(int cpu)
  40{
  41        /* on bigsmp, logical apicid is the same as physical */
  42        return early_per_cpu(x86_cpu_to_apicid, cpu);
  43}
  44
  45static inline unsigned long calculate_ldr(int cpu)
  46{
  47        unsigned long val, id;
  48
  49        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
  50        id = per_cpu(x86_bios_cpu_apicid, cpu);
  51        val |= SET_APIC_LOGICAL_ID(id);
  52
  53        return val;
  54}
  55
  56/*
  57 * Set up the logical destination ID.
  58 *
  59 * Intel recommends to set DFR, LDR and TPR before enabling
  60 * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
  61 * document number 292116).  So here it goes...
  62 */
  63static void bigsmp_init_apic_ldr(void)
  64{
  65        unsigned long val;
  66        int cpu = smp_processor_id();
  67
  68        apic_write(APIC_DFR, APIC_DFR_FLAT);
  69        val = calculate_ldr(cpu);
  70        apic_write(APIC_LDR, val);
  71}
  72
  73static void bigsmp_setup_apic_routing(void)
  74{
  75        printk(KERN_INFO
  76                "Enabling APIC mode:  Physflat.  Using %d I/O APICs\n",
  77                nr_ioapics);
  78}
  79
  80static int bigsmp_cpu_present_to_apicid(int mps_cpu)
  81{
  82        if (mps_cpu < nr_cpu_ids)
  83                return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
  84
  85        return BAD_APICID;
  86}
  87
  88static void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
  89{
  90        /* For clustered we don't have a good way to do this yet - hack */
  91        physids_promote(0xFFL, retmap);
  92}
  93
  94static int bigsmp_check_phys_apicid_present(int phys_apicid)
  95{
  96        return 1;
  97}
  98
  99static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
 100{
 101        return cpuid_apic >> index_msb;
 102}
 103
 104static inline void bigsmp_send_IPI_mask(const struct cpumask *mask, int vector)
 105{
 106        default_send_IPI_mask_sequence_phys(mask, vector);
 107}
 108
 109static void bigsmp_send_IPI_allbutself(int vector)
 110{
 111        default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
 112}
 113
 114static void bigsmp_send_IPI_all(int vector)
 115{
 116        bigsmp_send_IPI_mask(cpu_online_mask, vector);
 117}
 118
 119static int dmi_bigsmp; /* can be set by dmi scanners */
 120
 121static int hp_ht_bigsmp(const struct dmi_system_id *d)
 122{
 123        printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident);
 124        dmi_bigsmp = 1;
 125
 126        return 0;
 127}
 128
 129
 130static const struct dmi_system_id bigsmp_dmi_table[] = {
 131        { hp_ht_bigsmp, "HP ProLiant DL760 G2",
 132                {       DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
 133                        DMI_MATCH(DMI_BIOS_VERSION, "P44-"),
 134                }
 135        },
 136
 137        { hp_ht_bigsmp, "HP ProLiant DL740",
 138                {       DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
 139                        DMI_MATCH(DMI_BIOS_VERSION, "P47-"),
 140                }
 141        },
 142        { } /* NULL entry stops DMI scanning */
 143};
 144
 145static int probe_bigsmp(void)
 146{
 147        if (def_to_bigsmp)
 148                dmi_bigsmp = 1;
 149        else
 150                dmi_check_system(bigsmp_dmi_table);
 151
 152        return dmi_bigsmp;
 153}
 154
 155static struct apic apic_bigsmp = {
 156
 157        .name                           = "bigsmp",
 158        .probe                          = probe_bigsmp,
 159        .acpi_madt_oem_check            = NULL,
 160        .apic_id_valid                  = default_apic_id_valid,
 161        .apic_id_registered             = bigsmp_apic_id_registered,
 162
 163        .irq_delivery_mode              = dest_Fixed,
 164        /* phys delivery to target CPU: */
 165        .irq_dest_mode                  = 0,
 166
 167        .target_cpus                    = default_target_cpus,
 168        .disable_esr                    = 1,
 169        .dest_logical                   = 0,
 170        .check_apicid_used              = bigsmp_check_apicid_used,
 171        .check_apicid_present           = bigsmp_check_apicid_present,
 172
 173        .vector_allocation_domain       = default_vector_allocation_domain,
 174        .init_apic_ldr                  = bigsmp_init_apic_ldr,
 175
 176        .ioapic_phys_id_map             = bigsmp_ioapic_phys_id_map,
 177        .setup_apic_routing             = bigsmp_setup_apic_routing,
 178        .multi_timer_check              = NULL,
 179        .cpu_present_to_apicid          = bigsmp_cpu_present_to_apicid,
 180        .apicid_to_cpu_present          = physid_set_mask_of_physid,
 181        .setup_portio_remap             = NULL,
 182        .check_phys_apicid_present      = bigsmp_check_phys_apicid_present,
 183        .enable_apic_mode               = NULL,
 184        .phys_pkg_id                    = bigsmp_phys_pkg_id,
 185        .mps_oem_check                  = NULL,
 186
 187        .get_apic_id                    = bigsmp_get_apic_id,
 188        .set_apic_id                    = NULL,
 189        .apic_id_mask                   = 0xFF << 24,
 190
 191        .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 192
 193        .send_IPI_mask                  = bigsmp_send_IPI_mask,
 194        .send_IPI_mask_allbutself       = NULL,
 195        .send_IPI_allbutself            = bigsmp_send_IPI_allbutself,
 196        .send_IPI_all                   = bigsmp_send_IPI_all,
 197        .send_IPI_self                  = default_send_IPI_self,
 198
 199        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
 200        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
 201
 202        .wait_for_init_deassert         = default_wait_for_init_deassert,
 203
 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        .x86_32_early_logical_apicid    = bigsmp_early_logical_apicid,
 216};
 217
 218void __init generic_bigsmp_probe(void)
 219{
 220        unsigned int cpu;
 221
 222        if (!probe_bigsmp())
 223                return;
 224
 225        apic = &apic_bigsmp;
 226
 227        for_each_possible_cpu(cpu) {
 228                if (early_per_cpu(x86_cpu_to_logical_apicid,
 229                                  cpu) == BAD_APICID)
 230                        continue;
 231                early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
 232                        bigsmp_early_logical_apicid(cpu);
 233        }
 234
 235        pr_info("Overriding APIC driver with %s\n", apic_bigsmp.name);
 236}
 237
 238apic_driver(apic_bigsmp);
 239