884d9e40b4
Broadcast IPI's provide un-expected behaviour for cpu hotplug. CPU's in offline state also end up receiving the IPI. Once the cpus become online they receive these stale IPI's which are bad and introduce unexpected behaviour. This is easily avoided by not sending a broadcast and addressing just the CPU's in online map. Doing prelim cycle counts it appears there is no big overhead and numbers seem around 0x3000-0x3900 on an average on x86 and x86_64 systems with CPUS running 3G, both for broadcast and mask version of the API's. The shortcuts are useful only for flat mode (where the perf shows no degradation), and in cluster mode, its unicast anyway. Its simpler to just not use broadcast anymore. Signed-off-by: Ashok Raj <ashok.raj@intel.com> Acked-by: Andi Kleen <ak@muc.de> Acked-by: Zwane Mwaikambo <zwane@arm.linux.org.uk> Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
138 lines
3.1 KiB
C
138 lines
3.1 KiB
C
/*
|
|
* Copyright 2004 James Cleverdon, IBM.
|
|
* Subject to the GNU Public License, v.2
|
|
*
|
|
* Flat APIC subarch code. Maximum 8 CPUs, logical delivery.
|
|
*
|
|
* Hacked for x86-64 by James Cleverdon from i386 architecture code by
|
|
* Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
|
|
* James Cleverdon.
|
|
* Ashok Raj <ashok.raj@intel.com>
|
|
* Removed IPI broadcast shortcut to support CPU hotplug
|
|
*/
|
|
#include <linux/config.h>
|
|
#include <linux/threads.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/string.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/init.h>
|
|
#include <asm/smp.h>
|
|
#include <asm/ipi.h>
|
|
|
|
|
|
static cpumask_t flat_target_cpus(void)
|
|
{
|
|
return cpu_online_map;
|
|
}
|
|
|
|
/*
|
|
* Set up the logical destination ID.
|
|
*
|
|
* Intel recommends to set DFR, LDR and TPR before enabling
|
|
* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
|
|
* document number 292116). So here it goes...
|
|
*/
|
|
static void flat_init_apic_ldr(void)
|
|
{
|
|
unsigned long val;
|
|
unsigned long num, id;
|
|
|
|
num = smp_processor_id();
|
|
id = 1UL << num;
|
|
x86_cpu_to_log_apicid[num] = id;
|
|
apic_write_around(APIC_DFR, APIC_DFR_FLAT);
|
|
val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
|
|
val |= SET_APIC_LOGICAL_ID(id);
|
|
apic_write_around(APIC_LDR, val);
|
|
}
|
|
|
|
static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
|
|
{
|
|
unsigned long mask = cpus_addr(cpumask)[0];
|
|
unsigned long cfg;
|
|
unsigned long flags;
|
|
|
|
local_save_flags(flags);
|
|
local_irq_disable();
|
|
|
|
/*
|
|
* Wait for idle.
|
|
*/
|
|
apic_wait_icr_idle();
|
|
|
|
/*
|
|
* prepare target chip field
|
|
*/
|
|
cfg = __prepare_ICR2(mask);
|
|
apic_write_around(APIC_ICR2, cfg);
|
|
|
|
/*
|
|
* program the ICR
|
|
*/
|
|
cfg = __prepare_ICR(0, vector, APIC_DEST_LOGICAL);
|
|
|
|
/*
|
|
* Send the IPI. The write to APIC_ICR fires this off.
|
|
*/
|
|
apic_write_around(APIC_ICR, cfg);
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
static void flat_send_IPI_allbutself(int vector)
|
|
{
|
|
cpumask_t mask;
|
|
/*
|
|
* if there are no other CPUs in the system then
|
|
* we get an APIC send error if we try to broadcast.
|
|
* thus we have to avoid sending IPIs in this case.
|
|
*/
|
|
int this_cpu = get_cpu();
|
|
|
|
mask = cpu_online_map;
|
|
cpu_clear(this_cpu, mask);
|
|
|
|
if (cpus_weight(mask) >= 1)
|
|
flat_send_IPI_mask(mask, vector);
|
|
|
|
put_cpu();
|
|
}
|
|
|
|
static void flat_send_IPI_all(int vector)
|
|
{
|
|
flat_send_IPI_mask(cpu_online_map, vector);
|
|
}
|
|
|
|
static int flat_apic_id_registered(void)
|
|
{
|
|
return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map);
|
|
}
|
|
|
|
static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask)
|
|
{
|
|
return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
|
|
}
|
|
|
|
static unsigned int phys_pkg_id(int index_msb)
|
|
{
|
|
u32 ebx;
|
|
|
|
ebx = cpuid_ebx(1);
|
|
return ((ebx >> 24) & 0xFF) >> index_msb;
|
|
}
|
|
|
|
struct genapic apic_flat = {
|
|
.name = "flat",
|
|
.int_delivery_mode = dest_LowestPrio,
|
|
.int_dest_mode = (APIC_DEST_LOGICAL != 0),
|
|
.int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST,
|
|
.target_cpus = flat_target_cpus,
|
|
.apic_id_registered = flat_apic_id_registered,
|
|
.init_apic_ldr = flat_init_apic_ldr,
|
|
.send_IPI_all = flat_send_IPI_all,
|
|
.send_IPI_allbutself = flat_send_IPI_allbutself,
|
|
.send_IPI_mask = flat_send_IPI_mask,
|
|
.cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
|
|
.phys_pkg_id = phys_pkg_id,
|
|
};
|