es7000_32.c 17.8 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
/*
 * Written by: Garry Forsgren, Unisys Corporation
 *             Natalie Protasevich, Unisys Corporation
Ingo Molnar's avatar
Ingo Molnar committed
4
 *
Linus Torvalds's avatar
Linus Torvalds committed
5
6
7
 * This file contains the code to configure and interface
 * with Unisys ES7000 series hardware system manager.
 *
Ingo Molnar's avatar
Ingo Molnar committed
8
9
10
11
 * Copyright (c) 2003 Unisys Corporation.
 * Copyright (C) 2009, Red Hat, Inc., Ingo Molnar
 *
 *   All Rights Reserved.
Linus Torvalds's avatar
Linus Torvalds committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it would be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write the Free Software Foundation, Inc., 59
 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
 *
 * Contact information: Unisys Corporation, Township Line & Union Meeting
 * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
 *
 * http://www.unisys.com
 */
30
31
32

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

Ingo Molnar's avatar
Ingo Molnar committed
33
34
35
36
#include <linux/notifier.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
#include <linux/threads.h>
Linus Torvalds's avatar
Linus Torvalds committed
37
#include <linux/kernel.h>
Ingo Molnar's avatar
Ingo Molnar committed
38
39
#include <linux/module.h>
#include <linux/reboot.h>
Linus Torvalds's avatar
Linus Torvalds committed
40
#include <linux/string.h>
Ingo Molnar's avatar
Ingo Molnar committed
41
#include <linux/types.h>
Linus Torvalds's avatar
Linus Torvalds committed
42
43
#include <linux/errno.h>
#include <linux/acpi.h>
Ingo Molnar's avatar
Ingo Molnar committed
44
#include <linux/init.h>
Ingo Molnar's avatar
Ingo Molnar committed
45
#include <linux/nmi.h>
Ingo Molnar's avatar
Ingo Molnar committed
46
#include <linux/smp.h>
Ingo Molnar's avatar
Ingo Molnar committed
47
#include <linux/io.h>
Ingo Molnar's avatar
Ingo Molnar committed
48

Linus Torvalds's avatar
Linus Torvalds committed
49
#include <asm/apicdef.h>
Ingo Molnar's avatar
Ingo Molnar committed
50
51
52
#include <asm/atomic.h>
#include <asm/fixmap.h>
#include <asm/mpspec.h>
53
#include <asm/setup.h>
Ingo Molnar's avatar
Ingo Molnar committed
54
55
#include <asm/apic.h>
#include <asm/ipi.h>
Linus Torvalds's avatar
Linus Torvalds committed
56

57
58
59
60
/*
 * ES7000 chipsets
 */

Ingo Molnar's avatar
Ingo Molnar committed
61
62
63
#define NON_UNISYS			0
#define ES7000_CLASSIC			1
#define ES7000_ZORRO			2
64

Ingo Molnar's avatar
Ingo Molnar committed
65
66
#define	MIP_REG				1
#define	MIP_PSAI_REG			4
67

Ingo Molnar's avatar
Ingo Molnar committed
68
69
70
#define	MIP_BUSY			1
#define	MIP_SPIN			0xf0000
#define	MIP_VALID			0x0100000000000000ULL
71
#define	MIP_SW_APIC			0x1020b
72

Ingo Molnar's avatar
Ingo Molnar committed
73
#define	MIP_PORT(val)			((val >> 32) & 0xffff)
74

Ingo Molnar's avatar
Ingo Molnar committed
75
#define	MIP_RD_LO(val)			(val & 0xffffffff)
76

77
78
79
80
81
82
83
84
85
86
87
struct mip_reg {
	unsigned long long		off_0x00;
	unsigned long long		off_0x08;
	unsigned long long		off_0x10;
	unsigned long long		off_0x18;
	unsigned long long		off_0x20;
	unsigned long long		off_0x28;
	unsigned long long		off_0x30;
	unsigned long long		off_0x38;
};

88
struct mip_reg_info {
Ingo Molnar's avatar
Ingo Molnar committed
89
90
91
92
	unsigned long long		mip_info;
	unsigned long long		delivery_info;
	unsigned long long		host_reg;
	unsigned long long		mip_reg;
93
94
95
};

struct psai {
Ingo Molnar's avatar
Ingo Molnar committed
96
97
98
	unsigned long long		entry_type;
	unsigned long long		addr;
	unsigned long long		bep_addr;
99
100
101
};

#ifdef CONFIG_ACPI
Ingo Molnar's avatar
Ingo Molnar committed
102

103
struct es7000_oem_table {
Ingo Molnar's avatar
Ingo Molnar committed
104
105
106
	struct acpi_table_header	Header;
	u32				OEMTableAddr;
	u32				OEMTableSize;
107
};
Ingo Molnar's avatar
Ingo Molnar committed
108
109
110
111

static unsigned long			oem_addrX;
static unsigned long			oem_size;

112
113
#endif

Linus Torvalds's avatar
Linus Torvalds committed
114
115
116
117
/*
 * ES7000 Globals
 */

Ingo Molnar's avatar
Ingo Molnar committed
118
static volatile unsigned long		*psai;
Ingo Molnar's avatar
Ingo Molnar committed
119
120
121
static struct mip_reg			*mip_reg;
static struct mip_reg			*host_reg;
static int 				mip_port;
Ingo Molnar's avatar
Ingo Molnar committed
122
123
static unsigned long			mip_addr;
static unsigned long			host_addr;
Linus Torvalds's avatar
Linus Torvalds committed
124

Ingo Molnar's avatar
Ingo Molnar committed
125
int					es7000_plat;
126

Linus Torvalds's avatar
Linus Torvalds committed
127
128
129
130
/*
 * GSI override for ES7000 platforms.
 */

Ingo Molnar's avatar
Ingo Molnar committed
131
static unsigned int			base;
Linus Torvalds's avatar
Linus Torvalds committed
132
133
134
135

static int
es7000_rename_gsi(int ioapic, int gsi)
{
136
137
138
	if (es7000_plat == ES7000_ZORRO)
		return gsi;

Linus Torvalds's avatar
Linus Torvalds committed
139
140
141
142
143
144
	if (!base) {
		int i;
		for (i = 0; i < nr_ioapics; i++)
			base += nr_ioapic_registers[i];
	}

Yinghai Lu's avatar
Yinghai Lu committed
145
	if (!ioapic && (gsi < 16))
Linus Torvalds's avatar
Linus Torvalds committed
146
		gsi += base;
Ingo Molnar's avatar
Ingo Molnar committed
147

Linus Torvalds's avatar
Linus Torvalds committed
148
149
150
	return gsi;
}

151
static int __cpuinit wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
{
	unsigned long vect = 0, psaival = 0;

	if (psai == NULL)
		return -1;

	vect = ((unsigned long)__pa(eip)/0x1000) << 16;
	psaival = (0x1000000 | vect | cpu);

	while (*psai & 0x1000000)
		;

	*psai = psaival;

	return 0;
}
168

169
static int es7000_apic_is_cluster(void)
170
{
171
172
	/* MPENTIUMIII */
	if (boot_cpu_data.x86 == 6 &&
173
	    (boot_cpu_data.x86_model >= 7 && boot_cpu_data.x86_model <= 11))
174
		return 1;
175

176
177
	return 0;
}
178

179
static void setup_unisys(void)
180
181
182
183
184
185
186
187
188
{
	/*
	 * Determine the generation of the ES7000 currently running.
	 *
	 * es7000_plat = 1 if the machine is a 5xx ES7000 box
	 * es7000_plat = 2 if the machine is a x86_64 ES7000 box
	 *
	 */
	if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
189
		es7000_plat = ES7000_ZORRO;
190
	else
191
		es7000_plat = ES7000_CLASSIC;
192
193
194
	ioapic_renumber_irq = es7000_rename_gsi;
}

Linus Torvalds's avatar
Linus Torvalds committed
195
/*
Ingo Molnar's avatar
Ingo Molnar committed
196
 * Parse the OEM Table:
Linus Torvalds's avatar
Linus Torvalds committed
197
 */
198
static int parse_unisys_oem(char *oemptr)
Linus Torvalds's avatar
Linus Torvalds committed
199
{
200
	int			i;
Linus Torvalds's avatar
Linus Torvalds committed
201
	int 			success = 0;
202
203
204
205
	unsigned char		type, size;
	unsigned long		val;
	char			*tp = NULL;
	struct psai		*psaip = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
206
207
208
209
210
211
212
	struct mip_reg_info 	*mi;
	struct mip_reg		*host, *mip;

	tp = oemptr;

	tp += 8;

213
	for (i = 0; i <= 6; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
		type = *tp++;
		size = *tp++;
		tp -= 2;
		switch (type) {
		case MIP_REG:
			mi = (struct mip_reg_info *)tp;
			val = MIP_RD_LO(mi->host_reg);
			host_addr = val;
			host = (struct mip_reg *)val;
			host_reg = __va(host);
			val = MIP_RD_LO(mi->mip_reg);
			mip_port = MIP_PORT(mi->mip_info);
			mip_addr = val;
			mip = (struct mip_reg *)val;
			mip_reg = __va(mip);
229
			pr_debug("host_reg = 0x%lx\n",
230
				 (unsigned long)host_reg);
231
			pr_debug("mip_reg = 0x%lx\n",
232
				 (unsigned long)mip_reg);
Linus Torvalds's avatar
Linus Torvalds committed
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
			success++;
			break;
		case MIP_PSAI_REG:
			psaip = (struct psai *)tp;
			if (tp != NULL) {
				if (psaip->addr)
					psai = __va(psaip->addr);
				else
					psai = NULL;
				success++;
			}
			break;
		default:
			break;
		}
		tp += size;
	}

Ingo Molnar's avatar
Ingo Molnar committed
251
	if (success < 2)
252
		es7000_plat = NON_UNISYS;
Ingo Molnar's avatar
Ingo Molnar committed
253
	else
254
		setup_unisys();
Ingo Molnar's avatar
Ingo Molnar committed
255

Linus Torvalds's avatar
Linus Torvalds committed
256
257
258
	return es7000_plat;
}

259
#ifdef CONFIG_ACPI
260
static int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
Linus Torvalds's avatar
Linus Torvalds committed
261
{
262
	struct acpi_table_header *header = NULL;
Ingo Molnar's avatar
Ingo Molnar committed
263
	struct es7000_oem_table *table;
264
	acpi_size tbl_size;
Ingo Molnar's avatar
Ingo Molnar committed
265
266
	acpi_status ret;
	int i = 0;
267

Ingo Molnar's avatar
Ingo Molnar committed
268
269
270
271
	for (;;) {
		ret = acpi_get_table_with_size("OEM1", i++, &header, &tbl_size);
		if (!ACPI_SUCCESS(ret))
			return -1;
272

Ingo Molnar's avatar
Ingo Molnar committed
273
274
		if (!memcmp((char *) &header->oem_id, "UNISYS", 6))
			break;
275

276
		early_acpi_os_unmap_memory(header, tbl_size);
Linus Torvalds's avatar
Linus Torvalds committed
277
	}
Ingo Molnar's avatar
Ingo Molnar committed
278
279
280
281
282
283
284
285
286
287
288

	table = (void *)header;

	oem_addrX	= table->OEMTableAddr;
	oem_size	= table->OEMTableSize;

	early_acpi_os_unmap_memory(header, tbl_size);

	*oem_addr	= (unsigned long)__acpi_map_table(oem_addrX, oem_size);

	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
289
}
290

291
static void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
292
{
293
294
295
296
	if (!oem_addr)
		return;

	__acpi_unmap_table((char *)oem_addr, oem_size);
297
}
Ingo Molnar's avatar
Ingo Molnar committed
298
299
300
301
302
303
304
305
306
307
308

static int es7000_check_dsdt(void)
{
	struct acpi_table_header header;

	if (ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_DSDT, 0, &header)) &&
	    !strncmp(header.oem_id, "UNISYS", 6))
		return 1;
	return 0;
}

309
static int es7000_acpi_ret;
310

Ingo Molnar's avatar
Ingo Molnar committed
311
/* Hook from generic ACPI tables.c */
312
static int __init es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
Ingo Molnar's avatar
Ingo Molnar committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
{
	unsigned long oem_addr = 0;
	int check_dsdt;
	int ret = 0;

	/* check dsdt at first to avoid clear fix_map for oem_addr */
	check_dsdt = es7000_check_dsdt();

	if (!find_unisys_acpi_oem_table(&oem_addr)) {
		if (check_dsdt) {
			ret = parse_unisys_oem((char *)oem_addr);
		} else {
			setup_unisys();
			ret = 1;
		}
		/*
		 * we need to unmap it
		 */
		unmap_unisys_acpi_oem_table(oem_addr);
	}
333
334
335
336

	es7000_acpi_ret = ret;

	return ret && !es7000_apic_is_cluster();
Ingo Molnar's avatar
Ingo Molnar committed
337
}
338

339
static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id)
340
341
342
343
344
345
{
	int ret = es7000_acpi_ret;

	return ret && es7000_apic_is_cluster();
}

Ingo Molnar's avatar
Ingo Molnar committed
346
#else /* !CONFIG_ACPI: */
347
static int es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
Ingo Molnar's avatar
Ingo Molnar committed
348
349
350
{
	return 0;
}
351

352
static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id)
353
354
355
{
	return 0;
}
Ingo Molnar's avatar
Ingo Molnar committed
356
#endif /* !CONFIG_ACPI */
Linus Torvalds's avatar
Linus Torvalds committed
357

Ingo Molnar's avatar
Ingo Molnar committed
358
static void es7000_spin(int n)
Linus Torvalds's avatar
Linus Torvalds committed
359
360
361
362
363
364
365
{
	int i = 0;

	while (i++ < n)
		rep_nop();
}

366
static int es7000_mip_write(struct mip_reg *mip_reg)
Linus Torvalds's avatar
Linus Torvalds committed
367
{
Ingo Molnar's avatar
Ingo Molnar committed
368
369
	int status = 0;
	int spin;
Linus Torvalds's avatar
Linus Torvalds committed
370
371

	spin = MIP_SPIN;
Ingo Molnar's avatar
Ingo Molnar committed
372
373
	while ((host_reg->off_0x38 & MIP_VALID) != 0) {
		if (--spin <= 0) {
Ingo Molnar's avatar
Ingo Molnar committed
374
			WARN(1,	"Timeout waiting for Host Valid Flag\n");
Ingo Molnar's avatar
Ingo Molnar committed
375
376
			return -1;
		}
Linus Torvalds's avatar
Linus Torvalds committed
377
378
379
380
381
382
383
384
		es7000_spin(MIP_SPIN);
	}

	memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
	outb(1, mip_port);

	spin = MIP_SPIN;

Ingo Molnar's avatar
Ingo Molnar committed
385
	while ((mip_reg->off_0x38 & MIP_VALID) == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
386
		if (--spin <= 0) {
Ingo Molnar's avatar
Ingo Molnar committed
387
			WARN(1,	"Timeout waiting for MIP Valid Flag\n");
Linus Torvalds's avatar
Linus Torvalds committed
388
389
390
391
392
			return -1;
		}
		es7000_spin(MIP_SPIN);
	}

Ingo Molnar's avatar
Ingo Molnar committed
393
394
395
	status = (mip_reg->off_0x00 & 0xffff0000000000ULL) >> 48;
	mip_reg->off_0x38 &= ~MIP_VALID;

Linus Torvalds's avatar
Linus Torvalds committed
396
397
398
	return status;
}

399
static void es7000_enable_apic_mode(void)
Linus Torvalds's avatar
Linus Torvalds committed
400
{
401
402
403
404
	struct mip_reg es7000_mip_reg;
	int mip_status;

	if (!es7000_plat)
Linus Torvalds's avatar
Linus Torvalds committed
405
		return;
406

407
	pr_info("Enabling APIC mode.\n");
408
409
410
	memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
	es7000_mip_reg.off_0x00 = MIP_SW_APIC;
	es7000_mip_reg.off_0x38 = MIP_VALID;
411

Ingo Molnar's avatar
Ingo Molnar committed
412
413
	while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
		WARN(1, "Command failed, status = %x\n", mip_status);
Linus Torvalds's avatar
Linus Torvalds committed
414
}
Ingo Molnar's avatar
Ingo Molnar committed
415

416
static void es7000_vector_allocation_domain(int cpu, struct cpumask *retmask)
Ingo Molnar's avatar
Ingo Molnar committed
417
418
419
420
421
422
423
424
425
{
	/* Careful. Some cpus do not strictly honor the set of cpus
	 * specified in the interrupt destination when using lowest
	 * priority interrupt delivery mode.
	 *
	 * In particular there was a hyperthreading cpu observed to
	 * deliver interrupts to the wrong hyperthread when only one
	 * hyperthread was specified in the interrupt desitination.
	 */
426
427
	cpumask_clear(retmask);
	cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
Ingo Molnar's avatar
Ingo Molnar committed
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
}


static void es7000_wait_for_init_deassert(atomic_t *deassert)
{
	while (!atomic_read(deassert))
		cpu_relax();
}

static unsigned int es7000_get_apic_id(unsigned long x)
{
	return (x >> 24) & 0xFF;
}

static void es7000_send_IPI_mask(const struct cpumask *mask, int vector)
{
444
	default_send_IPI_mask_sequence_phys(mask, vector);
Ingo Molnar's avatar
Ingo Molnar committed
445
446
447
448
}

static void es7000_send_IPI_allbutself(int vector)
{
449
	default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
Ingo Molnar's avatar
Ingo Molnar committed
450
451
452
453
454
455
456
457
458
}

static void es7000_send_IPI_all(int vector)
{
	es7000_send_IPI_mask(cpu_online_mask, vector);
}

static int es7000_apic_id_registered(void)
{
459
	return 1;
Ingo Molnar's avatar
Ingo Molnar committed
460
461
}

462
static const struct cpumask *target_cpus_cluster(void)
Ingo Molnar's avatar
Ingo Molnar committed
463
{
464
	return cpu_all_mask;
Ingo Molnar's avatar
Ingo Molnar committed
465
466
}

467
static const struct cpumask *es7000_target_cpus(void)
Ingo Molnar's avatar
Ingo Molnar committed
468
{
469
	return cpumask_of(smp_processor_id());
Ingo Molnar's avatar
Ingo Molnar committed
470
471
}

472
static unsigned long es7000_check_apicid_used(physid_mask_t *map, int apicid)
Ingo Molnar's avatar
Ingo Molnar committed
473
474
475
{
	return 0;
}
476

Ingo Molnar's avatar
Ingo Molnar committed
477
478
479
480
481
482
483
static unsigned long es7000_check_apicid_present(int bit)
{
	return physid_isset(bit, phys_cpu_present_map);
}

static unsigned long calculate_ldr(int cpu)
{
Ingo Molnar's avatar
Ingo Molnar committed
484
	unsigned long id = per_cpu(x86_bios_cpu_apicid, cpu);
Ingo Molnar's avatar
Ingo Molnar committed
485

Ingo Molnar's avatar
Ingo Molnar committed
486
	return SET_APIC_LOGICAL_ID(id);
Ingo Molnar's avatar
Ingo Molnar committed
487
488
489
490
491
492
493
494
495
496
497
498
499
500
}

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

501
	apic_write(APIC_DFR, APIC_DFR_CLUSTER);
Ingo Molnar's avatar
Ingo Molnar committed
502
503
504
505
506
507
508
509
510
	val = calculate_ldr(cpu);
	apic_write(APIC_LDR, val);
}

static void es7000_init_apic_ldr(void)
{
	unsigned long val;
	int cpu = smp_processor_id();

511
	apic_write(APIC_DFR, APIC_DFR_FLAT);
Ingo Molnar's avatar
Ingo Molnar committed
512
513
514
515
516
517
518
	val = calculate_ldr(cpu);
	apic_write(APIC_LDR, val);
}

static void es7000_setup_apic_routing(void)
{
	int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id());
Ingo Molnar's avatar
Ingo Molnar committed
519

520
	pr_info("Enabling APIC mode:  %s. Using %d I/O APICs, target cpus %lx\n",
Ingo Molnar's avatar
Ingo Molnar committed
521
522
		(apic_version[apic] == 0x14) ?
			"Physical Cluster" : "Logical Cluster",
523
		nr_ioapics, cpumask_bits(es7000_target_cpus())[0]);
Ingo Molnar's avatar
Ingo Molnar committed
524
525
526
527
528
529
530
531
532
533
534
535
536
}

static int es7000_apicid_to_node(int logical_apicid)
{
	return 0;
}


static int es7000_cpu_present_to_apicid(int mps_cpu)
{
	if (!mps_cpu)
		return boot_cpu_physical_apicid;
	else if (mps_cpu < nr_cpu_ids)
Ingo Molnar's avatar
Ingo Molnar committed
537
		return per_cpu(x86_bios_cpu_apicid, mps_cpu);
Ingo Molnar's avatar
Ingo Molnar committed
538
539
540
541
	else
		return BAD_APICID;
}

Ingo Molnar's avatar
Ingo Molnar committed
542
543
static int cpu_id;

544
static void es7000_apicid_to_cpu_present(int phys_apicid, physid_mask_t *retmap)
Ingo Molnar's avatar
Ingo Molnar committed
545
{
546
	physid_set_mask_of_physid(cpu_id, retmap);
Ingo Molnar's avatar
Ingo Molnar committed
547
	++cpu_id;
Ingo Molnar's avatar
Ingo Molnar committed
548
549
550
551
552
553
554
555
}

/* Mapping from cpu number to logical apicid */
static int es7000_cpu_to_logical_apicid(int cpu)
{
#ifdef CONFIG_SMP
	if (cpu >= nr_cpu_ids)
		return BAD_APICID;
556
	return cpu_2_logical_apicid[cpu];
Ingo Molnar's avatar
Ingo Molnar committed
557
558
559
560
561
#else
	return logical_smp_processor_id();
#endif
}

562
static void es7000_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
Ingo Molnar's avatar
Ingo Molnar committed
563
564
{
	/* For clustered we don't have a good way to do this yet - hack */
565
	physids_promote(0xFFL, retmap);
Ingo Molnar's avatar
Ingo Molnar committed
566
567
568
569
570
}

static int es7000_check_phys_apicid_present(int cpu_physical_apicid)
{
	boot_cpu_physical_apicid = read_apic_id();
Ingo Molnar's avatar
Ingo Molnar committed
571
	return 1;
Ingo Molnar's avatar
Ingo Molnar committed
572
573
}

574
static unsigned int es7000_cpu_mask_to_apicid(const struct cpumask *cpumask)
Ingo Molnar's avatar
Ingo Molnar committed
575
{
576
577
	unsigned int round = 0;
	int cpu, uninitialized_var(apicid);
Ingo Molnar's avatar
Ingo Molnar committed
578
579

	/*
580
	 * The cpus in the mask must all be on the apic cluster.
Ingo Molnar's avatar
Ingo Molnar committed
581
	 */
582
583
	for_each_cpu(cpu, cpumask) {
		int new_apicid = es7000_cpu_to_logical_apicid(cpu);
Ingo Molnar's avatar
Ingo Molnar committed
584

585
586
		if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
			WARN(1, "Not a valid mask!");
Ingo Molnar's avatar
Ingo Molnar committed
587

588
			return BAD_APICID;
Ingo Molnar's avatar
Ingo Molnar committed
589
		}
590
591
		apicid = new_apicid;
		round++;
Ingo Molnar's avatar
Ingo Molnar committed
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
	}
	return apicid;
}

static unsigned int
es7000_cpu_mask_to_apicid_and(const struct cpumask *inmask,
			      const struct cpumask *andmask)
{
	int apicid = es7000_cpu_to_logical_apicid(0);
	cpumask_var_t cpumask;

	if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
		return apicid;

	cpumask_and(cpumask, inmask, andmask);
	cpumask_and(cpumask, cpumask, cpu_online_mask);
	apicid = es7000_cpu_mask_to_apicid(cpumask);

	free_cpumask_var(cpumask);

	return apicid;
}

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

static int probe_es7000(void)
{
	/* probed later in mptable/ACPI hooks */
	return 0;
}

626
627
628
static int es7000_mps_ret;
static int es7000_mps_oem_check(struct mpc_table *mpc, char *oem,
		char *productid)
Ingo Molnar's avatar
Ingo Molnar committed
629
{
630
631
	int ret = 0;

Ingo Molnar's avatar
Ingo Molnar committed
632
633
634
635
636
	if (mpc->oemptr) {
		struct mpc_oemtable *oem_table =
			(struct mpc_oemtable *)mpc->oemptr;

		if (!strncmp(oem, "UNISYS", 6))
637
			ret = parse_unisys_oem((char *)oem_table);
Ingo Molnar's avatar
Ingo Molnar committed
638
	}
639
640
641
642
643
644

	es7000_mps_ret = ret;

	return ret && !es7000_apic_is_cluster();
}

645
646
static int es7000_mps_oem_check_cluster(struct mpc_table *mpc, char *oem,
		char *productid)
647
648
649
650
{
	int ret = es7000_mps_ret;

	return ret && es7000_apic_is_cluster();
Ingo Molnar's avatar
Ingo Molnar committed
651
652
}

653
654
/* We've been warned by a false positive warning.Use __refdata to keep calm. */
struct apic __refdata apic_es7000_cluster = {
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690

	.name				= "es7000",
	.probe				= probe_es7000,
	.acpi_madt_oem_check		= es7000_acpi_madt_oem_check_cluster,
	.apic_id_registered		= es7000_apic_id_registered,

	.irq_delivery_mode		= dest_LowestPrio,
	/* logical delivery broadcast to all procs: */
	.irq_dest_mode			= 1,

	.target_cpus			= target_cpus_cluster,
	.disable_esr			= 1,
	.dest_logical			= 0,
	.check_apicid_used		= es7000_check_apicid_used,
	.check_apicid_present		= es7000_check_apicid_present,

	.vector_allocation_domain	= es7000_vector_allocation_domain,
	.init_apic_ldr			= es7000_init_apic_ldr_cluster,

	.ioapic_phys_id_map		= es7000_ioapic_phys_id_map,
	.setup_apic_routing		= es7000_setup_apic_routing,
	.multi_timer_check		= NULL,
	.apicid_to_node			= es7000_apicid_to_node,
	.cpu_to_logical_apicid		= es7000_cpu_to_logical_apicid,
	.cpu_present_to_apicid		= es7000_cpu_present_to_apicid,
	.apicid_to_cpu_present		= es7000_apicid_to_cpu_present,
	.setup_portio_remap		= NULL,
	.check_phys_apicid_present	= es7000_check_phys_apicid_present,
	.enable_apic_mode		= es7000_enable_apic_mode,
	.phys_pkg_id			= es7000_phys_pkg_id,
	.mps_oem_check			= es7000_mps_oem_check_cluster,

	.get_apic_id			= es7000_get_apic_id,
	.set_apic_id			= NULL,
	.apic_id_mask			= 0xFF << 24,

691
	.cpu_mask_to_apicid		= es7000_cpu_mask_to_apicid,
692
693
694
695
696
697
698
699
	.cpu_mask_to_apicid_and		= es7000_cpu_mask_to_apicid_and,

	.send_IPI_mask			= es7000_send_IPI_mask,
	.send_IPI_mask_allbutself	= NULL,
	.send_IPI_allbutself		= es7000_send_IPI_allbutself,
	.send_IPI_all			= es7000_send_IPI_all,
	.send_IPI_self			= default_send_IPI_self,

700
	.wakeup_secondary_cpu		= wakeup_secondary_cpu_via_mip,
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717

	.trampoline_phys_low		= 0x467,
	.trampoline_phys_high		= 0x469,

	.wait_for_init_deassert		= NULL,

	/* Nothing to do for most platforms, since cleared by the INIT cycle: */
	.smp_callin_clear_local_apic	= NULL,
	.inquire_remote_apic		= default_inquire_remote_apic,

	.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,
};
Ingo Molnar's avatar
Ingo Molnar committed
718

719
struct apic __refdata apic_es7000 = {
Ingo Molnar's avatar
Ingo Molnar committed
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762

	.name				= "es7000",
	.probe				= probe_es7000,
	.acpi_madt_oem_check		= es7000_acpi_madt_oem_check,
	.apic_id_registered		= es7000_apic_id_registered,

	.irq_delivery_mode		= dest_Fixed,
	/* phys delivery to target CPUs: */
	.irq_dest_mode			= 0,

	.target_cpus			= es7000_target_cpus,
	.disable_esr			= 1,
	.dest_logical			= 0,
	.check_apicid_used		= es7000_check_apicid_used,
	.check_apicid_present		= es7000_check_apicid_present,

	.vector_allocation_domain	= es7000_vector_allocation_domain,
	.init_apic_ldr			= es7000_init_apic_ldr,

	.ioapic_phys_id_map		= es7000_ioapic_phys_id_map,
	.setup_apic_routing		= es7000_setup_apic_routing,
	.multi_timer_check		= NULL,
	.apicid_to_node			= es7000_apicid_to_node,
	.cpu_to_logical_apicid		= es7000_cpu_to_logical_apicid,
	.cpu_present_to_apicid		= es7000_cpu_present_to_apicid,
	.apicid_to_cpu_present		= es7000_apicid_to_cpu_present,
	.setup_portio_remap		= NULL,
	.check_phys_apicid_present	= es7000_check_phys_apicid_present,
	.enable_apic_mode		= es7000_enable_apic_mode,
	.phys_pkg_id			= es7000_phys_pkg_id,
	.mps_oem_check			= es7000_mps_oem_check,

	.get_apic_id			= es7000_get_apic_id,
	.set_apic_id			= NULL,
	.apic_id_mask			= 0xFF << 24,

	.cpu_mask_to_apicid		= es7000_cpu_mask_to_apicid,
	.cpu_mask_to_apicid_and		= es7000_cpu_mask_to_apicid_and,

	.send_IPI_mask			= es7000_send_IPI_mask,
	.send_IPI_mask_allbutself	= NULL,
	.send_IPI_allbutself		= es7000_send_IPI_allbutself,
	.send_IPI_all			= es7000_send_IPI_all,
763
	.send_IPI_self			= default_send_IPI_self,
Ingo Molnar's avatar
Ingo Molnar committed
764
765
766
767
768
769
770
771
772

	.trampoline_phys_low		= 0x467,
	.trampoline_phys_high		= 0x469,

	.wait_for_init_deassert		= es7000_wait_for_init_deassert,

	/* Nothing to do for most platforms, since cleared by the INIT cycle: */
	.smp_callin_clear_local_apic	= NULL,
	.inquire_remote_apic		= default_inquire_remote_apic,
Yinghai Lu's avatar
Yinghai Lu committed
773
774
775
776
777
778
779

	.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,
Ingo Molnar's avatar
Ingo Molnar committed
780
};