genx2apic_cluster.c 5.3 KB
Newer Older
1 2 3 4 5 6
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/init.h>
7 8
#include <linux/dmar.h>

9 10 11 12 13 14
#include <asm/smp.h>
#include <asm/ipi.h>
#include <asm/genapic.h>

DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);

15
static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
16
{
17
	if (cpu_has_x2apic)
18 19 20 21 22
		return 1;

	return 0;
}

23 24
/* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */

25
static const struct cpumask *x2apic_target_cpus(void)
26
{
27
	return cpumask_of(0);
28 29 30 31 32
}

/*
 * for now each logical cpu is in its own vector allocation domain.
 */
33
static void x2apic_vector_allocation_domain(int cpu, struct cpumask *retmask)
34
{
35 36
	cpumask_clear(retmask);
	cpumask_set_cpu(cpu, retmask);
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
}

static void __x2apic_send_IPI_dest(unsigned int apicid, int vector,
				   unsigned int dest)
{
	unsigned long cfg;

	cfg = __prepare_ICR(0, vector, dest);

	/*
	 * send the IPI.
	 */
	x2apic_icr_write(cfg, apicid);
}

/*
 * for now, we send the IPI's one by one in the cpumask.
 * TBD: Based on the cpu mask, we can send the IPI's to the cluster group
 * at once. We have 16 cpu's in a cluster. This will minimize IPI register
 * writes.
 */
58
static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
59 60 61 62 63
{
	unsigned long flags;
	unsigned long query_cpu;

	local_irq_save(flags);
64
	for_each_cpu(query_cpu, mask)
65 66 67
		__x2apic_send_IPI_dest(
			per_cpu(x86_cpu_to_logical_apicid, query_cpu),
			vector, APIC_DEST_LOGICAL);
68 69 70
	local_irq_restore(flags);
}

71 72
static void x2apic_send_IPI_mask_allbutself(const struct cpumask *mask,
					    int vector)
73
{
74 75 76
	unsigned long flags;
	unsigned long query_cpu;
	unsigned long this_cpu = smp_processor_id();
77

78
	local_irq_save(flags);
79
	for_each_cpu(query_cpu, mask)
80 81 82 83 84 85
		if (query_cpu != this_cpu)
			__x2apic_send_IPI_dest(
				per_cpu(x86_cpu_to_logical_apicid, query_cpu),
				vector, APIC_DEST_LOGICAL);
	local_irq_restore(flags);
}
86

87 88 89 90 91 92 93 94 95 96 97 98 99
static void x2apic_send_IPI_allbutself(int vector)
{
	unsigned long flags;
	unsigned long query_cpu;
	unsigned long this_cpu = smp_processor_id();

	local_irq_save(flags);
	for_each_online_cpu(query_cpu)
		if (query_cpu != this_cpu)
			__x2apic_send_IPI_dest(
				per_cpu(x86_cpu_to_logical_apicid, query_cpu),
				vector, APIC_DEST_LOGICAL);
	local_irq_restore(flags);
100 101 102 103
}

static void x2apic_send_IPI_all(int vector)
{
104
	x2apic_send_IPI_mask(cpu_online_mask, vector);
105 106 107 108 109 110 111
}

static int x2apic_apic_id_registered(void)
{
	return 1;
}

112
static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask)
113 114 115 116
{
	int cpu;

	/*
117
	 * We're using fixed IRQ delivery, can only return one logical APIC ID.
118 119
	 * May as well be the first.
	 */
120
	cpu = cpumask_first(cpumask);
121
	if ((unsigned)cpu < nr_cpu_ids)
122 123 124 125 126
		return per_cpu(x86_cpu_to_logical_apicid, cpu);
	else
		return BAD_APICID;
}

127 128
static unsigned int x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
						  const struct cpumask *andmask)
M
Mike Travis 已提交
129 130 131 132
{
	int cpu;

	/*
133
	 * We're using fixed IRQ delivery, can only return one logical APIC ID.
M
Mike Travis 已提交
134 135
	 * May as well be the first.
	 */
136 137 138
	for_each_cpu_and(cpu, cpumask, andmask)
		if (cpumask_test_cpu(cpu, cpu_online_mask))
			break;
139
	if (cpu < nr_cpu_ids)
140
		return per_cpu(x86_cpu_to_logical_apicid, cpu);
M
Mike Travis 已提交
141 142 143
	return BAD_APICID;
}

Y
Yinghai Lu 已提交
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
static unsigned int get_apic_id(unsigned long x)
{
	unsigned int id;

	id = x;
	return id;
}

static unsigned long set_apic_id(unsigned int id)
{
	unsigned long x;

	x = id;
	return x;
}

160 161
static unsigned int phys_pkg_id(int index_msb)
{
162
	return current_cpu_data.initial_apicid >> index_msb;
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
}

static void x2apic_send_IPI_self(int vector)
{
	apic_write(APIC_SELF_IPI, vector);
}

static void init_x2apic_ldr(void)
{
	int cpu = smp_processor_id();

	per_cpu(x86_cpu_to_logical_apicid, cpu) = apic_read(APIC_LDR);
	return;
}

struct genapic apic_x2apic_cluster = {
I
Ingo Molnar 已提交
179 180 181 182 183 184

	.name				= "cluster x2apic",
	.probe				= NULL,
	.acpi_madt_oem_check		= x2apic_acpi_madt_oem_check,
	.apic_id_registered		= x2apic_apic_id_registered,

185 186
	.irq_delivery_mode		= dest_LowestPrio,
	.irq_dest_mode			= (APIC_DEST_LOGICAL != 0),
I
Ingo Molnar 已提交
187 188

	.target_cpus			= x2apic_target_cpus,
189
	.disable_esr			= 0,
I
Ingo Molnar 已提交
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
	.apic_destination_logical	= 0,
	.check_apicid_used		= NULL,
	.check_apicid_present		= NULL,

	.no_balance_irq			= 0,
	.no_ioapic_check		= 0,

	.vector_allocation_domain	= x2apic_vector_allocation_domain,
	.init_apic_ldr			= init_x2apic_ldr,

	.ioapic_phys_id_map		= NULL,
	.setup_apic_routing		= NULL,
	.multi_timer_check		= NULL,
	.apicid_to_node			= NULL,
	.cpu_to_logical_apicid		= NULL,
	.cpu_present_to_apicid		= NULL,
	.apicid_to_cpu_present		= NULL,
	.setup_portio_remap		= NULL,
	.check_phys_apicid_present	= NULL,
	.enable_apic_mode		= NULL,
	.phys_pkg_id			= phys_pkg_id,
	.mps_oem_check			= NULL,

	.get_apic_id			= get_apic_id,
	.set_apic_id			= set_apic_id,
	.apic_id_mask			= 0xFFFFFFFFu,

	.cpu_mask_to_apicid		= x2apic_cpu_mask_to_apicid,
	.cpu_mask_to_apicid_and		= x2apic_cpu_mask_to_apicid_and,

	.send_IPI_mask			= x2apic_send_IPI_mask,
	.send_IPI_mask_allbutself	= x2apic_send_IPI_mask_allbutself,
	.send_IPI_allbutself		= x2apic_send_IPI_allbutself,
	.send_IPI_all			= x2apic_send_IPI_all,
	.send_IPI_self			= x2apic_send_IPI_self,

	.wakeup_cpu			= NULL,
	.trampoline_phys_low		= 0,
	.trampoline_phys_high		= 0,
	.wait_for_init_deassert		= NULL,
	.smp_callin_clear_local_apic	= NULL,
	.store_NMI_vector		= NULL,
	.restore_NMI_vector		= NULL,
	.inquire_remote_apic		= NULL,
234
};