Path: blob/master/arch/x86/kernel/apic/bigsmp_32.c
17537 views
/*1* APIC driver for "bigsmp" xAPIC machines with more than 8 virtual CPUs.2*3* Drives the local APIC in "clustered mode".4*/5#include <linux/threads.h>6#include <linux/cpumask.h>7#include <linux/kernel.h>8#include <linux/init.h>9#include <linux/dmi.h>10#include <linux/smp.h>1112#include <asm/apicdef.h>13#include <asm/fixmap.h>14#include <asm/mpspec.h>15#include <asm/apic.h>16#include <asm/ipi.h>1718static unsigned bigsmp_get_apic_id(unsigned long x)19{20return (x >> 24) & 0xFF;21}2223static int bigsmp_apic_id_registered(void)24{25return 1;26}2728static const struct cpumask *bigsmp_target_cpus(void)29{30#ifdef CONFIG_SMP31return cpu_online_mask;32#else33return cpumask_of(0);34#endif35}3637static unsigned long bigsmp_check_apicid_used(physid_mask_t *map, int apicid)38{39return 0;40}4142static unsigned long bigsmp_check_apicid_present(int bit)43{44return 1;45}4647static int bigsmp_early_logical_apicid(int cpu)48{49/* on bigsmp, logical apicid is the same as physical */50return early_per_cpu(x86_cpu_to_apicid, cpu);51}5253static inline unsigned long calculate_ldr(int cpu)54{55unsigned long val, id;5657val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;58id = per_cpu(x86_bios_cpu_apicid, cpu);59val |= SET_APIC_LOGICAL_ID(id);6061return val;62}6364/*65* Set up the logical destination ID.66*67* Intel recommends to set DFR, LDR and TPR before enabling68* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel69* document number 292116). So here it goes...70*/71static void bigsmp_init_apic_ldr(void)72{73unsigned long val;74int cpu = smp_processor_id();7576apic_write(APIC_DFR, APIC_DFR_FLAT);77val = calculate_ldr(cpu);78apic_write(APIC_LDR, val);79}8081static void bigsmp_setup_apic_routing(void)82{83printk(KERN_INFO84"Enabling APIC mode: Physflat. Using %d I/O APICs\n",85nr_ioapics);86}8788static int bigsmp_cpu_present_to_apicid(int mps_cpu)89{90if (mps_cpu < nr_cpu_ids)91return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);9293return BAD_APICID;94}9596static void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)97{98/* For clustered we don't have a good way to do this yet - hack */99physids_promote(0xFFL, retmap);100}101102static int bigsmp_check_phys_apicid_present(int phys_apicid)103{104return 1;105}106107/* As we are using single CPU as destination, pick only one CPU here */108static unsigned int bigsmp_cpu_mask_to_apicid(const struct cpumask *cpumask)109{110int cpu = cpumask_first(cpumask);111112if (cpu < nr_cpu_ids)113return cpu_physical_id(cpu);114return BAD_APICID;115}116117static unsigned int bigsmp_cpu_mask_to_apicid_and(const struct cpumask *cpumask,118const struct cpumask *andmask)119{120int cpu;121122/*123* We're using fixed IRQ delivery, can only return one phys APIC ID.124* May as well be the first.125*/126for_each_cpu_and(cpu, cpumask, andmask) {127if (cpumask_test_cpu(cpu, cpu_online_mask))128return cpu_physical_id(cpu);129}130return BAD_APICID;131}132133static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)134{135return cpuid_apic >> index_msb;136}137138static inline void bigsmp_send_IPI_mask(const struct cpumask *mask, int vector)139{140default_send_IPI_mask_sequence_phys(mask, vector);141}142143static void bigsmp_send_IPI_allbutself(int vector)144{145default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);146}147148static void bigsmp_send_IPI_all(int vector)149{150bigsmp_send_IPI_mask(cpu_online_mask, vector);151}152153static int dmi_bigsmp; /* can be set by dmi scanners */154155static int hp_ht_bigsmp(const struct dmi_system_id *d)156{157printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident);158dmi_bigsmp = 1;159160return 0;161}162163164static const struct dmi_system_id bigsmp_dmi_table[] = {165{ hp_ht_bigsmp, "HP ProLiant DL760 G2",166{ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),167DMI_MATCH(DMI_BIOS_VERSION, "P44-"),168}169},170171{ hp_ht_bigsmp, "HP ProLiant DL740",172{ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),173DMI_MATCH(DMI_BIOS_VERSION, "P47-"),174}175},176{ } /* NULL entry stops DMI scanning */177};178179static void bigsmp_vector_allocation_domain(int cpu, struct cpumask *retmask)180{181cpumask_clear(retmask);182cpumask_set_cpu(cpu, retmask);183}184185static int probe_bigsmp(void)186{187if (def_to_bigsmp)188dmi_bigsmp = 1;189else190dmi_check_system(bigsmp_dmi_table);191192return dmi_bigsmp;193}194195static struct apic apic_bigsmp = {196197.name = "bigsmp",198.probe = probe_bigsmp,199.acpi_madt_oem_check = NULL,200.apic_id_registered = bigsmp_apic_id_registered,201202.irq_delivery_mode = dest_Fixed,203/* phys delivery to target CPU: */204.irq_dest_mode = 0,205206.target_cpus = bigsmp_target_cpus,207.disable_esr = 1,208.dest_logical = 0,209.check_apicid_used = bigsmp_check_apicid_used,210.check_apicid_present = bigsmp_check_apicid_present,211212.vector_allocation_domain = bigsmp_vector_allocation_domain,213.init_apic_ldr = bigsmp_init_apic_ldr,214215.ioapic_phys_id_map = bigsmp_ioapic_phys_id_map,216.setup_apic_routing = bigsmp_setup_apic_routing,217.multi_timer_check = NULL,218.cpu_present_to_apicid = bigsmp_cpu_present_to_apicid,219.apicid_to_cpu_present = physid_set_mask_of_physid,220.setup_portio_remap = NULL,221.check_phys_apicid_present = bigsmp_check_phys_apicid_present,222.enable_apic_mode = NULL,223.phys_pkg_id = bigsmp_phys_pkg_id,224.mps_oem_check = NULL,225226.get_apic_id = bigsmp_get_apic_id,227.set_apic_id = NULL,228.apic_id_mask = 0xFF << 24,229230.cpu_mask_to_apicid = bigsmp_cpu_mask_to_apicid,231.cpu_mask_to_apicid_and = bigsmp_cpu_mask_to_apicid_and,232233.send_IPI_mask = bigsmp_send_IPI_mask,234.send_IPI_mask_allbutself = NULL,235.send_IPI_allbutself = bigsmp_send_IPI_allbutself,236.send_IPI_all = bigsmp_send_IPI_all,237.send_IPI_self = default_send_IPI_self,238239.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,240.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,241242.wait_for_init_deassert = default_wait_for_init_deassert,243244.smp_callin_clear_local_apic = NULL,245.inquire_remote_apic = default_inquire_remote_apic,246247.read = native_apic_mem_read,248.write = native_apic_mem_write,249.icr_read = native_apic_icr_read,250.icr_write = native_apic_icr_write,251.wait_icr_idle = native_apic_wait_icr_idle,252.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,253254.x86_32_early_logical_apicid = bigsmp_early_logical_apicid,255};256257struct apic * __init generic_bigsmp_probe(void)258{259if (probe_bigsmp())260return &apic_bigsmp;261262return NULL;263}264265apic_driver(apic_bigsmp);266267268