Hi Eric, nice. Some minor comments below... On Sun, 2008-02-03 at 18:28 +0100, Éric Piel wrote: > The basics of DSDT from initramfs. In case this option is selected, > populate_rootfs() is called a bit earlier to have the initramfs content > available during ACPI initialisation. > > This is a very similar path to the one available at > http://gaugusch.at/kernel.shtml but with some update in the > documentation, default set to No and the change of populate_rootfs() the > "Jeff Mahony way" (which avoids reading the initramfs twice). > > Signed-off-by: Eric Piel <eric.piel@xxxxxxxxxxxxxxxx> > > --- > Documentation/dsdt-initrd.txt | 100 +++++++++++++++++++++++++++++++++++++++++ > drivers/acpi/Kconfig | 17 +++++++ > drivers/acpi/osl.c | 73 ++++++++++++++++++++++++++++-- > init/initramfs.c | 8 +++- > init/main.c | 7 +++ > 5 files changed, 200 insertions(+), 5 deletions(-) > create mode 100644 Documentation/dsdt-initrd.txt > > diff --git a/Documentation/dsdt-initrd.txt b/Documentation/dsdt-initrd.txt > new file mode 100644 > index 0000000..b2e9460 > --- /dev/null > +++ b/Documentation/dsdt-initrd.txt > @@ -0,0 +1,100 @@ > +ACPI Custom DSDT read from initramfs > + > +2003 by Markuss Gaugusch < dsdt at gaugusch dot org > > +Special thanks go to Thomas Renninger from SuSE, who updated the patch for > +2.6.0 and later modified it to read inside initramfs > +2004 - 2008 maintained by Eric Piel < eric dot piel at tremplin-utc dot net > > + > +This option is intended for people who would like to hack their DSDT and don't > +want to recompile their kernel after every change. It can also be useful to > +distros which offers pre-compiled kernels and want to allow their users to use > +a modified DSDT. In the Kernel config, enable the initial RAM filesystem > +support (in General Setup) and enable ACPI_CUSTOM_DSDT_INITRD at the ACPI > +options (General Setup|ACPI Support|Read Custom DSDT from initramfs). > + > +A custom DSDT (Differentiated System Description Table) is useful when your > +computer uses ACPI but problems occur due to broken implementation. Typically, > +your computer works but there are some troubles with the hardware detection or > +the power management. You can check that troubles come from errors in the DSDT by > +activating the ACPI debug option and reading the logs. This table is provided > +by the BIOS, therefore it might be a good idea to check for BIOS update on your > +vendor website before going any further. Errors are often caused by vendors > +testing their hardware only with Windows or because there is code which is > +executed only on a specific OS with a specific version and Linux hasn't been > +considered during the development. > + > +Before you run away from customising your DSDT, you should note that already > +corrected tables are available for a fair amount of computers on this web-page: > +http://acpi.sf.net/dsdt . Be careful though, to work correctly a DSDT has to > +match closely the hardware, including the amount of RAM, the frequency of the > +processor and the PCI cards present! If you are part of the unluckies who > +cannot find their hardware in this database, you can modify your DSDT by > +yourself. This process is less painful than it sounds. Download the Intel ASL > +compiler/decompiler at http://www.intel.com/technology/IAPC/acpi/downloads.htm . AFAIK Intel wants to move away from this address. There should have been an opensource project for the ACPICA code started, we should reference this one instead. Len? > +As root, you then have to dump your DSDT and decompile it. By using the > +compiler messages as well as the kernel ACPI debug messages and the reference > +book (available at the Intel website and also at http://www.acpi.info), it is > +quite easy to obtain a fully working table. Hmm, IMO this sentence should not go in, but instead a reference to: Something like: You can learn how to extract your BIOS ACPI tables, disassemble, modify and recompile them here: http://www.lesswatts.org/projects/acpi/overridingDSDT.php (which then still needs to be updated). > +Once your new DSDT is ready you'll have to add it to an initramfs so that the > +kernel can read the table at the very beginning of the boot. As the file has to > +be accessed very early during the boot process the initramfs has to be an > +initramfs. The file is contained into the initramfs under the name /DSDT.aml . So this patch is still using /DSDT.aml... > +To obtain such an initramfs, you might have to modify your initramfs script or > +you can add it later to the initramfs with the script appended to this > +document. The command will look like: > +initramfs-add-dsdt initramfs.img my-dsdt.aml > + > +In case you don't use any initramfs, the possibilities you have are to either > +start using one (try mkinitrd or yaird), or use the "Include Custom DSDT" > +configure option to directly include your DSDT inside the kernel. > + > +The message "Looking for DSDT in initramfs..." Removing this was point 4. of Len's wish list. IMO it can stay, but I don't really care. > will tell you if the DSDT was > +found or not. If you need to update your DSDT, generate a new initramfs and > +perform the steps above. Don't forget that with Lilo, you'll have to re-run it. > + > + > +====================== Here starts initramfs-add-dsdt ========================== > +#!/bin/bash > +# Adds a DSDT file to the initrd (if it's an initramfs) > +# first argument is the name of archive > +# second argument is the name of the file to add > +# The file will be copied as /DSDT.aml > + > +# 20060126: fix "Premature end of file" with some old cpio (Roland Robic) > +# 20060205: this time it should really work > + > +# check the arguments > +if [ $# -ne 2 ]; then > + program_name=$(basename $0) > + echo "\ > +$program_name: too few arguments > +Usage: $program_name initrd-name.img DSDT-to-add.aml > +Adds a DSDT file to an initrd (in initramfs format) > + > + initrd-name.img: filename of the initrd in initramfs format > + DSDT-to-add.aml: filename of the DSDT file to add > + " 1>&2 > + exit 1 > +fi > + > +# we should check it's an initramfs > + > +tempcpio=$(mktemp -d) > +# cleanup on exit, hangup, interrupt, quit, termination > +trap 'rm -rf $tempcpio' 0 1 2 3 15 > + > +# extract the archive > +gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1 > + > +# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml" > +cp -f "$2" "$tempcpio"/DSDT.aml DSDT.aml... > + > +# add the file > +cd "$tempcpio" > +(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1 > +cd "$OLDPWD" > + > +# re-compress the archive > +gzip -c "$tempcpio"/initramfs.cpio > "$1" > + > diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig > index ccf6ea9..8607ed3 100644 > --- a/drivers/acpi/Kconfig > +++ b/drivers/acpi/Kconfig > @@ -274,6 +274,23 @@ config ACPI_CUSTOM_DSDT_FILE > Enter the full path name to the file which includes the AmlCode > declaration. > > +config ACPI_CUSTOM_DSDT_INITRD > + bool "Read Custom DSDT from initramfs" > + depends on BLK_DEV_INITRD > + default n > + help > + The DSDT (Differentiated System Description Table) often needs to be > + overridden because of broken BIOS implementations. If this feature is > + activated you will be able to provide a customized DSDT by adding it > + to your initramfs. If your mkinitrd tool does not support this feature > + a script is provided in the documentation. For more details see > + <file:Documentation/dsdt-initrd.txt> or <http://gaugusch.at/kernel.shtml>. > + If there is no table found, it will fall-back to the custom DSDT > + in-kernel (if activated) or to the DSDT from the BIOS. > + > + Even if you do not need a new one at the moment, you may want to use a > + better DSDT later. It is safe to say Y here. This one should be rephrased. Don't invite all users to modify or use foreign DSDTs just for little improvements. I think the main goal of this patch should be debugging/testing purposes. Better phrase it like: If you have problems with ACPI on your machine and you have fixed it up by modifying the DSDT, don't override the DSDT as a long term solution. E.g. if you add new memory to your machine, it will invalidate the modified DSDT (BIOS would generate a slightly adjusted one). Always report bugs in a DSDT to bugzilla.kernel.org and assign it to the ACPI component. Overriding of the DSDT is mainly thought for developing/testing purposes! > + > config ACPI_BLACKLIST_YEAR > int "Disable ACPI for systems before Jan 1st this year" if X86_32 > default 0 > diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c > index e53fb51..4568a59 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, > return AE_OK; > } > > +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD > +struct acpi_table_header *acpi_find_dsdt_initrd(void) > +{ > + struct file *firmware_file; > + mm_segment_t oldfs; > + unsigned long len, len2; > + struct acpi_table_header *dsdt_buffer, *ret = NULL; > + struct kstat stat; > + char *ramfs_dsdt_name = "/DSDT.aml"; DSDT.aml > + > + printk(KERN_INFO PREFIX "Looking for DSDT in initramfs... "); > + > + /* > + * Never do this at home, only the user-space is allowed to open a file. > + * The clean way would be to use the firmware loader. But this code must be run > + * before there is any userspace available. So we need a static/init firmware > + * infrastructure, which doesn't exist yet... > + */ > + if (vfs_stat(ramfs_dsdt_name, &stat) < 0) { > + printk("not found.\n"); > + return ret; > + } > + > + len = stat.size; > + /* check especially against empty files */ > + if (len <= 4) { > + printk("error, file is too small: only %lu bytes.\n", len); > + return ret; > + } > + > + firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0); > + if (IS_ERR(firmware_file)) { > + printk("error, could not open file %s.\n", ramfs_dsdt_name); > + return ret; > + } > + > + dsdt_buffer = ACPI_ALLOCATE(len); > + if (!dsdt_buffer) { > + printk("error when allocating %lu bytes of memory.\n", len); > + goto err; > + } > + > + oldfs = get_fs(); > + set_fs(KERNEL_DS); > + len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len, &firmware_file->f_pos); > + set_fs(oldfs); > + if (len2 < len) { > + printk("error trying to read %lu bytes from %s.\n", len, ramfs_dsdt_name); > + ACPI_FREE(dsdt_buffer); > + goto err; > + } > + > + printk("successfully read %lu bytes from %s.\n", len, ramfs_dsdt_name); > + ret = dsdt_buffer; > +err: > + filp_close(firmware_file, NULL); > + return ret; > +} > +#endif > + > acpi_status > acpi_os_table_override(struct acpi_table_header * existing_table, > struct acpi_table_header ** new_table) > @@ -319,13 +379,18 @@ acpi_os_table_override(struct acpi_table_header * existing_table, > if (!existing_table || !new_table) > return AE_BAD_PARAMETER; > > + *new_table = NULL; > + > #ifdef CONFIG_ACPI_CUSTOM_DSDT > if (strncmp(existing_table->signature, "DSDT", 4) == 0) > *new_table = (struct acpi_table_header *)AmlCode; > - else > - *new_table = NULL; > -#else > - *new_table = NULL; > +#endif > +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD > + if (strncmp(existing_table->signature, "DSDT", 4) == 0) { > + struct acpi_table_header *initrd_table = acpi_find_dsdt_initrd(); > + if (initrd_table) > + *new_table = initrd_table; > + } > #endif > return AE_OK; > } > diff --git a/init/initramfs.c b/init/initramfs.c > index 1db02a0..f2662e2 100644 > --- a/init/initramfs.c > +++ b/init/initramfs.c > @@ -541,7 +541,7 @@ skip: > > #endif > > -static int __init populate_rootfs(void) > +int __init populate_rootfs(void) > { > char *err = unpack_to_rootfs(__initramfs_start, > __initramfs_end - __initramfs_start, 0); > @@ -582,4 +582,10 @@ static int __init populate_rootfs(void) > #endif > return 0; > } > +#ifndef CONFIG_ACPI_CUSTOM_DSDT_INITRD > +/* > + * if this option is enabled, populate_rootfs() is called _earlier_ in the > + * boot sequence. This insures that the ACPI initialisation can find the file. > + */ > rootfs_initcall(populate_rootfs); > +#endif > diff --git a/init/main.c b/init/main.c > index f287ca5..7eb1b89 100644 > --- a/init/main.c > +++ b/init/main.c > @@ -102,6 +102,12 @@ static inline void mark_rodata_ro(void) { } > extern void tc_init(void); > #endif > > +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD > +extern int populate_rootfs(void); > +#else > +static inline void populate_rootfs(void) {} > +#endif > + > enum system_states system_state; > EXPORT_SYMBOL(system_state); > > @@ -643,6 +649,7 @@ asmlinkage void __init start_kernel(void) > > check_bugs(); > > + populate_rootfs(); /* For DSDT override from initramfs */ > acpi_early_init(); /* before LAPIC and SMP init */ > > /* Do the rest non-__init'ed, we're now alive */ IMO it should go in as it is for now. It could still be extended on the next rcX cycle. All comments are only minor enhancements. About the /DSDT.aml vs. /dsdt/DSDT.aml location: As said this is for SSDT overrides. If someone sees (beside the table signature, I think I can handle/workaround this), why this has no use or not worth to look at it, pls let me know. Otherwise I will have a look at it (but possibly not that soon...) I expect it need to be checked then whether /dsdt exists at all, is a directory and find all files in it. The advantage to at least change the name now to dsdt/DSDT.aml, would be to have a consistent naming. If DSDT.aml changes to dsdt/DSDT.aml at some later time we need to adjust userspace tools and will get userspace vs kernel version problems. I test-compiled the patches on various archs and configs, but didn't do any real DSDT override tests (the patches are in use for quite some time...). All builds succeeded. Thomas - To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html