Path: blob/master/arch/x86/kernel/apic/apic_flat_64.c
17531 views
/*1* Copyright 2004 James Cleverdon, IBM.2* Subject to the GNU Public License, v.23*4* Flat APIC subarch code.5*6* Hacked for x86-64 by James Cleverdon from i386 architecture code by7* Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and8* James Cleverdon.9*/10#include <linux/errno.h>11#include <linux/threads.h>12#include <linux/cpumask.h>13#include <linux/string.h>14#include <linux/kernel.h>15#include <linux/ctype.h>16#include <linux/init.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>2223#ifdef CONFIG_ACPI24#include <acpi/acpi_bus.h>25#endif2627static struct apic apic_physflat;28static struct apic apic_flat;2930struct apic __read_mostly *apic = &apic_flat;31EXPORT_SYMBOL_GPL(apic);3233static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)34{35return 1;36}3738static const struct cpumask *flat_target_cpus(void)39{40return cpu_online_mask;41}4243static void flat_vector_allocation_domain(int cpu, struct cpumask *retmask)44{45/* Careful. Some cpus do not strictly honor the set of cpus46* specified in the interrupt destination when using lowest47* priority interrupt delivery mode.48*49* In particular there was a hyperthreading cpu observed to50* deliver interrupts to the wrong hyperthread when only one51* hyperthread was specified in the interrupt desitination.52*/53cpumask_clear(retmask);54cpumask_bits(retmask)[0] = APIC_ALL_CPUS;55}5657/*58* Set up the logical destination ID.59*60* Intel recommends to set DFR, LDR and TPR before enabling61* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel62* document number 292116). So here it goes...63*/64static void flat_init_apic_ldr(void)65{66unsigned long val;67unsigned long num, id;6869num = smp_processor_id();70id = 1UL << num;71apic_write(APIC_DFR, APIC_DFR_FLAT);72val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;73val |= SET_APIC_LOGICAL_ID(id);74apic_write(APIC_LDR, val);75}7677static inline void _flat_send_IPI_mask(unsigned long mask, int vector)78{79unsigned long flags;8081local_irq_save(flags);82__default_send_IPI_dest_field(mask, vector, apic->dest_logical);83local_irq_restore(flags);84}8586static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)87{88unsigned long mask = cpumask_bits(cpumask)[0];8990_flat_send_IPI_mask(mask, vector);91}9293static void94flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)95{96unsigned long mask = cpumask_bits(cpumask)[0];97int cpu = smp_processor_id();9899if (cpu < BITS_PER_LONG)100clear_bit(cpu, &mask);101102_flat_send_IPI_mask(mask, vector);103}104105static void flat_send_IPI_allbutself(int vector)106{107int cpu = smp_processor_id();108#ifdef CONFIG_HOTPLUG_CPU109int hotplug = 1;110#else111int hotplug = 0;112#endif113if (hotplug || vector == NMI_VECTOR) {114if (!cpumask_equal(cpu_online_mask, cpumask_of(cpu))) {115unsigned long mask = cpumask_bits(cpu_online_mask)[0];116117if (cpu < BITS_PER_LONG)118clear_bit(cpu, &mask);119120_flat_send_IPI_mask(mask, vector);121}122} else if (num_online_cpus() > 1) {123__default_send_IPI_shortcut(APIC_DEST_ALLBUT,124vector, apic->dest_logical);125}126}127128static void flat_send_IPI_all(int vector)129{130if (vector == NMI_VECTOR) {131flat_send_IPI_mask(cpu_online_mask, vector);132} else {133__default_send_IPI_shortcut(APIC_DEST_ALLINC,134vector, apic->dest_logical);135}136}137138static unsigned int flat_get_apic_id(unsigned long x)139{140unsigned int id;141142id = (((x)>>24) & 0xFFu);143144return id;145}146147static unsigned long set_apic_id(unsigned int id)148{149unsigned long x;150151x = ((id & 0xFFu)<<24);152return x;153}154155static unsigned int read_xapic_id(void)156{157unsigned int id;158159id = flat_get_apic_id(apic_read(APIC_ID));160return id;161}162163static int flat_apic_id_registered(void)164{165return physid_isset(read_xapic_id(), phys_cpu_present_map);166}167168static int flat_phys_pkg_id(int initial_apic_id, int index_msb)169{170return initial_apic_id >> index_msb;171}172173static struct apic apic_flat = {174.name = "flat",175.probe = NULL,176.acpi_madt_oem_check = flat_acpi_madt_oem_check,177.apic_id_registered = flat_apic_id_registered,178179.irq_delivery_mode = dest_LowestPrio,180.irq_dest_mode = 1, /* logical */181182.target_cpus = flat_target_cpus,183.disable_esr = 0,184.dest_logical = APIC_DEST_LOGICAL,185.check_apicid_used = NULL,186.check_apicid_present = NULL,187188.vector_allocation_domain = flat_vector_allocation_domain,189.init_apic_ldr = flat_init_apic_ldr,190191.ioapic_phys_id_map = NULL,192.setup_apic_routing = NULL,193.multi_timer_check = NULL,194.cpu_present_to_apicid = default_cpu_present_to_apicid,195.apicid_to_cpu_present = NULL,196.setup_portio_remap = NULL,197.check_phys_apicid_present = default_check_phys_apicid_present,198.enable_apic_mode = NULL,199.phys_pkg_id = flat_phys_pkg_id,200.mps_oem_check = NULL,201202.get_apic_id = flat_get_apic_id,203.set_apic_id = set_apic_id,204.apic_id_mask = 0xFFu << 24,205206.cpu_mask_to_apicid = default_cpu_mask_to_apicid,207.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,208209.send_IPI_mask = flat_send_IPI_mask,210.send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself,211.send_IPI_allbutself = flat_send_IPI_allbutself,212.send_IPI_all = flat_send_IPI_all,213.send_IPI_self = apic_send_IPI_self,214215.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,216.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,217.wait_for_init_deassert = NULL,218.smp_callin_clear_local_apic = NULL,219.inquire_remote_apic = default_inquire_remote_apic,220221.read = native_apic_mem_read,222.write = native_apic_mem_write,223.icr_read = native_apic_icr_read,224.icr_write = native_apic_icr_write,225.wait_icr_idle = native_apic_wait_icr_idle,226.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,227};228229/*230* Physflat mode is used when there are more than 8 CPUs on a system.231* We cannot use logical delivery in this case because the mask232* overflows, so use physical mode.233*/234static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)235{236#ifdef CONFIG_ACPI237/*238* Quirk: some x86_64 machines can only use physical APIC mode239* regardless of how many processors are present (x86_64 ES7000240* is an example).241*/242if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&243(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {244printk(KERN_DEBUG "system APIC only can use physical flat");245return 1;246}247248if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) {249printk(KERN_DEBUG "IBM Summit detected, will use apic physical");250return 1;251}252#endif253254return 0;255}256257static const struct cpumask *physflat_target_cpus(void)258{259return cpu_online_mask;260}261262static void physflat_vector_allocation_domain(int cpu, struct cpumask *retmask)263{264cpumask_clear(retmask);265cpumask_set_cpu(cpu, retmask);266}267268static void physflat_send_IPI_mask(const struct cpumask *cpumask, int vector)269{270default_send_IPI_mask_sequence_phys(cpumask, vector);271}272273static void physflat_send_IPI_mask_allbutself(const struct cpumask *cpumask,274int vector)275{276default_send_IPI_mask_allbutself_phys(cpumask, vector);277}278279static void physflat_send_IPI_allbutself(int vector)280{281default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);282}283284static void physflat_send_IPI_all(int vector)285{286physflat_send_IPI_mask(cpu_online_mask, vector);287}288289static unsigned int physflat_cpu_mask_to_apicid(const struct cpumask *cpumask)290{291int cpu;292293/*294* We're using fixed IRQ delivery, can only return one phys APIC ID.295* May as well be the first.296*/297cpu = cpumask_first(cpumask);298if ((unsigned)cpu < nr_cpu_ids)299return per_cpu(x86_cpu_to_apicid, cpu);300else301return BAD_APICID;302}303304static unsigned int305physflat_cpu_mask_to_apicid_and(const struct cpumask *cpumask,306const struct cpumask *andmask)307{308int cpu;309310/*311* We're using fixed IRQ delivery, can only return one phys APIC ID.312* May as well be the first.313*/314for_each_cpu_and(cpu, cpumask, andmask) {315if (cpumask_test_cpu(cpu, cpu_online_mask))316break;317}318return per_cpu(x86_cpu_to_apicid, cpu);319}320321static int physflat_probe(void)322{323if (apic == &apic_physflat || num_possible_cpus() > 8)324return 1;325326return 0;327}328329static struct apic apic_physflat = {330331.name = "physical flat",332.probe = physflat_probe,333.acpi_madt_oem_check = physflat_acpi_madt_oem_check,334.apic_id_registered = flat_apic_id_registered,335336.irq_delivery_mode = dest_Fixed,337.irq_dest_mode = 0, /* physical */338339.target_cpus = physflat_target_cpus,340.disable_esr = 0,341.dest_logical = 0,342.check_apicid_used = NULL,343.check_apicid_present = NULL,344345.vector_allocation_domain = physflat_vector_allocation_domain,346/* not needed, but shouldn't hurt: */347.init_apic_ldr = flat_init_apic_ldr,348349.ioapic_phys_id_map = NULL,350.setup_apic_routing = NULL,351.multi_timer_check = NULL,352.cpu_present_to_apicid = default_cpu_present_to_apicid,353.apicid_to_cpu_present = NULL,354.setup_portio_remap = NULL,355.check_phys_apicid_present = default_check_phys_apicid_present,356.enable_apic_mode = NULL,357.phys_pkg_id = flat_phys_pkg_id,358.mps_oem_check = NULL,359360.get_apic_id = flat_get_apic_id,361.set_apic_id = set_apic_id,362.apic_id_mask = 0xFFu << 24,363364.cpu_mask_to_apicid = physflat_cpu_mask_to_apicid,365.cpu_mask_to_apicid_and = physflat_cpu_mask_to_apicid_and,366367.send_IPI_mask = physflat_send_IPI_mask,368.send_IPI_mask_allbutself = physflat_send_IPI_mask_allbutself,369.send_IPI_allbutself = physflat_send_IPI_allbutself,370.send_IPI_all = physflat_send_IPI_all,371.send_IPI_self = apic_send_IPI_self,372373.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,374.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,375.wait_for_init_deassert = NULL,376.smp_callin_clear_local_apic = NULL,377.inquire_remote_apic = default_inquire_remote_apic,378379.read = native_apic_mem_read,380.write = native_apic_mem_write,381.icr_read = native_apic_icr_read,382.icr_write = native_apic_icr_write,383.wait_icr_idle = native_apic_wait_icr_idle,384.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,385};386387/*388* We need to check for physflat first, so this order is important.389*/390apic_drivers(apic_physflat, apic_flat);391392393