diff options
| -rw-r--r-- | Documentation/acpi/dsdt-initrd.txt | 99 | ||||
| -rw-r--r-- | drivers/acpi/Kconfig | 17 | ||||
| -rw-r--r-- | drivers/acpi/osl.c | 73 | ||||
| -rw-r--r-- | init/initramfs.c | 8 | ||||
| -rw-r--r-- | init/main.c | 7 |
5 files changed, 199 insertions, 5 deletions
diff --git a/Documentation/acpi/dsdt-initrd.txt b/Documentation/acpi/dsdt-initrd.txt new file mode 100644 index 000000000000..736043359dfb --- /dev/null +++ b/Documentation/acpi/dsdt-initrd.txt | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | ACPI Custom DSDT read from initramfs | ||
| 2 | |||
| 3 | 2003 by Markus Gaugusch < dsdt at gaugusch dot at > | ||
| 4 | Special thanks go to Thomas Renninger from SuSE, who updated the patch for | ||
| 5 | 2.6.0 and later modified it to read inside initramfs | ||
| 6 | 2004 - 2008 maintained by Eric Piel < eric dot piel at tremplin-utc dot net > | ||
| 7 | |||
| 8 | This option is intended for people who would like to hack their DSDT and don't | ||
| 9 | want to recompile their kernel after every change. It can also be useful to | ||
| 10 | distros which offers pre-compiled kernels and want to allow their users to use | ||
| 11 | a modified DSDT. In the Kernel config, enable the initial RAM filesystem | ||
| 12 | support (in General Setup) and enable ACPI_CUSTOM_DSDT_INITRD at the ACPI | ||
| 13 | options (General Setup|ACPI Support|Read Custom DSDT from initramfs). | ||
| 14 | |||
| 15 | A custom DSDT (Differentiated System Description Table) is useful when your | ||
| 16 | computer uses ACPI but problems occur due to broken implementation. Typically, | ||
| 17 | your computer works but there are some troubles with the hardware detection or | ||
| 18 | the power management. You can check that troubles come from errors in the DSDT by | ||
| 19 | activating the ACPI debug option and reading the logs. This table is provided | ||
| 20 | by the BIOS, therefore it might be a good idea to check for BIOS update on your | ||
| 21 | vendor website before going any further. Errors are often caused by vendors | ||
| 22 | testing their hardware only with Windows or because there is code which is | ||
| 23 | executed only on a specific OS with a specific version and Linux hasn't been | ||
| 24 | considered during the development. | ||
| 25 | |||
| 26 | Before you run away from customising your DSDT, you should note that already | ||
| 27 | corrected tables are available for a fair amount of computers on this web-page: | ||
| 28 | http://acpi.sf.net/dsdt . Be careful though, to work correctly a DSDT has to | ||
| 29 | match closely the hardware, including the amount of RAM, the frequency of the | ||
| 30 | processor and the PCI cards present! If you are part of the unluckies who | ||
| 31 | cannot find their hardware in this database, you can modify your DSDT by | ||
| 32 | yourself. This process is less painful than it sounds. Download the Intel ASL | ||
| 33 | compiler/decompiler at http://www.intel.com/technology/IAPC/acpi/downloads.htm . | ||
| 34 | As root, you then have to dump your DSDT and decompile it. By using the | ||
| 35 | compiler messages as well as the kernel ACPI debug messages and the reference | ||
| 36 | book (available at the Intel website and also at http://www.acpi.info), it is | ||
| 37 | quite easy to obtain a fully working table. | ||
| 38 | |||
| 39 | Once your new DSDT is ready you'll have to add it to an initramfs so that the | ||
| 40 | kernel can read the table at the very beginning of the boot. As the file has to | ||
| 41 | be accessed very early during the boot process the initramfs has to be an | ||
| 42 | initramfs. The file is contained into the initramfs under the name /DSDT.aml . | ||
| 43 | To obtain such an initramfs, you might have to modify your initramfs script or | ||
| 44 | you can add it later to the initramfs with the script appended to this | ||
| 45 | document. The command will look like: | ||
| 46 | initramfs-add-dsdt initramfs.img my-dsdt.aml | ||
| 47 | |||
| 48 | In case you don't use any initramfs, the possibilities you have are to either | ||
| 49 | start using one (try mkinitrd or yaird), or use the "Include Custom DSDT" | ||
| 50 | configure option to directly include your DSDT inside the kernel. | ||
| 51 | |||
| 52 | The message "Looking for DSDT in initramfs..." will tell you if the DSDT was | ||
| 53 | found or not. If you need to update your DSDT, generate a new initramfs and | ||
| 54 | perform the steps above. Don't forget that with Lilo, you'll have to re-run it. | ||
| 55 | |||
| 56 | |||
| 57 | ====================== Here starts initramfs-add-dsdt ========================== | ||
| 58 | #!/bin/bash | ||
| 59 | # Adds a DSDT file to the initrd (if it's an initramfs) | ||
| 60 | # first argument is the name of archive | ||
| 61 | # second argument is the name of the file to add | ||
| 62 | # The file will be copied as /DSDT.aml | ||
| 63 | |||
| 64 | # 20060126: fix "Premature end of file" with some old cpio (Roland Robic) | ||
| 65 | # 20060205: this time it should really work | ||
| 66 | |||
| 67 | # check the arguments | ||
| 68 | if [ $# -ne 2 ]; then | ||
| 69 | program_name=$(basename $0) | ||
| 70 | echo "\ | ||
| 71 | $program_name: too few arguments | ||
| 72 | Usage: $program_name initrd-name.img DSDT-to-add.aml | ||
| 73 | Adds a DSDT file to an initrd (in initramfs format) | ||
| 74 | |||
| 75 | initrd-name.img: filename of the initrd in initramfs format | ||
| 76 | DSDT-to-add.aml: filename of the DSDT file to add | ||
| 77 | " 1>&2 | ||
| 78 | exit 1 | ||
| 79 | fi | ||
| 80 | |||
| 81 | # we should check it's an initramfs | ||
| 82 | |||
| 83 | tempcpio=$(mktemp -d) | ||
| 84 | # cleanup on exit, hangup, interrupt, quit, termination | ||
| 85 | trap 'rm -rf $tempcpio' 0 1 2 3 15 | ||
| 86 | |||
| 87 | # extract the archive | ||
| 88 | gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1 | ||
| 89 | |||
| 90 | # copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml" | ||
| 91 | cp -f "$2" "$tempcpio"/DSDT.aml | ||
| 92 | |||
| 93 | # add the file | ||
| 94 | cd "$tempcpio" | ||
| 95 | (echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1 | ||
| 96 | cd "$OLDPWD" | ||
| 97 | |||
| 98 | # re-compress the archive | ||
| 99 | gzip -c "$tempcpio"/initramfs.cpio > "$1" | ||
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ccf6ea95f68c..0442ae153a24 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
| @@ -274,6 +274,23 @@ config ACPI_CUSTOM_DSDT_FILE | |||
| 274 | Enter the full path name to the file which includes the AmlCode | 274 | Enter the full path name to the file which includes the AmlCode |
| 275 | declaration. | 275 | declaration. |
| 276 | 276 | ||
| 277 | config ACPI_CUSTOM_DSDT_INITRD | ||
| 278 | bool "Read Custom DSDT from initramfs" | ||
| 279 | depends on BLK_DEV_INITRD | ||
| 280 | default n | ||
| 281 | help | ||
| 282 | The DSDT (Differentiated System Description Table) often needs to be | ||
| 283 | overridden because of broken BIOS implementations. If this feature is | ||
| 284 | activated you will be able to provide a customized DSDT by adding it | ||
| 285 | to your initramfs. If your mkinitrd tool does not support this feature | ||
| 286 | a script is provided in the documentation. For more details see | ||
| 287 | <file:Documentation/dsdt-initrd.txt> or <http://gaugusch.at/kernel.shtml>. | ||
| 288 | If there is no table found, it will fall-back to the custom DSDT | ||
| 289 | in-kernel (if activated) or to the DSDT from the BIOS. | ||
| 290 | |||
| 291 | Even if you do not need a new one at the moment, you may want to use a | ||
| 292 | better DSDT later. It is safe to say Y here. | ||
| 293 | |||
| 277 | config ACPI_BLACKLIST_YEAR | 294 | config ACPI_BLACKLIST_YEAR |
| 278 | int "Disable ACPI for systems before Jan 1st this year" if X86_32 | 295 | int "Disable ACPI for systems before Jan 1st this year" if X86_32 |
| 279 | default 0 | 296 | default 0 |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e53fb516f9d4..131936e7ff17 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
| @@ -312,6 +312,66 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, | |||
| 312 | return AE_OK; | 312 | return AE_OK; |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
| 316 | struct acpi_table_header *acpi_find_dsdt_initrd(void) | ||
| 317 | { | ||
| 318 | struct file *firmware_file; | ||
| 319 | mm_segment_t oldfs; | ||
| 320 | unsigned long len, len2; | ||
| 321 | struct acpi_table_header *dsdt_buffer, *ret = NULL; | ||
| 322 | struct kstat stat; | ||
| 323 | char *ramfs_dsdt_name = "/DSDT.aml"; | ||
| 324 | |||
| 325 | printk(KERN_INFO PREFIX "Looking for DSDT in initramfs... "); | ||
| 326 | |||
| 327 | /* | ||
| 328 | * Never do this at home, only the user-space is allowed to open a file. | ||
| 329 | * The clean way would be to use the firmware loader. But this code must be run | ||
| 330 | * before there is any userspace available. So we need a static/init firmware | ||
| 331 | * infrastructure, which doesn't exist yet... | ||
| 332 | */ | ||
| 333 | if (vfs_stat(ramfs_dsdt_name, &stat) < 0) { | ||
| 334 | printk("not found.\n"); | ||
| 335 | return ret; | ||
| 336 | } | ||
| 337 | |||
| 338 | len = stat.size; | ||
| 339 | /* check especially against empty files */ | ||
| 340 | if (len <= 4) { | ||
| 341 | printk("error, file is too small: only %lu bytes.\n", len); | ||
| 342 | return ret; | ||
| 343 | } | ||
| 344 | |||
| 345 | firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0); | ||
| 346 | if (IS_ERR(firmware_file)) { | ||
| 347 | printk("error, could not open file %s.\n", ramfs_dsdt_name); | ||
| 348 | return ret; | ||
| 349 | } | ||
| 350 | |||
| 351 | dsdt_buffer = ACPI_ALLOCATE(len); | ||
| 352 | if (!dsdt_buffer) { | ||
| 353 | printk("error when allocating %lu bytes of memory.\n", len); | ||
| 354 | goto err; | ||
| 355 | } | ||
| 356 | |||
| 357 | oldfs = get_fs(); | ||
| 358 | set_fs(KERNEL_DS); | ||
| 359 | len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len, &firmware_file->f_pos); | ||
| 360 | set_fs(oldfs); | ||
| 361 | if (len2 < len) { | ||
| 362 | printk("error trying to read %lu bytes from %s.\n", len, ramfs_dsdt_name); | ||
| 363 | ACPI_FREE(dsdt_buffer); | ||
| 364 | goto err; | ||
| 365 | } | ||
| 366 | |||
| 367 | printk("successfully read %lu bytes from %s.\n", len, ramfs_dsdt_name); | ||
| 368 | ret = dsdt_buffer; | ||
| 369 | err: | ||
| 370 | filp_close(firmware_file, NULL); | ||
| 371 | return ret; | ||
| 372 | } | ||
| 373 | #endif | ||
| 374 | |||
| 315 | acpi_status | 375 | acpi_status |
| 316 | acpi_os_table_override(struct acpi_table_header * existing_table, | 376 | acpi_os_table_override(struct acpi_table_header * existing_table, |
| 317 | struct acpi_table_header ** new_table) | 377 | struct acpi_table_header ** new_table) |
| @@ -319,13 +379,18 @@ acpi_os_table_override(struct acpi_table_header * existing_table, | |||
| 319 | if (!existing_table || !new_table) | 379 | if (!existing_table || !new_table) |
| 320 | return AE_BAD_PARAMETER; | 380 | return AE_BAD_PARAMETER; |
| 321 | 381 | ||
| 382 | *new_table = NULL; | ||
| 383 | |||
| 322 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 384 | #ifdef CONFIG_ACPI_CUSTOM_DSDT |
| 323 | if (strncmp(existing_table->signature, "DSDT", 4) == 0) | 385 | if (strncmp(existing_table->signature, "DSDT", 4) == 0) |
| 324 | *new_table = (struct acpi_table_header *)AmlCode; | 386 | *new_table = (struct acpi_table_header *)AmlCode; |
| 325 | else | 387 | #endif |
| 326 | *new_table = NULL; | 388 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD |
| 327 | #else | 389 | if (strncmp(existing_table->signature, "DSDT", 4) == 0) { |
| 328 | *new_table = NULL; | 390 | struct acpi_table_header *initrd_table = acpi_find_dsdt_initrd(); |
| 391 | if (initrd_table) | ||
| 392 | *new_table = initrd_table; | ||
| 393 | } | ||
| 329 | #endif | 394 | #endif |
| 330 | return AE_OK; | 395 | return AE_OK; |
| 331 | } | 396 | } |
diff --git a/init/initramfs.c b/init/initramfs.c index d53fee8d8604..c0b1e0533d80 100644 --- a/init/initramfs.c +++ b/init/initramfs.c | |||
| @@ -538,7 +538,7 @@ skip: | |||
| 538 | initrd_end = 0; | 538 | initrd_end = 0; |
| 539 | } | 539 | } |
| 540 | 540 | ||
| 541 | static int __init populate_rootfs(void) | 541 | int __init populate_rootfs(void) |
| 542 | { | 542 | { |
| 543 | char *err = unpack_to_rootfs(__initramfs_start, | 543 | char *err = unpack_to_rootfs(__initramfs_start, |
| 544 | __initramfs_end - __initramfs_start, 0); | 544 | __initramfs_end - __initramfs_start, 0); |
| @@ -577,4 +577,10 @@ static int __init populate_rootfs(void) | |||
| 577 | } | 577 | } |
| 578 | return 0; | 578 | return 0; |
| 579 | } | 579 | } |
| 580 | #ifndef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
| 581 | /* | ||
| 582 | * if this option is enabled, populate_rootfs() is called _earlier_ in the | ||
| 583 | * boot sequence. This insures that the ACPI initialisation can find the file. | ||
| 584 | */ | ||
| 580 | rootfs_initcall(populate_rootfs); | 585 | rootfs_initcall(populate_rootfs); |
| 586 | #endif | ||
diff --git a/init/main.c b/init/main.c index c691f5f7fc27..2a78932f6c07 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -102,6 +102,12 @@ static inline void mark_rodata_ro(void) { } | |||
| 102 | extern void tc_init(void); | 102 | extern void tc_init(void); |
| 103 | #endif | 103 | #endif |
| 104 | 104 | ||
| 105 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
| 106 | extern int populate_rootfs(void); | ||
| 107 | #else | ||
| 108 | static inline void populate_rootfs(void) {} | ||
| 109 | #endif | ||
| 110 | |||
| 105 | enum system_states system_state; | 111 | enum system_states system_state; |
| 106 | EXPORT_SYMBOL(system_state); | 112 | EXPORT_SYMBOL(system_state); |
| 107 | 113 | ||
| @@ -648,6 +654,7 @@ asmlinkage void __init start_kernel(void) | |||
| 648 | 654 | ||
| 649 | check_bugs(); | 655 | check_bugs(); |
| 650 | 656 | ||
| 657 | populate_rootfs(); /* For DSDT override from initramfs */ | ||
| 651 | acpi_early_init(); /* before LAPIC and SMP init */ | 658 | acpi_early_init(); /* before LAPIC and SMP init */ |
| 652 | 659 | ||
| 653 | /* Do the rest non-__init'ed, we're now alive */ | 660 | /* Do the rest non-__init'ed, we're now alive */ |
