acpi.c 22.5 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
David Mosberger's avatar
David Mosberger committed
2
 *  acpi.c - Architecture-Specific Low-Level ACPI Support
Linus Torvalds's avatar
Linus Torvalds committed
3
 *
David Mosberger's avatar
David Mosberger committed
4 5
 *  Copyright (C) 1999 VA Linux Systems
 *  Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
6 7
 *  Copyright (C) 2000, 2002 Hewlett-Packard Co.
 *	David Mosberger-Tang <davidm@hpl.hp.com>
David Mosberger's avatar
David Mosberger committed
8 9 10
 *  Copyright (C) 2000 Intel Corp.
 *  Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
 *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
Erich Focht's avatar
Erich Focht committed
11 12 13
 *  Copyright (C) 2001 Jenna Hall <jenna.s.hall@intel.com>
 *  Copyright (C) 2001 Takayoshi Kochi <t-kouchi@cq.jp.nec.com>
 *  Copyright (C) 2002 Erich Focht <efocht@ess.nec.de>
Linus Torvalds's avatar
Linus Torvalds committed
14
 *
David Mosberger's avatar
David Mosberger committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Linus Torvalds's avatar
Linus Torvalds committed
32 33 34 35 36 37 38 39 40 41
 */

#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/irq.h>
David Mosberger's avatar
David Mosberger committed
42
#include <linux/acpi.h>
43
#include <linux/efi.h>
Linus Torvalds's avatar
Linus Torvalds committed
44 45 46 47
#include <asm/io.h>
#include <asm/iosapic.h>
#include <asm/machvec.h>
#include <asm/page.h>
David Mosberger's avatar
David Mosberger committed
48
#include <asm/system.h>
Erich Focht's avatar
Erich Focht committed
49
#include <asm/numa.h>
Linus Torvalds's avatar
Linus Torvalds committed
50

Linus Torvalds's avatar
Linus Torvalds committed
51

David Mosberger's avatar
David Mosberger committed
52
#define PREFIX			"ACPI: "
Linus Torvalds's avatar
Linus Torvalds committed
53

54 55 56
asm (".weak iosapic_register_intr");
asm (".weak iosapic_override_isa_irq");
asm (".weak iosapic_register_platform_intr");
Linus Torvalds's avatar
Linus Torvalds committed
57
asm (".weak iosapic_init");
Linus Torvalds's avatar
Linus Torvalds committed
58
asm (".weak iosapic_version");
Linus Torvalds's avatar
Linus Torvalds committed
59

David Mosberger's avatar
David Mosberger committed
60 61 62
void (*pm_idle) (void);
void (*pm_power_off) (void);

63 64
unsigned char acpi_kbd_controller_present = 1;

David Mosberger's avatar
David Mosberger committed
65 66
int acpi_disabled __initdata;	/* XXX this shouldn't be needed---we can't boot without ACPI! */

Linus Torvalds's avatar
Linus Torvalds committed
67 68 69 70
const char *
acpi_get_sysname (void)
{
#ifdef CONFIG_IA64_GENERIC
71
	unsigned long rsdp_phys;
72 73 74 75
	struct acpi20_table_rsdp *rsdp;
	struct acpi_table_xsdt *xsdt;
	struct acpi_table_header *hdr;

76 77
	rsdp_phys = acpi_find_rsdp();
	if (!rsdp_phys) {
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
		printk("ACPI 2.0 RSDP not found, default to \"dig\"\n");
		return "dig";
	}

	rsdp = (struct acpi20_table_rsdp *) __va(rsdp_phys);
	if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) {
		printk("ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n");
		return "dig";
	}

	xsdt = (struct acpi_table_xsdt *) __va(rsdp->xsdt_address);
	hdr = &xsdt->header;
	if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) {
		printk("ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n");
		return "dig";
	}

	if (!strcmp(hdr->oem_id, "HP")) {
		return "hpzx1";
	}

	return "dig";
Linus Torvalds's avatar
Linus Torvalds committed
100 101 102
#else
# if defined (CONFIG_IA64_HP_SIM)
	return "hpsim";
103 104
# elif defined (CONFIG_IA64_HP_ZX1)
	return "hpzx1";
Linus Torvalds's avatar
Linus Torvalds committed
105 106
# elif defined (CONFIG_IA64_SGI_SN1)
	return "sn1";
Linus Torvalds's avatar
Linus Torvalds committed
107 108
# elif defined (CONFIG_IA64_SGI_SN2)
	return "sn2";
Linus Torvalds's avatar
Linus Torvalds committed
109 110
# elif defined (CONFIG_IA64_DIG)
	return "dig";
111 112
# elif defined (CONFIG_IA64_HP_ZX1)
	return "hpzx1";
Linus Torvalds's avatar
Linus Torvalds committed
113 114 115 116 117 118
# else
#	error Unknown platform.  Fix acpi.c.
# endif
#endif
}

119 120 121 122 123 124 125 126 127 128 129 130
#ifdef CONFIG_ACPI

/**
 * acpi_get_crs - Return the current resource settings for a device
 * obj: A handle for this device
 * buf: A buffer to be populated by this call.
 *
 * Pass a valid handle, typically obtained by walking the namespace and a
 * pointer to an allocated buffer, and this function will fill in the buffer
 * with a list of acpi_resource structures.
 */
acpi_status
David Mosberger's avatar
David Mosberger committed
131
acpi_get_crs (acpi_handle obj, struct acpi_buffer *buf)
132 133 134 135 136 137 138 139 140 141 142 143
{
	acpi_status result;
	buf->length = 0;
	buf->pointer = NULL;

	result = acpi_get_current_resources(obj, buf);
	if (result != AE_BUFFER_OVERFLOW)
		return result;
	buf->pointer = kmalloc(buf->length, GFP_KERNEL);
	if (!buf->pointer)
		return -ENOMEM;

144
	return acpi_get_current_resources(obj, buf);
145 146
}

David Mosberger's avatar
David Mosberger committed
147 148
struct acpi_resource *
acpi_get_crs_next (struct acpi_buffer *buf, int *offset)
149
{
David Mosberger's avatar
David Mosberger committed
150
	struct acpi_resource *res;
151 152 153 154 155 156 157 158 159

	if (*offset >= buf->length)
		return NULL;

	res = buf->pointer + *offset;
	*offset += res->length;
	return res;
}

David Mosberger's avatar
David Mosberger committed
160 161
union acpi_resource_data *
acpi_get_crs_type (struct acpi_buffer *buf, int *offset, int type)
162 163
{
	for (;;) {
David Mosberger's avatar
David Mosberger committed
164
		struct acpi_resource *res = acpi_get_crs_next(buf, offset);
165 166 167 168 169 170 171 172
		if (!res)
			return NULL;
		if (res->id == type)
			return &res->data;
	}
}

void
David Mosberger's avatar
David Mosberger committed
173
acpi_dispose_crs (struct acpi_buffer *buf)
174 175 176 177 178 179
{
	kfree(buf->pointer);
}

#endif /* CONFIG_ACPI */

David Mosberger's avatar
David Mosberger committed
180 181
#ifdef CONFIG_ACPI_BOOT

182
#define ACPI_MAX_PLATFORM_INTERRUPTS	256
David Mosberger's avatar
David Mosberger committed
183 184

/* Array to record platform interrupt vectors for generic interrupt routing. */
185
int platform_intr_list[ACPI_MAX_PLATFORM_INTERRUPTS] = { [0 ... ACPI_MAX_PLATFORM_INTERRUPTS - 1] = -1 };
David Mosberger's avatar
David Mosberger committed
186

187 188
enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC;

Linus Torvalds's avatar
Linus Torvalds committed
189
/*
David Mosberger's avatar
David Mosberger committed
190 191
 * Interrupt routing API for device drivers.  Provides interrupt vector for
 * a generic platform event.  Currently only CPEI is implemented.
Linus Torvalds's avatar
Linus Torvalds committed
192 193
 */
int
David Mosberger's avatar
David Mosberger committed
194
acpi_request_vector (u32 int_type)
Linus Torvalds's avatar
Linus Torvalds committed
195 196 197
{
	int vector = -1;

198
	if (int_type < ACPI_MAX_PLATFORM_INTERRUPTS) {
Linus Torvalds's avatar
Linus Torvalds committed
199
		/* correctable platform error interrupt */
200
		vector = platform_intr_list[int_type];
Linus Torvalds's avatar
Linus Torvalds committed
201 202 203 204 205
	} else
		printk("acpi_request_vector(): invalid interrupt type\n");
	return vector;
}

206 207 208 209 210
char *
__acpi_map_table (unsigned long phys_addr, unsigned long size)
{
	return __va(phys_addr);
}
Linus Torvalds's avatar
Linus Torvalds committed
211

David Mosberger's avatar
David Mosberger committed
212 213 214
/* --------------------------------------------------------------------------
                            Boot-time Table Parsing
   -------------------------------------------------------------------------- */
Linus Torvalds's avatar
Linus Torvalds committed
215

David Mosberger's avatar
David Mosberger committed
216 217 218
static int			total_cpus __initdata;
static int			available_cpus __initdata;
struct acpi_table_madt *	acpi_madt __initdata;
219
static u8			has_8259;
Linus Torvalds's avatar
Linus Torvalds committed
220

David Mosberger's avatar
David Mosberger committed
221 222 223

static int __init
acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header)
Linus Torvalds's avatar
Linus Torvalds committed
224
{
225
	struct acpi_table_lapic_addr_ovr *lapic;
David Mosberger's avatar
David Mosberger committed
226 227 228 229 230 231

	lapic = (struct acpi_table_lapic_addr_ovr *) header;
	if (!lapic)
		return -EINVAL;

	acpi_table_print_madt_entry(header);
Linus Torvalds's avatar
Linus Torvalds committed
232

David Mosberger's avatar
David Mosberger committed
233 234 235 236 237
	if (lapic->address) {
		iounmap((void *) ipi_base_addr);
		ipi_base_addr = (unsigned long) ioremap(lapic->address, 0);
	}
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
238 239
}

David Mosberger's avatar
David Mosberger committed
240 241 242

static int __init
acpi_parse_lsapic (acpi_table_entry_header *header)
Linus Torvalds's avatar
Linus Torvalds committed
243
{
244
	struct acpi_table_lsapic *lsapic;
Linus Torvalds's avatar
Linus Torvalds committed
245

David Mosberger's avatar
David Mosberger committed
246 247 248
	lsapic = (struct acpi_table_lsapic *) header;
	if (!lsapic)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
249

David Mosberger's avatar
David Mosberger committed
250
	acpi_table_print_madt_entry(header);
Linus Torvalds's avatar
Linus Torvalds committed
251

David Mosberger's avatar
David Mosberger committed
252 253 254
	printk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid);

	if (lsapic->flags.enabled) {
Linus Torvalds's avatar
Linus Torvalds committed
255
		available_cpus++;
David Mosberger's avatar
David Mosberger committed
256
		printk(" enabled");
Linus Torvalds's avatar
Linus Torvalds committed
257 258
#ifdef CONFIG_SMP
		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
Linus Torvalds's avatar
Linus Torvalds committed
259 260 261
		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
			printk(" (BSP)");
#endif
Linus Torvalds's avatar
Linus Torvalds committed
262
	}
David Mosberger's avatar
David Mosberger committed
263 264 265 266 267 268 269 270 271
	else {
		printk(" disabled");
#ifdef CONFIG_SMP
		smp_boot_data.cpu_phys_id[total_cpus] = -1;
#endif
	}

	printk("\n");

Linus Torvalds's avatar
Linus Torvalds committed
272
	total_cpus++;
David Mosberger's avatar
David Mosberger committed
273
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
274 275
}

David Mosberger's avatar
David Mosberger committed
276 277 278 279

static int __init
acpi_parse_lapic_nmi (acpi_table_entry_header *header)
{
280
	struct acpi_table_lapic_nmi *lacpi_nmi;
David Mosberger's avatar
David Mosberger committed
281 282 283 284 285 286 287 288 289 290 291 292

	lacpi_nmi = (struct acpi_table_lapic_nmi*) header;
	if (!lacpi_nmi)
		return -EINVAL;

	acpi_table_print_madt_entry(header);

	/* TBD: Support lapic_nmi entries */
	return 0;
}


Linus Torvalds's avatar
Linus Torvalds committed
293
static int __init
294
acpi_find_iosapic (unsigned int gsi, u32 *gsi_base, char **iosapic_address)
Linus Torvalds's avatar
Linus Torvalds committed
295
{
296
	struct acpi_table_iosapic *iosapic;
297 298 299 300
	int ver;
	int max_pin;
	char *p;
	char *end;
Linus Torvalds's avatar
Linus Torvalds committed
301

302
	if (!gsi_base || !iosapic_address)
David Mosberger's avatar
David Mosberger committed
303 304 305 306
		return -ENODEV;

	p = (char *) (acpi_madt + 1);
	end = p + (acpi_madt->header.length - sizeof(struct acpi_table_madt));
Linus Torvalds's avatar
Linus Torvalds committed
307 308

	while (p < end) {
David Mosberger's avatar
David Mosberger committed
309 310 311
		if (*p == ACPI_MADT_IOSAPIC) {
			iosapic = (struct acpi_table_iosapic *) p;

312
			*gsi_base = iosapic->global_irq_base;
Linus Torvalds's avatar
Linus Torvalds committed
313
			*iosapic_address = ioremap(iosapic->address, 0);
David Mosberger's avatar
David Mosberger committed
314

Linus Torvalds's avatar
Linus Torvalds committed
315 316
			ver = iosapic_version(*iosapic_address);
			max_pin = (ver >> 16) & 0xff;
David Mosberger's avatar
David Mosberger committed
317

318
			if ((gsi - *gsi_base) <= max_pin)
David Mosberger's avatar
David Mosberger committed
319
				return 0;	/* Found it! */
Linus Torvalds's avatar
Linus Torvalds committed
320 321 322
		}
		p += p[1];
	}
David Mosberger's avatar
David Mosberger committed
323
	return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
324 325
}

David Mosberger's avatar
David Mosberger committed
326 327 328

static int __init
acpi_parse_iosapic (acpi_table_entry_header *header)
Linus Torvalds's avatar
Linus Torvalds committed
329
{
David Mosberger's avatar
David Mosberger committed
330
	struct acpi_table_iosapic *iosapic;
Linus Torvalds's avatar
Linus Torvalds committed
331

David Mosberger's avatar
David Mosberger committed
332 333 334
	iosapic = (struct acpi_table_iosapic *) header;
	if (!iosapic)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
335

David Mosberger's avatar
David Mosberger committed
336
	acpi_table_print_madt_entry(header);
Linus Torvalds's avatar
Linus Torvalds committed
337

David Mosberger's avatar
David Mosberger committed
338 339 340 341 342 343 344 345 346
	if (iosapic_init) {
#ifndef CONFIG_ITANIUM
		/* PCAT_COMPAT flag indicates dual-8259 setup */
		iosapic_init(iosapic->address, iosapic->global_irq_base,
			     acpi_madt->flags.pcat_compat);
#else
		/* Firmware on old Itanium systems is broken */
		iosapic_init(iosapic->address, iosapic->global_irq_base, 1);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
347
	}
David Mosberger's avatar
David Mosberger committed
348 349 350 351 352 353 354
	return 0;
}


static int __init
acpi_parse_plat_int_src (acpi_table_entry_header *header)
{
355
	struct acpi_table_plat_int_src *plintsrc;
356
	int vector;
357
	u32 gsi_base;
358
	char *iosapic_address;
Linus Torvalds's avatar
Linus Torvalds committed
359

David Mosberger's avatar
David Mosberger committed
360 361 362 363 364 365
	plintsrc = (struct acpi_table_plat_int_src *) header;
	if (!plintsrc)
		return -EINVAL;

	acpi_table_print_madt_entry(header);

366 367
	if (!iosapic_register_platform_intr) {
		printk(KERN_WARNING PREFIX "No ACPI platform interrupt support\n");
David Mosberger's avatar
David Mosberger committed
368
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
369 370
	}

371
	if (acpi_find_iosapic(plintsrc->global_irq, &gsi_base, &iosapic_address)) {
David Mosberger's avatar
David Mosberger committed
372 373
		printk(KERN_WARNING PREFIX "IOSAPIC not found\n");
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
374 375 376
	}

	/*
377 378
	 * Get vector assignment for this interrupt, set attributes,
	 * and program the IOSAPIC routing table.
Linus Torvalds's avatar
Linus Torvalds committed
379
	 */
380 381 382 383 384 385 386 387 388 389 390
	vector = iosapic_register_platform_intr(plintsrc->type,
						plintsrc->global_irq,
						plintsrc->iosapic_vector,
						plintsrc->eid,
						plintsrc->id,
						(plintsrc->flags.polarity == 1) ? 1 : 0,
						(plintsrc->flags.trigger == 1) ? 1 : 0,
						gsi_base,
						iosapic_address);

	platform_intr_list[plintsrc->type] = vector;
David Mosberger's avatar
David Mosberger committed
391
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
392 393
}

David Mosberger's avatar
David Mosberger committed
394 395 396

static int __init
acpi_parse_int_src_ovr (acpi_table_entry_header *header)
Linus Torvalds's avatar
Linus Torvalds committed
397
{
398
	struct acpi_table_int_src_ovr *p;
Linus Torvalds's avatar
Linus Torvalds committed
399

David Mosberger's avatar
David Mosberger committed
400 401 402
	p = (struct acpi_table_int_src_ovr *) header;
	if (!p)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
403

David Mosberger's avatar
David Mosberger committed
404 405 406
	acpi_table_print_madt_entry(header);

	/* Ignore if the platform doesn't support overrides */
407
	if (!iosapic_override_isa_irq)
David Mosberger's avatar
David Mosberger committed
408 409
		return 0;

410 411 412
	iosapic_override_isa_irq(p->bus_irq, p->global_irq,
				 (p->flags.polarity == 1) ? 1 : 0,
				 (p->flags.trigger == 1) ? 1 : 0);
David Mosberger's avatar
David Mosberger committed
413
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
414 415
}

David Mosberger's avatar
David Mosberger committed
416 417 418

static int __init
acpi_parse_nmi_src (acpi_table_entry_header *header)
Linus Torvalds's avatar
Linus Torvalds committed
419
{
420
	struct acpi_table_nmi_src *nmi_src;
Linus Torvalds's avatar
Linus Torvalds committed
421

David Mosberger's avatar
David Mosberger committed
422 423 424
	nmi_src = (struct acpi_table_nmi_src*) header;
	if (!nmi_src)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
425

David Mosberger's avatar
David Mosberger committed
426
	acpi_table_print_madt_entry(header);
Linus Torvalds's avatar
Linus Torvalds committed
427

David Mosberger's avatar
David Mosberger committed
428 429 430
	/* TBD: Support nimsrc entries */
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
431

Linus Torvalds's avatar
Linus Torvalds committed
432

David Mosberger's avatar
David Mosberger committed
433 434 435 436 437 438 439
static int __init
acpi_parse_madt (unsigned long phys_addr, unsigned long size)
{
	if (!phys_addr || !size)
		return -EINVAL;

	acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
Linus Torvalds's avatar
Linus Torvalds committed
440

441 442 443
	/* remember the value for reference after free_initmem() */
	has_8259 = acpi_madt->flags.pcat_compat;

David Mosberger's avatar
David Mosberger committed
444 445 446
	/* Get base address of IPI Message Block */

	if (acpi_madt->lapic_address)
447
		ipi_base_addr = (unsigned long) ioremap(acpi_madt->lapic_address, 0);
David Mosberger's avatar
David Mosberger committed
448 449 450

	printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr);
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
451 452
}

453

Erich Focht's avatar
Erich Focht committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
#ifdef CONFIG_ACPI_NUMA

#define SLIT_DEBUG

#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32)

static int __initdata srat_num_cpus;			/* number of cpus */
static u32 __initdata pxm_flag[PXM_FLAG_LEN];
#define pxm_bit_set(bit)	(set_bit(bit,(void *)pxm_flag))
#define pxm_bit_test(bit)	(test_bit(bit,(void *)pxm_flag))
/* maps to convert between proximity domain and logical node ID */
int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS];
int __initdata nid_to_pxm_map[NR_NODES];
static struct acpi_table_slit __initdata *slit_table;

/*
 * ACPI 2.0 SLIT (System Locality Information Table)
 * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf
 */
void __init
acpi_numa_slit_init (struct acpi_table_slit *slit)
{
	u32 len;

	len = sizeof(struct acpi_table_header) + 8
		+ slit->localities * slit->localities;
	if (slit->header.length != len) {
		printk("ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n",
		      len, slit->header.length);
		memset(numa_slit, 10, sizeof(numa_slit));
		return;
	}
	slit_table = slit;
}

void __init
acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa)
{
	/* record this node in proximity bitmap */
	pxm_bit_set(pa->proximity_domain);

	node_cpuid[srat_num_cpus].phys_id = (pa->apic_id << 8) | (pa->lsapic_eid);
	/* nid should be overridden as logical node id later */
	node_cpuid[srat_num_cpus].nid = pa->proximity_domain;
	srat_num_cpus++;
}

void __init
acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma)
{
504
	unsigned long paddr, size, hole_size, min_hole_size;
Erich Focht's avatar
Erich Focht committed
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
	u8 pxm;
	struct node_memblk_s *p, *q, *pend;

	pxm = ma->proximity_domain;

	/* fill node memory chunk structure */
	paddr = ma->base_addr_hi;
	paddr = (paddr << 32) | ma->base_addr_lo;
	size = ma->length_hi;
	size = (size << 32) | ma->length_lo;

	if (num_memblks >= NR_MEMBLKS) {
		printk("Too many mem chunks in SRAT. Ignoring %ld MBytes at %lx\n",
			size/(1024*1024), paddr);
		return;
	}

522 523 524 525
	/* Ignore disabled entries */
	if (!ma->flags.enabled)
		return;

526 527 528 529 530
	/*
	 * When the chunk is not the first one in the node, check distance
	 * from the other chunks. When the hole is too huge ignore the chunk.
	 * This restriction should be removed when multiple chunks per node
	 * is supported.
531
	 */
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
	pend = &node_memblk[num_memblks];
	min_hole_size = 0;
	for (p = &node_memblk[0]; p < pend; p++) {
		if (p->nid != pxm)
			continue;
		if (p->start_paddr < paddr)
			hole_size = paddr - (p->start_paddr + p->size);
		else
			hole_size = p->start_paddr - (paddr + size);

		if (!min_hole_size || hole_size < min_hole_size)
			min_hole_size = hole_size;
	}

	if (min_hole_size) {
		if (min_hole_size > size) {
			printk("Too huge memory hole. Ignoring %ld MBytes at %lx\n",
				size/(1024*1024), paddr);
			return;
		}
	}

554 555 556
	/* record this node in proximity bitmap */
	pxm_bit_set(pxm);

Erich Focht's avatar
Erich Focht committed
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
	/* Insertion sort based on base address */
	pend = &node_memblk[num_memblks];
	for (p = &node_memblk[0]; p < pend; p++) {
		if (paddr < p->start_paddr)
			break;
	}
	if (p < pend) {
		for (q = pend; q >= p; q--)
			*(q + 1) = *q;
	}
	p->start_paddr = paddr;
	p->size = size;
	p->nid = pxm;
	num_memblks++;
}

void __init
acpi_numa_arch_fixup(void)
{
576
	int i, j, node_from, node_to;
Erich Focht's avatar
Erich Focht committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 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 626 627 628 629 630 631 632 633 634 635 636

	/* calculate total number of nodes in system from PXM bitmap */
	numnodes = 0;		/* init total nodes in system */

	memset(pxm_to_nid_map, -1, sizeof(pxm_to_nid_map));
	memset(nid_to_pxm_map, -1, sizeof(nid_to_pxm_map));
	for (i = 0; i < MAX_PXM_DOMAINS; i++) {
		if (pxm_bit_test(i)) {
			pxm_to_nid_map[i] = numnodes;
			nid_to_pxm_map[numnodes++] = i;
		}
	}

	/* set logical node id in memory chunk structure */
	for (i = 0; i < num_memblks; i++)
		node_memblk[i].nid = pxm_to_nid_map[node_memblk[i].nid];

	/* assign memory bank numbers for each chunk on each node */
	for (i = 0; i < numnodes; i++) {
		int bank;

		bank = 0;
		for (j = 0; j < num_memblks; j++)
			if (node_memblk[j].nid == i)
				node_memblk[j].bank = bank++;
	}

	/* set logical node id in cpu structure */
	for (i = 0; i < srat_num_cpus; i++)
		node_cpuid[i].nid = pxm_to_nid_map[node_cpuid[i].nid];

	printk("Number of logical nodes in system = %d\n", numnodes);
	printk("Number of memory chunks in system = %d\n", num_memblks);

	if (!slit_table) return;
	memset(numa_slit, -1, sizeof(numa_slit));
	for (i=0; i<slit_table->localities; i++) {
		if (!pxm_bit_test(i))
			continue;
		node_from = pxm_to_nid_map[i];
		for (j=0; j<slit_table->localities; j++) {
			if (!pxm_bit_test(j))
				continue;
			node_to = pxm_to_nid_map[j];
			node_distance(node_from, node_to) = 
				slit_table->entry[i*slit_table->localities + j];
		}
	}

#ifdef SLIT_DEBUG
	printk("ACPI 2.0 SLIT locality table:\n");
	for (i = 0; i < numnodes; i++) {
		for (j = 0; j < numnodes; j++)
			printk("%03d ", node_distance(i,j));
		printk("\n");
	}
#endif
}
#endif /* CONFIG_ACPI_NUMA */

637 638 639 640
static int __init
acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
{
	struct acpi_table_header *fadt_header;
David Mosberger's avatar
David Mosberger committed
641
	struct fadt_descriptor_rev2 *fadt;
642 643
	u32 sci_irq, gsi_base;
	char *iosapic_address;
644 645 646 647 648 649 650 651

	if (!phys_addr || !size)
		return -EINVAL;

	fadt_header = (struct acpi_table_header *) __va(phys_addr);
	if (fadt_header->revision != 3)
		return -ENODEV;		/* Only deal with ACPI 2.0 FADT */

David Mosberger's avatar
David Mosberger committed
652
	fadt = (struct fadt_descriptor_rev2 *) fadt_header;
653 654 655 656

	if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER))
		acpi_kbd_controller_present = 0;

657 658 659 660 661 662 663 664 665 666
	if (!iosapic_register_intr)
		return 0;	/* just ignore the rest */

	sci_irq = fadt->sci_int;

	if (has_8259 && sci_irq < 16)
		return 0;	/* legacy, no setup required */

	if (!acpi_find_iosapic(sci_irq, &gsi_base, &iosapic_address))
		iosapic_register_intr(sci_irq, 0, 0, gsi_base, iosapic_address);
667 668 669
	return 0;
}

670

671 672
unsigned long __init
acpi_find_rsdp (void)
Linus Torvalds's avatar
Linus Torvalds committed
673
{
674
	unsigned long rsdp_phys = 0;
Linus Torvalds's avatar
Linus Torvalds committed
675

676 677 678
	if (efi.acpi20)
		rsdp_phys = __pa(efi.acpi20);
	else if (efi.acpi)
David Mosberger's avatar
David Mosberger committed
679
		printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n");
680
	return rsdp_phys;
David Mosberger's avatar
David Mosberger committed
681
}
Linus Torvalds's avatar
Linus Torvalds committed
682 683


David Mosberger's avatar
David Mosberger committed
684
#ifdef CONFIG_SERIAL_8250_ACPI
Linus Torvalds's avatar
Linus Torvalds committed
685

David Mosberger's avatar
David Mosberger committed
686
#include <linux/acpi_serial.h>
Linus Torvalds's avatar
Linus Torvalds committed
687

David Mosberger's avatar
David Mosberger committed
688 689 690
static int __init
acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
{
691
	acpi_ser_t *spcr;
692
	unsigned int gsi;
Linus Torvalds's avatar
Linus Torvalds committed
693

David Mosberger's avatar
David Mosberger committed
694 695
	if (!phys_addr || !size)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
696

697
	if (!iosapic_register_intr)
David Mosberger's avatar
David Mosberger committed
698
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
699

Linus Torvalds's avatar
Linus Torvalds committed
700
	/*
David Mosberger's avatar
David Mosberger committed
701 702 703 704 705 706
	 * ACPI is able to describe serial ports that live at non-standard
	 * memory addresses and use non-standard interrupts, either via
	 * direct SAPIC mappings or via PCI interrupts.  We handle interrupt
	 * routing for SAPIC-based (non-PCI) devices here.  Interrupt routing
	 * for PCI devices will be handled when processing the PCI Interrupt
	 * Routing Table (PRT).
Linus Torvalds's avatar
Linus Torvalds committed
707
	 */
David Mosberger's avatar
David Mosberger committed
708 709

	spcr = (acpi_ser_t *) __va(phys_addr);
710

David Mosberger's avatar
David Mosberger committed
711 712 713 714 715 716 717 718 719
	setup_serial_acpi(spcr);

	if (spcr->length < sizeof(acpi_ser_t))
		/* Table not long enough for full info, thus no interrupt */
		return -ENODEV;

	if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) &&
	    (spcr->int_type == ACPI_SERIAL_INT_SAPIC))
	{
720
		u32 gsi_base;
721 722
		char *iosapic_address;
		int vector;
David Mosberger's avatar
David Mosberger committed
723 724 725

		/* We have a UART in memory space with an SAPIC interrupt */

726 727 728 729
		gsi = (  (spcr->global_int[3] << 24) |
			 (spcr->global_int[2] << 16) |
			 (spcr->global_int[1] << 8)  |
			 (spcr->global_int[0])  );
David Mosberger's avatar
David Mosberger committed
730

731
		/* Which iosapic does this interrupt belong to? */
David Mosberger's avatar
David Mosberger committed
732

733 734 735
		if (!acpi_find_iosapic(gsi, &gsi_base, &iosapic_address))
			vector = iosapic_register_intr(gsi, 1, 1,
						       gsi_base, iosapic_address);
Linus Torvalds's avatar
Linus Torvalds committed
736
	}
David Mosberger's avatar
David Mosberger committed
737
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
738 739
}

David Mosberger's avatar
David Mosberger committed
740
#endif /* CONFIG_SERIAL_8250_ACPI */
David Mosberger's avatar
David Mosberger committed
741 742 743 744


int __init
acpi_boot_init (char *cmdline)
Linus Torvalds's avatar
Linus Torvalds committed
745 746
{

David Mosberger's avatar
David Mosberger committed
747 748 749 750 751 752 753
	/*
	 * MADT
	 * ----
	 * Parse the Multiple APIC Description Table (MADT), if exists.
	 * Note that this table provides platform SMP configuration
	 * information -- the successor to MPS tables.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
754

755 756 757 758
	if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) {
		printk(KERN_ERR PREFIX "Can't find MADT\n");
		goto skip_madt;
	}
Linus Torvalds's avatar
Linus Torvalds committed
759

David Mosberger's avatar
David Mosberger committed
760
	/* Local APIC */
Linus Torvalds's avatar
Linus Torvalds committed
761

762
	if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr) < 0)
David Mosberger's avatar
David Mosberger committed
763
		printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
764

765
	if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic) < 1)
766
		printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n");
Linus Torvalds's avatar
Linus Torvalds committed
767

768
	if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi) < 0)
David Mosberger's avatar
David Mosberger committed
769
		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
770

David Mosberger's avatar
David Mosberger committed
771
	/* I/O APIC */
Linus Torvalds's avatar
Linus Torvalds committed
772

773 774
	if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic) < 1)
		printk(KERN_ERR PREFIX "Error parsing MADT - no IOSAPIC entries\n");
Linus Torvalds's avatar
Linus Torvalds committed
775

David Mosberger's avatar
David Mosberger committed
776
	/* System-Level Interrupt Routing */
Linus Torvalds's avatar
Linus Torvalds committed
777

778
	if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src) < 0)
David Mosberger's avatar
David Mosberger committed
779
		printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
780

781
	if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr) < 0)
David Mosberger's avatar
David Mosberger committed
782
		printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
783

784
	if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src) < 0)
David Mosberger's avatar
David Mosberger committed
785
		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
786
  skip_madt:
787

788 789 790 791 792 793
	/*
	 * FADT says whether a legacy keyboard controller is present.
	 * The FADT also contains an SCI_INT line, by which the system
	 * gets interrupts such as power and sleep buttons.  If it's not
	 * on a Legacy interrupt, it needs to be setup.
	 */
David Mosberger's avatar
David Mosberger committed
794
	if (acpi_table_parse(ACPI_FADT, acpi_parse_fadt) < 1)
795
		printk(KERN_ERR PREFIX "Can't find FADT\n");
Linus Torvalds's avatar
Linus Torvalds committed
796

David Mosberger's avatar
David Mosberger committed
797
#ifdef CONFIG_SERIAL_8250_ACPI
David Mosberger's avatar
David Mosberger committed
798 799 800 801 802 803 804
	/*
	 * TBD: Need phased approach to table parsing (only do those absolutely
	 *      required during boot-up).  Recommend expanding concept of fix-
	 *      feature devices (LDM) to include table-based devices such as
	 *      serial ports, EC, SMBus, etc.
	 */
	acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);
805
#endif
David Mosberger's avatar
David Mosberger committed
806 807 808 809 810 811 812

#ifdef CONFIG_SMP
	if (available_cpus == 0) {
		printk("ACPI: Found 0 CPUS; assuming 1\n");
		available_cpus = 1; /* We've got at least one of these, no? */
	}
	smp_boot_data.cpu_count = total_cpus;
813 814

	smp_build_cpu_map();
815 816 817
#ifdef CONFIG_NUMA
	build_cpu_to_node_map();
#endif
David Mosberger's avatar
David Mosberger committed
818 819 820 821
#endif
	/* Make boot-up look pretty */
	printk("%d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
822 823
}

David Mosberger's avatar
David Mosberger committed
824 825 826 827 828

/* --------------------------------------------------------------------------
                             PCI Interrupt Routing
   -------------------------------------------------------------------------- */

Linus Torvalds's avatar
Linus Torvalds committed
829
int __init
David Mosberger's avatar
David Mosberger committed
830
acpi_get_prt (struct pci_vector_struct **vectors, int *count)
Linus Torvalds's avatar
Linus Torvalds committed
831
{
832 833 834
	struct pci_vector_struct *vector;
	struct list_head *node;
	struct acpi_prt_entry *entry;
David Mosberger's avatar
David Mosberger committed
835
	int i = 0;
Linus Torvalds's avatar
Linus Torvalds committed
836

David Mosberger's avatar
David Mosberger committed
837 838
	if (!vectors || !count)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
839

David Mosberger's avatar
David Mosberger committed
840 841 842
	*vectors = NULL;
	*count = 0;

843
	if (acpi_prt.count < 0) {
844
		printk(KERN_ERR PREFIX "No PCI interrupt routing entries\n");
David Mosberger's avatar
David Mosberger committed
845
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
846 847
	}

David Mosberger's avatar
David Mosberger committed
848
	/* Allocate vectors */
Linus Torvalds's avatar
Linus Torvalds committed
849

850
	*vectors = kmalloc(sizeof(struct pci_vector_struct) * acpi_prt.count, GFP_KERNEL);
David Mosberger's avatar
David Mosberger committed
851 852
	if (!(*vectors))
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
853

David Mosberger's avatar
David Mosberger committed
854
	/* Convert PRT entries to IOSAPIC PCI vectors */
Linus Torvalds's avatar
Linus Torvalds committed
855

David Mosberger's avatar
David Mosberger committed
856
	vector = *vectors;
Linus Torvalds's avatar
Linus Torvalds committed
857

858
	list_for_each(node, &acpi_prt.entries) {
David Mosberger's avatar
David Mosberger committed
859
		entry = (struct acpi_prt_entry *)node;
David Mosberger's avatar
David Mosberger committed
860
		vector[i].bus    = entry->id.bus;
861 862 863
		vector[i].pci_id = ((u32) entry->id.device << 16) | 0xffff;
		vector[i].pin    = entry->pin;
		vector[i].irq    = entry->link.index;
David Mosberger's avatar
David Mosberger committed
864
		i++;
Linus Torvalds's avatar
Linus Torvalds committed
865
	}
866
	*count = acpi_prt.count;
David Mosberger's avatar
David Mosberger committed
867 868
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
869

David Mosberger's avatar
David Mosberger committed
870
/* Assume IA64 always use I/O SAPIC */
Linus Torvalds's avatar
Linus Torvalds committed
871

David Mosberger's avatar
David Mosberger committed
872 873 874 875 876 877
int __init
acpi_get_interrupt_model (int *type)
{
        if (!type)
                return -EINVAL;

878
	*type = ACPI_IRQ_MODEL_IOSAPIC;
David Mosberger's avatar
David Mosberger committed
879
        return 0;
Linus Torvalds's avatar
Linus Torvalds committed
880
}
David Mosberger's avatar
David Mosberger committed
881

882 883 884 885 886 887 888 889 890
int
acpi_irq_to_vector (u32 irq)
{
	if (has_8259 && irq < 16)
		return isa_irq_to_vector(irq);

	return gsi_to_vector(irq);
}

891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
int __init
acpi_register_irq (u32 gsi, u32 polarity, u32 trigger)
{
	int vector = 0;
	u32 irq_base;
	char *iosapic_address;

	if (acpi_madt->flags.pcat_compat && (gsi < 16))
		return isa_irq_to_vector(gsi);

	if (!iosapic_register_intr)
		return 0;

	/* Find the IOSAPIC */
	if (!acpi_find_iosapic(gsi, &irq_base, &iosapic_address)) {
		/* Turn it on */
		vector = iosapic_register_intr (gsi, polarity, trigger,
						irq_base, iosapic_address);
	}
	return vector;
}

David Mosberger's avatar
David Mosberger committed
913
#endif /* CONFIG_ACPI_BOOT */