Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6595 serge 1
/*
2
 *  boot.c - Architecture-Specific Low-Level ACPI Boot Support
3
 *
4
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh 
5
 *  Copyright (C) 2001 Jun Nakajima 
6
 *
7
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  (at your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program; if not, write to the Free Software
21
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 *
23
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24
 */
25
 
26
#include 
27
#include 
28
#include 
29
#include 
30
#include 
31
 
32
static inline void outb(u8 v, u16 port)
33
{
34
        asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
35
}
36
static inline u8 inb(u16 port)
37
{
38
        u8 v;
39
        asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
40
        return v;
41
}
42
 
43
 
44
static int __initdata acpi_force = 0;
45
int acpi_disabled;
46
EXPORT_SYMBOL(acpi_disabled);
47
 
48
#ifdef	CONFIG_X86_64
49
# include 
50
#endif				/* X86 */
51
 
52
#define PREFIX			"ACPI: "
53
 
54
int acpi_noirq;				/* skip ACPI IRQ initialization */
55
int acpi_pci_disabled;		/* skip ACPI PCI scan and IRQ initialization */
56
EXPORT_SYMBOL(acpi_pci_disabled);
57
 
58
int acpi_ioapic;
59
int acpi_strict;
60
u8 acpi_sci_flags __initdata;
61
/*
62
 * acpi_pic_sci_set_trigger()
63
 *
64
 * use ELCR to set PIC-mode trigger type for SCI
65
 *
66
 * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
67
 * it may require Edge Trigger -- use "acpi_sci=edge"
68
 *
69
 * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
70
 * for the 8259 PIC.  bit[n] = 1 means irq[n] is Level, otherwise Edge.
71
 * ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
72
 * ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
73
 */
74
 
75
void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
76
{
77
	unsigned int mask = 1 << irq;
78
	unsigned int old, new;
79
 
80
	/* Real old ELCR mask */
81
//	old = inb(0x4d0) | (inb(0x4d1) << 8);
82
 
83
	/*
84
	 * If we use ACPI to set PCI IRQs, then we should clear ELCR
85
	 * since we will set it correctly as we enable the PCI irq
86
	 * routing.
87
	 */
88
	new = acpi_noirq ? old : 0;
89
 
90
	/*
91
	 * Update SCI information in the ELCR, it isn't in the PCI
92
	 * routing tables..
93
	 */
94
	switch (trigger) {
95
	case 1:		/* Edge - clear */
96
		new &= ~mask;
97
		break;
98
	case 3:		/* Level - set */
99
		new |= mask;
100
		break;
101
	}
102
 
103
	if (old == new)
104
		return;
105
 
106
	printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
107
//	outb(new, 0x4d0);
108
//	outb(new >> 8, 0x4d1);
109
}
110
 
111
static int __init acpi_parse_sbf(struct acpi_table_header *table)
112
{
113
	struct acpi_table_boot *sb = (struct acpi_table_boot *)table;
114
 
115
	sbf_port = sb->cmos_index;	/* Save CMOS port */
116
 
117
	return 0;
118
}
119
 
120
#ifdef CONFIG_HPET_TIMER
121
#include 
122
 
123
static struct resource *hpet_res __initdata;
124
 
125
static int __init acpi_parse_hpet(struct acpi_table_header *table)
126
{
127
	struct acpi_table_hpet *hpet_tbl = (struct acpi_table_hpet *)table;
128
 
129
	if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
130
		printk(KERN_WARNING PREFIX "HPET timers must be located in "
131
		       "memory.\n");
132
		return -1;
133
	}
134
 
135
	hpet_address = hpet_tbl->address.address;
136
	hpet_blockid = hpet_tbl->sequence;
137
 
138
	/*
139
	 * Some broken BIOSes advertise HPET at 0x0. We really do not
140
	 * want to allocate a resource there.
141
	 */
142
	if (!hpet_address) {
143
		printk(KERN_WARNING PREFIX
144
		       "HPET id: %#x base: %#lx is invalid\n",
145
		       hpet_tbl->id, hpet_address);
146
		return 0;
147
	}
148
#ifdef CONFIG_X86_64
149
	/*
150
	 * Some even more broken BIOSes advertise HPET at
151
	 * 0xfed0000000000000 instead of 0xfed00000. Fix it up and add
152
	 * some noise:
153
	 */
154
	if (hpet_address == 0xfed0000000000000UL) {
155
		if (!hpet_force_user) {
156
			printk(KERN_WARNING PREFIX "HPET id: %#x "
157
			       "base: 0xfed0000000000000 is bogus\n "
158
			       "try hpet=force on the kernel command line to "
159
			       "fix it up to 0xfed00000.\n", hpet_tbl->id);
160
			hpet_address = 0;
161
			return 0;
162
		}
163
		printk(KERN_WARNING PREFIX
164
		       "HPET id: %#x base: 0xfed0000000000000 fixed up "
165
		       "to 0xfed00000.\n", hpet_tbl->id);
166
		hpet_address >>= 32;
167
	}
168
#endif
169
	printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
170
	       hpet_tbl->id, hpet_address);
171
 
172
	/*
173
	 * Allocate and initialize the HPET firmware resource for adding into
174
	 * the resource tree during the lateinit timeframe.
175
	 */
176
#define HPET_RESOURCE_NAME_SIZE 9
177
	hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
178
 
179
	hpet_res->name = (void *)&hpet_res[1];
180
	hpet_res->flags = IORESOURCE_MEM;
181
	snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
182
		 hpet_tbl->sequence);
183
 
184
	hpet_res->start = hpet_address;
185
	hpet_res->end = hpet_address + (1 * 1024) - 1;
186
 
187
	return 0;
188
}
189
 
190
/*
191
 * hpet_insert_resource inserts the HPET resources used into the resource
192
 * tree.
193
 */
194
static __init int hpet_insert_resource(void)
195
{
196
	if (!hpet_res)
197
		return 1;
198
 
199
	return insert_resource(&iomem_resource, hpet_res);
200
}
201
 
202
late_initcall(hpet_insert_resource);
203
 
204
#else
205
#define	acpi_parse_hpet	NULL
206
#endif
207
 
208
static int __init acpi_parse_fadt(struct acpi_table_header *table)
209
{
210
 
211
#ifdef CONFIG_X86_PM_TIMER
212
	/* detect the location of the ACPI PM Timer */
213
	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
214
		/* FADT rev. 2 */
215
		if (acpi_gbl_FADT.xpm_timer_block.space_id !=
216
		    ACPI_ADR_SPACE_SYSTEM_IO)
217
			return 0;
218
 
219
		pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
220
		/*
221
		 * "X" fields are optional extensions to the original V1.0
222
		 * fields, so we must selectively expand V1.0 fields if the
223
		 * corresponding X field is zero.
224
	 	 */
225
		if (!pmtmr_ioport)
226
			pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
227
	} else {
228
		/* FADT rev. 1 */
229
		pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
230
	}
231
	if (pmtmr_ioport)
232
		printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
233
		       pmtmr_ioport);
234
#endif
235
	return 0;
236
}
237
 
238
 
239
#ifdef	CONFIG_X86_IO_APIC
240
#else
241
static inline int acpi_parse_madt_ioapic_entries(void)
242
{
243
	return -1;
244
}
245
#endif	/* !CONFIG_X86_IO_APIC */
246
 
247
static void __init early_acpi_process_madt(void)
248
{
249
#ifdef CONFIG_X86_LOCAL_APIC
250
	int error;
251
 
252
	if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
253
 
254
		/*
255
		 * Parse MADT LAPIC entries
256
		 */
257
		error = early_acpi_parse_madt_lapic_addr_ovr();
258
		if (!error) {
259
			acpi_lapic = 1;
260
			smp_found_config = 1;
261
		}
262
		if (error == -EINVAL) {
263
			/*
264
			 * Dell Precision Workstation 410, 610 come here.
265
			 */
266
			printk(KERN_ERR PREFIX
267
			       "Invalid BIOS MADT, disabling ACPI\n");
268
			disable_acpi();
269
		}
270
	}
271
#endif
272
}
273
 
274
static void __init acpi_process_madt(void)
275
{
276
#ifdef CONFIG_X86_LOCAL_APIC
277
	int error;
278
 
279
	if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
280
 
281
		/*
282
		 * Parse MADT LAPIC entries
283
		 */
284
		error = acpi_parse_madt_lapic_entries();
285
		if (!error) {
286
			acpi_lapic = 1;
287
 
288
			/*
289
			 * Parse MADT IO-APIC entries
290
			 */
291
			mutex_lock(&acpi_ioapic_lock);
292
			error = acpi_parse_madt_ioapic_entries();
293
			mutex_unlock(&acpi_ioapic_lock);
294
			if (!error) {
295
				acpi_set_irq_model_ioapic();
296
 
297
				smp_found_config = 1;
298
			}
299
		}
300
		if (error == -EINVAL) {
301
			/*
302
			 * Dell Precision Workstation 410, 610 come here.
303
			 */
304
			printk(KERN_ERR PREFIX
305
			       "Invalid BIOS MADT, disabling ACPI\n");
306
			disable_acpi();
307
		}
308
	} else {
309
		/*
310
 		 * ACPI found no MADT, and so ACPI wants UP PIC mode.
311
 		 * In the event an MPS table was found, forget it.
312
 		 * Boot with "acpi=off" to use MPS on such a system.
313
 		 */
314
		if (smp_found_config) {
315
			printk(KERN_WARNING PREFIX
316
				"No APIC-table, disabling MPS\n");
317
			smp_found_config = 0;
318
		}
319
	}
320
 
321
	/*
322
	 * ACPI supports both logical (e.g. Hyper-Threading) and physical
323
	 * processors, where MPS only supports physical.
324
	 */
325
	if (acpi_lapic && acpi_ioapic)
326
		printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
327
		       "information\n");
328
	else if (acpi_lapic)
329
		printk(KERN_INFO "Using ACPI for processor (LAPIC) "
330
		       "configuration information\n");
331
#endif
332
	return;
333
}
334
 
335
static int __init disable_acpi_irq(const struct dmi_system_id *d)
336
{
337
	if (!acpi_force) {
338
		printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
339
		       d->ident);
340
		acpi_noirq_set();
341
	}
342
	return 0;
343
}
344
 
345
static int __init disable_acpi_pci(const struct dmi_system_id *d)
346
{
347
	if (!acpi_force) {
348
		printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
349
		       d->ident);
350
		acpi_disable_pci();
351
	}
352
	return 0;
353
}
354
 
355
static int __init dmi_disable_acpi(const struct dmi_system_id *d)
356
{
357
	if (!acpi_force) {
358
		printk(KERN_NOTICE "%s detected: acpi off\n", d->ident);
359
		disable_acpi();
360
	} else {
361
		printk(KERN_NOTICE
362
		       "Warning: DMI blacklist says broken, but acpi forced\n");
363
	}
364
	return 0;
365
}
366
 
367
/*
368
 * Force ignoring BIOS IRQ0 override
369
 */
370
static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
371
{
372
	if (!acpi_skip_timer_override) {
373
		pr_notice("%s detected: Ignoring BIOS IRQ0 override\n",
374
			d->ident);
375
		acpi_skip_timer_override = 1;
376
	}
377
	return 0;
378
}
379
 
380
/*
381
 * If your system is blacklisted here, but you find that acpi=force
382
 * works for you, please contact linux-acpi@vger.kernel.org
383
 */
384
static struct dmi_system_id __initdata acpi_dmi_table[] = {
385
	/*
386
	 * Boxes that need ACPI disabled
387
	 */
388
	{
389
	 .callback = dmi_disable_acpi,
390
	 .ident = "IBM Thinkpad",
391
	 .matches = {
392
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
393
		     DMI_MATCH(DMI_BOARD_NAME, "2629H1G"),
394
		     },
395
	 },
396
 
397
	/*
398
	 * Boxes that need ACPI PCI IRQ routing disabled
399
	 */
400
	{
401
	 .callback = disable_acpi_irq,
402
	 .ident = "ASUS A7V",
403
	 .matches = {
404
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
405
		     DMI_MATCH(DMI_BOARD_NAME, ""),
406
		     /* newer BIOS, Revision 1011, does work */
407
		     DMI_MATCH(DMI_BIOS_VERSION,
408
			       "ASUS A7V ACPI BIOS Revision 1007"),
409
		     },
410
	 },
411
	{
412
		/*
413
		 * Latest BIOS for IBM 600E (1.16) has bad pcinum
414
		 * for LPC bridge, which is needed for the PCI
415
		 * interrupt links to work. DSDT fix is in bug 5966.
416
		 * 2645, 2646 model numbers are shared with 600/600E/600X
417
		 */
418
	 .callback = disable_acpi_irq,
419
	 .ident = "IBM Thinkpad 600 Series 2645",
420
	 .matches = {
421
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
422
		     DMI_MATCH(DMI_BOARD_NAME, "2645"),
423
		     },
424
	 },
425
	{
426
	 .callback = disable_acpi_irq,
427
	 .ident = "IBM Thinkpad 600 Series 2646",
428
	 .matches = {
429
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
430
		     DMI_MATCH(DMI_BOARD_NAME, "2646"),
431
		     },
432
	 },
433
	/*
434
	 * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
435
	 */
436
	{			/* _BBN 0 bug */
437
	 .callback = disable_acpi_pci,
438
	 .ident = "ASUS PR-DLS",
439
	 .matches = {
440
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
441
		     DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"),
442
		     DMI_MATCH(DMI_BIOS_VERSION,
443
			       "ASUS PR-DLS ACPI BIOS Revision 1010"),
444
		     DMI_MATCH(DMI_BIOS_DATE, "03/21/2003")
445
		     },
446
	 },
447
	{
448
	 .callback = disable_acpi_pci,
449
	 .ident = "Acer TravelMate 36x Laptop",
450
	 .matches = {
451
		     DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
452
		     DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
453
		     },
454
	 },
455
	{}
456
};
457
 
458
/* second table for DMI checks that should run after early-quirks */
459
static struct dmi_system_id __initdata acpi_dmi_table_late[] = {
460
	/*
461
	 * HP laptops which use a DSDT reporting as HP/SB400/10000,
462
	 * which includes some code which overrides all temperature
463
	 * trip points to 16C if the INTIN2 input of the I/O APIC
464
	 * is enabled.  This input is incorrectly designated the
465
	 * ISA IRQ 0 via an interrupt source override even though
466
	 * it is wired to the output of the master 8259A and INTIN0
467
	 * is not connected at all.  Force ignoring BIOS IRQ0
468
	 * override in that cases.
469
	 */
470
	{
471
	 .callback = dmi_ignore_irq0_timer_override,
472
	 .ident = "HP nx6115 laptop",
473
	 .matches = {
474
		     DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
475
		     DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6115"),
476
		     },
477
	 },
478
	{
479
	 .callback = dmi_ignore_irq0_timer_override,
480
	 .ident = "HP NX6125 laptop",
481
	 .matches = {
482
		     DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
483
		     DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"),
484
		     },
485
	 },
486
	{
487
	 .callback = dmi_ignore_irq0_timer_override,
488
	 .ident = "HP NX6325 laptop",
489
	 .matches = {
490
		     DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
491
		     DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
492
		     },
493
	 },
494
	{
495
	 .callback = dmi_ignore_irq0_timer_override,
496
	 .ident = "HP 6715b laptop",
497
	 .matches = {
498
		     DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
499
		     DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6715b"),
500
		     },
501
	 },
502
	{
503
	 .callback = dmi_ignore_irq0_timer_override,
504
	 .ident = "FUJITSU SIEMENS",
505
	 .matches = {
506
		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
507
		     DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"),
508
		     },
509
	 },
510
	{}
511
};
512
 
513
/*
514
 * acpi_boot_table_init() and acpi_boot_init()
515
 *  called from setup_arch(), always.
516
 *	1. checksums all tables
517
 *	2. enumerates lapics
518
 *	3. enumerates io-apics
519
 *
520
 * acpi_table_init() is separate to allow reading SRAT without
521
 * other side effects.
522
 *
523
 * side effects of acpi_boot_init:
524
 *	acpi_lapic = 1 if LAPIC found
525
 *	acpi_ioapic = 1 if IOAPIC found
526
 *	if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
527
 *	if acpi_blacklisted() acpi_disabled = 1;
528
 *	acpi_irq_model=...
529
 *	...
530
 */
531
 
532
void __init acpi_boot_table_init(void)
533
{
534
	dmi_check_system(acpi_dmi_table);
535
 
536
	/*
537
	 * If acpi_disabled, bail out
538
	 */
539
	if (acpi_disabled)
540
		return;
541
 
542
	/*
543
	 * Initialize the ACPI boot-time table parser.
544
	 */
545
	if (acpi_table_init()) {
546
		disable_acpi();
547
		return;
548
	}
549
 
550
	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
551
 
552
	/*
553
	 * blacklist may disable ACPI entirely
554
	 */
555
	if (acpi_blacklisted()) {
556
		if (acpi_force) {
557
			printk(KERN_WARNING PREFIX "acpi=force override\n");
558
		} else {
559
			printk(KERN_WARNING PREFIX "Disabling ACPI support\n");
560
			disable_acpi();
561
			return;
562
		}
563
	}
564
}
565
 
566
int __init early_acpi_boot_init(void)
567
{
568
	/*
569
	 * If acpi_disabled, bail out
570
	 */
571
	if (acpi_disabled)
572
		return 1;
573
 
574
	/*
575
	 * Process the Multiple APIC Description Table (MADT), if present
576
	 */
577
	early_acpi_process_madt();
578
 
579
	/*
580
	 * Hardware-reduced ACPI mode initialization:
581
	 */
582
//	acpi_reduced_hw_init();
583
 
584
	return 0;
585
}
586
 
587
int __init acpi_boot_init(void)
588
{
589
	/* those are executed after early-quirks are executed */
590
	dmi_check_system(acpi_dmi_table_late);
591
 
592
	/*
593
	 * If acpi_disabled, bail out
594
	 */
595
	if (acpi_disabled)
596
		return 1;
597
 
598
//	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
599
 
600
	/*
601
	 * set sci_int and PM timer address
602
	 */
603
	acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
604
 
605
	/*
606
	 * Process the Multiple APIC Description Table (MADT), if present
607
	 */
608
	acpi_process_madt();
609
 
610
	acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
611
 
612
//	if (!acpi_noirq)
613
//		x86_init.pci.init = pci_acpi_init;
614
 
615
	return 0;
616
}