[RFC] Include ACPI DSDT from INITRD patch into mainline

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I'd be willing to bet that most distros have this patch in their kernel.
One of those things we can't really live without.

What I haven't understood is why it isn't included in the mainline
kernel yet. There's enough kernel hackers out there using this that I
doubt it will get stale or broken for very long.

I'm willing to do the grunt work to get it suitable.

Patch attached for convenience.

diff -urpN -X linux-2.6.18/Documentation/dontdiff linux-2.6.18.bak/Documentation/dsdt-initrd.txt linux-2.6.18/Documentation/dsdt-initrd.txt
--- linux-2.6.18.bak/Documentation/dsdt-initrd.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18/Documentation/dsdt-initrd.txt	2006-08-12 11:15:13.000000000 +0200
@@ -0,0 +1,98 @@
+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 - 2006 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 Device Drivers|Block Devices) and enable ACPI_CUSTOM_DSDT_INITRD at the ACPI
+options (General Setup|ACPI Support|Read custom DSDT from initrd).
+
+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 . 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 .
+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.
+
+Once your new DSDT is ready you'll have to add it to an initrd 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 initrd has to be an
+initramfs. The file is contained into the initramfs under the name /DSDT.aml .
+To obtain such an initrd, you might have to modify your mkinitrd script or you
+can add it later to the initrd with the script appended to this document. The
+command will look like:
+initrd-add-dsdt initrd.img my-dsdt.aml
+
+In case you don't use any initrd, 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..." will tell you if the DSDT was
+found or not. If you need to update your DSDT, generate a new initrd and
+perform the steps above. Don't forget that with Lilo, you'll have to re-run it.
+
+
+======================= Here starts initrd-add-dsdt ===============================
+#!/bin/bash
+# Adds a DSDT file to the initrd (if it's an initramfs)
+# first argument is the name of archive
+# second argurment 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
+
+# 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 -urpN -X linux-2.6.18/Documentation/dontdiff linux-2.6.18.bak/drivers/acpi/Kconfig linux-2.6.18/drivers/acpi/Kconfig
--- linux-2.6.18.bak/drivers/acpi/Kconfig	2006-08-12 11:14:05.000000000 +0200
+++ linux-2.6.18/drivers/acpi/Kconfig	2006-08-12 11:15:13.000000000 +0200
@@ -264,6 +264,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 y
+	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.  For now you need to use a special mkinitrd tool.
+	  For more details see <file:Documentation/dsdt-initrd.txt> or 
+	  <http://gaugusch.at/kernel.shtml>. If there is no table found, it 
+	  will fallback 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 implemented DSDT later. It is safe to say Y here.
+
 config ACPI_BLACKLIST_YEAR
 	int "Disable ACPI for systems before Jan 1st this year" if X86_32
 	default 0
diff -urpN -X linux-2.6.18/Documentation/dontdiff linux-2.6.18.bak/drivers/acpi/osl.c linux-2.6.18/drivers/acpi/osl.c
--- linux-2.6.18.bak/drivers/acpi/osl.c	2006-08-12 11:14:05.000000000 +0200
+++ linux-2.6.18/drivers/acpi/osl.c	2006-08-12 11:16:08.000000000 +0200
@@ -69,6 +69,10 @@ extern char line_buf[80];
 int acpi_specific_hotkey_enabled = TRUE;
 EXPORT_SYMBOL(acpi_specific_hotkey_enabled);
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+int acpi_must_unregister_table = FALSE;
+#endif
+
 static unsigned int acpi_irq_irq;
 static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
@@ -219,6 +223,67 @@ acpi_os_predefined_override(const struct
 	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;
+	/* maybe this could be an argument on the cmd line, but let's keep it simple for now */
+	char *ramfs_dsdt_name = "/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("error, file %s not found.\n", ramfs_dsdt_name);
+		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)
@@ -226,13 +291,20 @@ acpi_os_table_override(struct acpi_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;
+			acpi_must_unregister_table = TRUE;
+		}
+	}
 #endif
 	return AE_OK;
 }
diff -urpN -X linux-2.6.18/Documentation/dontdiff linux-2.6.18.bak/drivers/acpi/tables/tbget.c linux-2.6.18/drivers/acpi/tables/tbget.c
--- linux-2.6.18.bak/drivers/acpi/tables/tbget.c	2006-08-12 11:14:05.000000000 +0200
+++ linux-2.6.18/drivers/acpi/tables/tbget.c	2006-08-12 11:15:27.000000000 +0200
@@ -278,6 +278,14 @@ acpi_tb_table_override(struct acpi_table
 	address.pointer.logical = new_table;
 
 	status = acpi_tb_get_this_table(&address, new_table, table_info);
+
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+	if (acpi_must_unregister_table) {
+		ACPI_FREE(new_table);
+		acpi_must_unregister_table = FALSE;
+	}
+#endif
+
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Could not copy ACPI table"));
 		return_ACPI_STATUS(status);
diff -urpN -X linux-2.6.18/Documentation/dontdiff linux-2.6.18.bak/include/acpi/acpiosxf.h linux-2.6.18/include/acpi/acpiosxf.h
--- linux-2.6.18.bak/include/acpi/acpiosxf.h	2006-08-12 11:14:05.000000000 +0200
+++ linux-2.6.18/include/acpi/acpiosxf.h	2006-08-12 11:15:13.000000000 +0200
@@ -95,6 +95,10 @@ acpi_status
 acpi_os_table_override(struct acpi_table_header *existing_table,
 		       struct acpi_table_header **new_table);
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+extern int acpi_must_unregister_table;
+#endif
+
 /*
  * Spinlock primitives
  */
diff -urpN -X linux-2.6.18/Documentation/dontdiff linux-2.6.18.bak/init/main.c linux-2.6.18/init/main.c
--- linux-2.6.18.bak/init/main.c	2006-08-12 11:14:05.000000000 +0200
+++ linux-2.6.18/init/main.c	2006-08-12 11:15:13.000000000 +0200
@@ -581,8 +581,6 @@ asmlinkage void __init start_kernel(void
 
 	check_bugs();
 
-	acpi_early_init(); /* before LAPIC and SMP init */
-
 	/* Do the rest non-__init'ed, we're now alive */
 	rest_init();
 }
@@ -699,6 +697,14 @@ static int init(void * unused)
 	 */
 	child_reaper = current;
 
+ 	/*
+ 	 * Do this before initcalls, because some drivers want to access
+ 	 * firmware files.
+ 	 */
+ 	populate_rootfs();
+ 
+ 	acpi_early_init(); /* before LAPIC and SMP init */
+
 	smp_prepare_cpus(max_cpus);
 
 	do_pre_smp_initcalls();
@@ -708,12 +714,6 @@ static int init(void * unused)
 
 	cpuset_init_smp();
 
-	/*
-	 * Do this before initcalls, because some drivers want to access
-	 * firmware files.
-	 */
-	populate_rootfs();
-
 	do_basic_setup();
 
 	/*

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux