bigsmp_32.c 6.55 KB
Newer Older
1
/*
Linus Torvalds's avatar
Linus Torvalds committed
2 3 4 5 6 7
 * APIC driver for "bigsmp" XAPIC machines with more than 8 virtual CPUs.
 * Drives the local APIC in "clustered mode".
 */
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <asm/mpspec.h>
Ingo Molnar's avatar
Ingo Molnar committed
8
#include <asm/apic.h>
Linus Torvalds's avatar
Linus Torvalds committed
9 10
#include <asm/fixmap.h>
#include <asm/apicdef.h>
11
#include <asm/ipi.h>
Linus Torvalds's avatar
Linus Torvalds committed
12 13 14
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/dmi.h>
15
#include <linux/smp.h>
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158


static inline unsigned bigsmp_get_apic_id(unsigned long x)
{
	return (x >> 24) & 0xFF;
}

#define xapic_phys_to_log_apicid(cpu) (per_cpu(x86_bios_cpu_apicid, cpu))

static inline int bigsmp_apic_id_registered(void)
{
	return 1;
}

static inline const cpumask_t *bigsmp_target_cpus(void)
{
#ifdef CONFIG_SMP
	return &cpu_online_map;
#else
	return &cpumask_of_cpu(0);
#endif
}

#define APIC_DFR_VALUE		(APIC_DFR_FLAT)

static inline unsigned long
bigsmp_check_apicid_used(physid_mask_t bitmap, int apicid)
{
	return 0;
}

static inline unsigned long bigsmp_check_apicid_present(int bit)
{
	return 1;
}

static inline unsigned long calculate_ldr(int cpu)
{
	unsigned long val, id;
	val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
	id = xapic_phys_to_log_apicid(cpu);
	val |= SET_APIC_LOGICAL_ID(id);
	return val;
}

/*
 * 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 inline void bigsmp_init_apic_ldr(void)
{
	unsigned long val;
	int cpu = smp_processor_id();

	apic_write(APIC_DFR, APIC_DFR_VALUE);
	val = calculate_ldr(cpu);
	apic_write(APIC_LDR, val);
}

static inline void bigsmp_setup_apic_routing(void)
{
	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
		"Physflat", nr_ioapics);
}

static inline int bigsmp_apicid_to_node(int logical_apicid)
{
	return apicid_2_node[hard_smp_processor_id()];
}

static inline int bigsmp_cpu_present_to_apicid(int mps_cpu)
{
	if (mps_cpu < nr_cpu_ids)
		return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);

	return BAD_APICID;
}

static inline physid_mask_t bigsmp_apicid_to_cpu_present(int phys_apicid)
{
	return physid_mask_of_physid(phys_apicid);
}

extern u8 cpu_2_logical_apicid[];
/* Mapping from cpu number to logical apicid */
static inline int bigsmp_cpu_to_logical_apicid(int cpu)
{
	if (cpu >= nr_cpu_ids)
		return BAD_APICID;
	return cpu_physical_id(cpu);
}

static inline physid_mask_t bigsmp_ioapic_phys_id_map(physid_mask_t phys_map)
{
	/* For clustered we don't have a good way to do this yet - hack */
	return physids_promote(0xFFL);
}

static inline void bigsmp_setup_portio_remap(void)
{
}

static inline int bigsmp_check_phys_apicid_present(int boot_cpu_physical_apicid)
{
	return 1;
}

/* As we are using single CPU as destination, pick only one CPU here */
static inline unsigned int bigsmp_cpu_mask_to_apicid(const cpumask_t *cpumask)
{
	return bigsmp_cpu_to_logical_apicid(first_cpu(*cpumask));
}

static inline unsigned int
bigsmp_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
			      const struct cpumask *andmask)
{
	int cpu;

	/*
	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
	 * May as well be the first.
	 */
	for_each_cpu_and(cpu, cpumask, andmask) {
		if (cpumask_test_cpu(cpu, cpu_online_mask))
			break;
	}
	if (cpu < nr_cpu_ids)
		return bigsmp_cpu_to_logical_apicid(cpu);

	return BAD_APICID;
}

static inline int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
{
	return cpuid_apic >> index_msb;
}

static inline void bigsmp_send_IPI_mask(const struct cpumask *mask, int vector)
{
159
	default_send_IPI_mask_sequence_phys(mask, vector);
160 161 162 163
}

static inline void bigsmp_send_IPI_allbutself(int vector)
{
164
	default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
165 166 167 168 169 170
}

static inline void bigsmp_send_IPI_all(int vector)
{
	bigsmp_send_IPI_mask(cpu_online_mask, vector);
}
Linus Torvalds's avatar
Linus Torvalds committed
171 172 173

static int dmi_bigsmp; /* can be set by dmi scanners */

174
static int hp_ht_bigsmp(const struct dmi_system_id *d)
Linus Torvalds's avatar
Linus Torvalds committed
175 176 177 178 179 180 181
{
	printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident);
	dmi_bigsmp = 1;
	return 0;
}


182
static const struct dmi_system_id bigsmp_dmi_table[] = {
183 184 185 186 187 188 189 190 191
	{ hp_ht_bigsmp, "HP ProLiant DL760 G2",
	{ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
	DMI_MATCH(DMI_BIOS_VERSION, "P44-"),}
	},

	{ hp_ht_bigsmp, "HP ProLiant DL740",
	{ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
	DMI_MATCH(DMI_BIOS_VERSION, "P47-"),}
	},
Linus Torvalds's avatar
Linus Torvalds committed
192 193 194
	 { }
};

195
static void bigsmp_vector_allocation_domain(int cpu, cpumask_t *retmask)
196
{
197 198
	cpus_clear(*retmask);
	cpu_set(cpu, *retmask);
199
}
Linus Torvalds's avatar
Linus Torvalds committed
200

201
static int probe_bigsmp(void)
202
{
203
	if (def_to_bigsmp)
204
		dmi_bigsmp = 1;
205 206
	else
		dmi_check_system(bigsmp_dmi_table);
207 208
	return dmi_bigsmp;
}
Linus Torvalds's avatar
Linus Torvalds committed
209

210 211 212 213
struct genapic apic_bigsmp = {

	.name				= "bigsmp",
	.probe				= probe_bigsmp,
214
	.acpi_madt_oem_check		= NULL,
215
	.apic_id_registered		= bigsmp_apic_id_registered,
216

217 218 219
	.irq_delivery_mode		= dest_Fixed,
	/* phys delivery to target CPU: */
	.irq_dest_mode			= 0,
220

221
	.target_cpus			= bigsmp_target_cpus,
222
	.disable_esr			= 1,
223
	.dest_logical			= 0,
224 225
	.check_apicid_used		= bigsmp_check_apicid_used,
	.check_apicid_present		= bigsmp_check_apicid_present,
226

227
	.vector_allocation_domain	= bigsmp_vector_allocation_domain,
228
	.init_apic_ldr			= bigsmp_init_apic_ldr,
229

230
	.ioapic_phys_id_map		= bigsmp_ioapic_phys_id_map,
231
	.setup_apic_routing		= bigsmp_setup_apic_routing,
232
	.multi_timer_check		= NULL,
233
	.apicid_to_node			= bigsmp_apicid_to_node,
234
	.cpu_to_logical_apicid		= bigsmp_cpu_to_logical_apicid,
235
	.cpu_present_to_apicid		= bigsmp_cpu_present_to_apicid,
236
	.apicid_to_cpu_present		= bigsmp_apicid_to_cpu_present,
237
	.setup_portio_remap		= NULL,
238
	.check_phys_apicid_present	= bigsmp_check_phys_apicid_present,
239
	.enable_apic_mode		= NULL,
240
	.phys_pkg_id			= bigsmp_phys_pkg_id,
241
	.mps_oem_check			= NULL,
242

243
	.get_apic_id			= bigsmp_get_apic_id,
244
	.set_apic_id			= NULL,
245
	.apic_id_mask			= 0xFF << 24,
246

247 248
	.cpu_mask_to_apicid		= bigsmp_cpu_mask_to_apicid,
	.cpu_mask_to_apicid_and		= bigsmp_cpu_mask_to_apicid_and,
249

250
	.send_IPI_mask			= bigsmp_send_IPI_mask,
251
	.send_IPI_mask_allbutself	= NULL,
252 253
	.send_IPI_allbutself		= bigsmp_send_IPI_allbutself,
	.send_IPI_all			= bigsmp_send_IPI_all,
254
	.send_IPI_self			= default_send_IPI_self,
255 256

	.wakeup_cpu			= NULL,
257 258
	.trampoline_phys_low		= DEFAULT_TRAMPOLINE_PHYS_LOW,
	.trampoline_phys_high		= DEFAULT_TRAMPOLINE_PHYS_HIGH,
259 260 261

	.wait_for_init_deassert		= default_wait_for_init_deassert,

262
	.smp_callin_clear_local_apic	= NULL,
263
	.store_NMI_vector		= NULL,
264
	.inquire_remote_apic		= default_inquire_remote_apic,
Yinghai Lu's avatar
Yinghai Lu committed
265 266 267 268 269 270 271

	.read				= native_apic_mem_read,
	.write				= native_apic_mem_write,
	.icr_read			= native_apic_icr_read,
	.icr_write			= native_apic_icr_write,
	.wait_icr_idle			= native_apic_wait_icr_idle,
	.safe_wait_icr_idle		= native_safe_apic_wait_icr_idle,
272
};