ACPI: static acpi_no_initrd_override_setup()
[cascardo/linux.git] / drivers / acpi / osl.c
index 101691e..346f049 100644 (file)
@@ -44,6 +44,8 @@
 #include <asm/uaccess.h>
 
 #include <linux/efi.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
 
 #define _COMPONENT             ACPI_OS_SERVICES
 ACPI_MODULE_NAME("osl");
@@ -74,15 +76,75 @@ static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
 static struct workqueue_struct *kacpi_notify_wq;
 
+struct acpi_res_list {
+       resource_size_t start;
+       resource_size_t end;
+       acpi_adr_space_type resource_type; /* IO port, System memory, ...*/
+       char name[5];   /* only can have a length of 4 chars, make use of this
+                          one instead of res->name, no need to kalloc then */
+       struct list_head resource_list;
+};
+
+static LIST_HEAD(resource_list_head);
+static DEFINE_SPINLOCK(acpi_res_lock);
+
 #define        OSI_STRING_LENGTH_MAX 64        /* arbitrary */
 static char osi_additional_string[OSI_STRING_LENGTH_MAX];
 
-static int osi_linux;          /* disable _OSI(Linux) by default */
-
-#ifdef CONFIG_DMI
-static struct __initdata dmi_system_id acpi_osl_dmi_table[];
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+static int acpi_no_initrd_override;
 #endif
 
+/*
+ * "Ode to _OSI(Linux)"
+ *
+ * osi_linux -- Control response to BIOS _OSI(Linux) query.
+ *
+ * As Linux evolves, the features that it supports change.
+ * So an OSI string such as "Linux" is not specific enough
+ * to be useful across multiple versions of Linux.  It
+ * doesn't identify any particular feature, interface,
+ * or even any particular version of Linux...
+ *
+ * Unfortunately, Linux-2.6.22 and earlier responded "yes"
+ * to a BIOS _OSI(Linux) query.  When
+ * a reference mobile BIOS started using it, its use
+ * started to spread to many vendor platforms.
+ * As it is not supportable, we need to halt that spread.
+ *
+ * Today, most BIOS references to _OSI(Linux) are noise --
+ * they have no functional effect and are just dead code
+ * carried over from the reference BIOS.
+ *
+ * The next most common case is that _OSI(Linux) harms Linux,
+ * usually by causing the BIOS to follow paths that are
+ * not tested during Windows validation.
+ *
+ * Finally, there is a short list of platforms
+ * where OSI(Linux) benefits Linux.
+ *
+ * In Linux-2.6.23, OSI(Linux) is first disabled by default.
+ * DMI is used to disable the dmesg warning about OSI(Linux)
+ * on platforms where it is known to have no effect.
+ * But a dmesg warning remains for systems where
+ * we do not know if OSI(Linux) is good or bad for the system.
+ * DMI is also used to enable OSI(Linux) for the machines
+ * that are known to need it.
+ *
+ * BIOS writers should NOT query _OSI(Linux) on future systems.
+ * It will be ignored by default, and to get Linux to
+ * not ignore it will require a kernel source update to
+ * add a DMI entry, or a boot-time "acpi_osi=Linux" invocation.
+ */
+#define OSI_LINUX_ENABLE 0
+
+static struct osi_linux {
+       unsigned int    enable:1;
+       unsigned int    dmi:1;
+       unsigned int    cmdline:1;
+       unsigned int    known:1;
+} osi_linux = { OSI_LINUX_ENABLE, 0, 0, 0};
+
 static void __init acpi_request_region (struct acpi_generic_address *addr,
        unsigned int length, char *desc)
 {
@@ -133,21 +195,11 @@ device_initcall(acpi_reserve_resources);
 
 acpi_status __init acpi_os_initialize(void)
 {
-       dmi_check_system(acpi_osl_dmi_table);
        return AE_OK;
 }
 
 acpi_status acpi_os_initialize1(void)
 {
-       /*
-        * Initialize PCI configuration space access, as we'll need to access
-        * it while walking the namespace (bus 0 and root bridges w/ _BBNs).
-        */
-       if (!raw_pci_ops) {
-               printk(KERN_ERR PREFIX
-                      "Access to PCI configuration space unavailable\n");
-               return AE_NULL_ENTRY;
-       }
        kacpid_wq = create_singlethread_workqueue("kacpid");
        kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
        BUG_ON(!kacpid_wq);
@@ -176,8 +228,6 @@ void acpi_os_printf(const char *fmt, ...)
        va_end(args);
 }
 
-EXPORT_SYMBOL(acpi_os_printf);
-
 void acpi_os_vprintf(const char *fmt, va_list args)
 {
        static char buffer[512];
@@ -215,7 +265,8 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
        }
 }
 
-void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
+void __iomem *__init_refok
+acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
        if (phys > ULONG_MAX) {
                printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -273,6 +324,67 @@ 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";
+
+       printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT\n");
+
+       /*
+        * 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.
+        * A static/init firmware infrastructure doesn't exist yet...
+        */
+       if (vfs_stat(ramfs_dsdt_name, &stat) < 0)
+               return ret;
+
+       len = stat.size;
+       /* check especially against empty files */
+       if (len <= 4) {
+               printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len);
+               return ret;
+       }
+
+       firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
+       if (IS_ERR(firmware_file)) {
+               printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name);
+               return ret;
+       }
+
+       dsdt_buffer = kmalloc(len, GFP_ATOMIC);
+       if (!dsdt_buffer) {
+               printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\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(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n",
+                       len, ramfs_dsdt_name);
+               ACPI_FREE(dsdt_buffer);
+               goto err;
+       }
+
+       printk(KERN_INFO PREFIX "Found %lu byte DSDT in %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)
@@ -280,20 +392,52 @@ 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) &&
+           !acpi_no_initrd_override) {
+               struct acpi_table_header *initrd_table;
+
+               initrd_table = acpi_find_dsdt_initrd();
+               if (initrd_table)
+                       *new_table = initrd_table;
+       }
+#endif
+       if (*new_table != NULL) {
+               printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], "
+                          "this is unsafe: tainting kernel\n",
+                      existing_table->signature,
+                      existing_table->oem_table_id);
+               add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
+       }
        return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+static int __init acpi_no_initrd_override_setup(char *s)
+{
+       acpi_no_initrd_override = 1;
+       return 1;
+}
+__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup);
+#endif
+
 static irqreturn_t acpi_irq(int irq, void *dev_id)
 {
-       return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
+       u32 handled;
+
+       handled = (*acpi_irq_handler) (acpi_irq_context);
+
+       if (handled) {
+               acpi_irq_handled++;
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
 }
 
 acpi_status
@@ -302,6 +446,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
 {
        unsigned int irq;
 
+       acpi_irq_stats_init();
+
        /*
         * Ignore the GSI from the core, and use the value in our copy of the
         * FADT. It may not be the same if an interrupt source override exists
@@ -345,8 +491,6 @@ void acpi_os_sleep(acpi_integer ms)
        schedule_timeout_interruptible(msecs_to_jiffies(ms));
 }
 
-EXPORT_SYMBOL(acpi_os_sleep);
-
 void acpi_os_stall(u32 us)
 {
        while (us) {
@@ -360,8 +504,6 @@ void acpi_os_stall(u32 us)
        }
 }
 
-EXPORT_SYMBOL(acpi_os_stall);
-
 /*
  * Support ACPI 3.0 AML Timer operand
  * Returns 64-bit free-running, monotonically increasing timer
@@ -391,17 +533,14 @@ acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
        if (!value)
                value = &dummy;
 
-       switch (width) {
-       case 8:
+       *value = 0;
+       if (width <= 8) {
                *(u8 *) value = inb(port);
-               break;
-       case 16:
+       } else if (width <= 16) {
                *(u16 *) value = inw(port);
-               break;
-       case 32:
+       } else if (width <= 32) {
                *(u32 *) value = inl(port);
-               break;
-       default:
+       } else {
                BUG();
        }
 
@@ -412,17 +551,13 @@ EXPORT_SYMBOL(acpi_os_read_port);
 
 acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
 {
-       switch (width) {
-       case 8:
+       if (width <= 8) {
                outb(value, port);
-               break;
-       case 16:
+       } else if (width <= 16) {
                outw(value, port);
-               break;
-       case 32:
+       } else if (width <= 32) {
                outl(value, port);
-               break;
-       default:
+       } else {
                BUG();
        }
 
@@ -488,7 +623,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
 
 acpi_status
 acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
-                              void *value, u32 width)
+                              u32 *value, u32 width)
 {
        int result, size;
 
@@ -509,17 +644,13 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
                return AE_ERROR;
        }
 
-       BUG_ON(!raw_pci_ops);
-
-       result = raw_pci_ops->read(pci_id->segment, pci_id->bus,
-                                  PCI_DEVFN(pci_id->device, pci_id->function),
-                                  reg, size, value);
+       result = raw_pci_read(pci_id->segment, pci_id->bus,
+                               PCI_DEVFN(pci_id->device, pci_id->function),
+                               reg, size, value);
 
        return (result ? AE_ERROR : AE_OK);
 }
 
-EXPORT_SYMBOL(acpi_os_read_pci_configuration);
-
 acpi_status
 acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
                                acpi_integer value, u32 width)
@@ -540,11 +671,9 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
                return AE_ERROR;
        }
 
-       BUG_ON(!raw_pci_ops);
-
-       result = raw_pci_ops->write(pci_id->segment, pci_id->bus,
-                                   PCI_DEVFN(pci_id->device, pci_id->function),
-                                   reg, size, value);
+       result = raw_pci_write(pci_id->segment, pci_id->bus,
+                               PCI_DEVFN(pci_id->device, pci_id->function),
+                               reg, size, value);
 
        return (result ? AE_ERROR : AE_OK);
 }
@@ -560,7 +689,6 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle,    /* upper bound  */
        acpi_status status;
        unsigned long temp;
        acpi_object_type type;
-       u8 tu8;
 
        acpi_get_parent(chandle, &handle);
        if (handle != rhandle) {
@@ -575,6 +703,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle,    /* upper bound  */
                    acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
                                          &temp);
                if (ACPI_SUCCESS(status)) {
+                       u32 val;
                        pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
                        pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
 
@@ -583,24 +712,24 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle,  /* upper bound  */
 
                        /* any nicer way to get bus number of bridge ? */
                        status =
-                           acpi_os_read_pci_configuration(pci_id, 0x0e, &tu8,
+                           acpi_os_read_pci_configuration(pci_id, 0x0e, &val,
                                                           8);
                        if (ACPI_SUCCESS(status)
-                           && ((tu8 & 0x7f) == 1 || (tu8 & 0x7f) == 2)) {
+                           && ((val & 0x7f) == 1 || (val & 0x7f) == 2)) {
                                status =
                                    acpi_os_read_pci_configuration(pci_id, 0x18,
-                                                                  &tu8, 8);
+                                                                  &val, 8);
                                if (!ACPI_SUCCESS(status)) {
                                        /* Certainly broken...  FIX ME */
                                        return;
                                }
                                *is_bridge = 1;
-                               pci_id->bus = tu8;
+                               pci_id->bus = val;
                                status =
                                    acpi_os_read_pci_configuration(pci_id, 0x19,
-                                                                  &tu8, 8);
+                                                                  &val, 8);
                                if (ACPI_SUCCESS(status)) {
-                                       *bus_number = tu8;
+                                       *bus_number = val;
                                }
                        } else
                                *is_bridge = 0;
@@ -629,25 +758,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)
        dpc->function(dpc->context);
        kfree(dpc);
 
-       /* Yield cpu to notify thread */
-       cond_resched();
-
-       return;
-}
-
-static void acpi_os_execute_notify(struct work_struct *work)
-{
-       struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
-
-       if (!dpc) {
-               printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
-               return;
-       }
-
-       dpc->function(dpc->context);
-
-       kfree(dpc);
-
        return;
 }
 
@@ -671,7 +781,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 {
        acpi_status status = AE_OK;
        struct acpi_os_dpc *dpc;
-
+       struct workqueue_struct *queue;
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                          "Scheduling function [%p(%p)] for deferred execution.\n",
                          function, context));
@@ -695,20 +805,13 @@ acpi_status acpi_os_execute(acpi_execute_type type,
        dpc->function = function;
        dpc->context = context;
 
-       if (type == OSL_NOTIFY_HANDLER) {
-               INIT_WORK(&dpc->work, acpi_os_execute_notify);
-               if (!queue_work(kacpi_notify_wq, &dpc->work)) {
-                       status = AE_ERROR;
-                       kfree(dpc);
-               }
-       } else {
-               INIT_WORK(&dpc->work, acpi_os_execute_deferred);
-               if (!queue_work(kacpid_wq, &dpc->work)) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "Call to queue_work() failed.\n"));
-                       status = AE_ERROR;
-                       kfree(dpc);
-               }
+       INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+       queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
+       if (!queue_work(queue, &dpc->work)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                         "Call to queue_work() failed.\n"));
+               status = AE_ERROR;
+               kfree(dpc);
        }
        return_ACPI_STATUS(status);
 }
@@ -761,8 +864,6 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
        return AE_OK;
 }
 
-EXPORT_SYMBOL(acpi_os_create_semaphore);
-
 /*
  * TODO: A better way to delete semaphores?  Linux doesn't have a
  * 'delete_semaphore()' function -- may result in an invalid
@@ -786,8 +887,6 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle)
        return AE_OK;
 }
 
-EXPORT_SYMBOL(acpi_os_delete_semaphore);
-
 /*
  * TODO: The kernel doesn't have a 'down_timeout' function -- had to
  * improvise.  The process is to sleep for one scheduler quantum
@@ -880,8 +979,6 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
        return status;
 }
 
-EXPORT_SYMBOL(acpi_os_wait_semaphore);
-
 /*
  * TODO: Support for units > 1?
  */
@@ -904,8 +1001,6 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
        return AE_OK;
 }
 
-EXPORT_SYMBOL(acpi_os_signal_semaphore);
-
 #ifdef ACPI_FUTURE_USAGE
 u32 acpi_os_get_line(char *buffer)
 {
@@ -949,8 +1044,6 @@ acpi_status acpi_os_signal(u32 function, void *info)
        return AE_OK;
 }
 
-EXPORT_SYMBOL(acpi_os_signal);
-
 static int __init acpi_os_name_setup(char *str)
 {
        char *p = acpi_os_name;
@@ -975,13 +1068,37 @@ static int __init acpi_os_name_setup(char *str)
 
 __setup("acpi_os_name=", acpi_os_name_setup);
 
-static void enable_osi_linux(int enable) {
+static void __init set_osi_linux(unsigned int enable)
+{
+       if (osi_linux.enable != enable) {
+               osi_linux.enable = enable;
+               printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
+                       enable ? "Add": "Delet");
+       }
+       return;
+}
 
-       if (osi_linux != enable)
-               printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n",
-                       enable ? "En": "Dis");
+static void __init acpi_cmdline_osi_linux(unsigned int enable)
+{
+       osi_linux.cmdline = 1;  /* cmdline set the default */
+       set_osi_linux(enable);
+
+       return;
+}
+
+void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
+{
+       osi_linux.dmi = 1;      /* DMI knows that this box asks OSI(Linux) */
+
+       printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
+
+       if (enable == -1)
+               return;
+
+       osi_linux.known = 1;    /* DMI knows which OSI(Linux) default needed */
+
+       set_osi_linux(enable);
 
-       osi_linux = enable;
        return;
 }
 
@@ -998,12 +1115,12 @@ static int __init acpi_osi_setup(char *str)
                printk(KERN_INFO PREFIX "_OSI method disabled\n");
                acpi_gbl_create_osi_method = FALSE;
        } else if (!strcmp("!Linux", str)) {
-               enable_osi_linux(0);
+               acpi_cmdline_osi_linux(0);      /* !enable */
        } else if (*str == '!') {
                if (acpi_osi_invalidate(++str) == AE_OK)
                        printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
        } else if (!strcmp("Linux", str)) {
-               enable_osi_linux(1);
+               acpi_cmdline_osi_linux(1);      /* enable */
        } else if (*osi_additional_string == '\0') {
                strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
                printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
@@ -1046,6 +1163,128 @@ static int __init acpi_wake_gpes_always_on_setup(char *str)
 
 __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
 
+/* Check of resource interference between native drivers and ACPI
+ * OperationRegions (SystemIO and System Memory only).
+ * IO ports and memory declared in ACPI might be used by the ACPI subsystem
+ * in arbitrary AML code and can interfere with legacy drivers.
+ * acpi_enforce_resources= can be set to:
+ *
+ *   - strict           (2)
+ *     -> further driver trying to access the resources will not load
+ *   - lax (default)    (1)
+ *     -> further driver trying to access the resources will load, but you
+ *     get a system message that something might go wrong...
+ *
+ *   - no               (0)
+ *     -> ACPI Operation Region resources will not be registered
+ *
+ */
+#define ENFORCE_RESOURCES_STRICT 2
+#define ENFORCE_RESOURCES_LAX    1
+#define ENFORCE_RESOURCES_NO     0
+
+static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
+
+static int __init acpi_enforce_resources_setup(char *str)
+{
+       if (str == NULL || *str == '\0')
+               return 0;
+
+       if (!strcmp("strict", str))
+               acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
+       else if (!strcmp("lax", str))
+               acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
+       else if (!strcmp("no", str))
+               acpi_enforce_resources = ENFORCE_RESOURCES_NO;
+
+       return 1;
+}
+
+__setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
+
+/* Check for resource conflicts between ACPI OperationRegions and native
+ * drivers */
+int acpi_check_resource_conflict(struct resource *res)
+{
+       struct acpi_res_list *res_list_elem;
+       int ioport;
+       int clash = 0;
+
+       if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
+               return 0;
+       if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
+               return 0;
+
+       ioport = res->flags & IORESOURCE_IO;
+
+       spin_lock(&acpi_res_lock);
+       list_for_each_entry(res_list_elem, &resource_list_head,
+                           resource_list) {
+               if (ioport && (res_list_elem->resource_type
+                              != ACPI_ADR_SPACE_SYSTEM_IO))
+                       continue;
+               if (!ioport && (res_list_elem->resource_type
+                               != ACPI_ADR_SPACE_SYSTEM_MEMORY))
+                       continue;
+
+               if (res->end < res_list_elem->start
+                   || res_list_elem->end < res->start)
+                       continue;
+               clash = 1;
+               break;
+       }
+       spin_unlock(&acpi_res_lock);
+
+       if (clash) {
+               if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
+                       printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]"
+                              " conflicts with ACPI region %s"
+                              " [0x%llx-0x%llx]\n",
+                              acpi_enforce_resources == ENFORCE_RESOURCES_LAX
+                              ? KERN_WARNING : KERN_ERR,
+                              ioport ? "I/O" : "Memory", res->name,
+                              (long long) res->start, (long long) res->end,
+                              res_list_elem->name,
+                              (long long) res_list_elem->start,
+                              (long long) res_list_elem->end);
+                       printk(KERN_INFO "ACPI: Device needs an ACPI driver\n");
+               }
+               if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
+                       return -EBUSY;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(acpi_check_resource_conflict);
+
+int acpi_check_region(resource_size_t start, resource_size_t n,
+                     const char *name)
+{
+       struct resource res = {
+               .start = start,
+               .end   = start + n - 1,
+               .name  = name,
+               .flags = IORESOURCE_IO,
+       };
+
+       return acpi_check_resource_conflict(&res);
+}
+EXPORT_SYMBOL(acpi_check_region);
+
+int acpi_check_mem_region(resource_size_t start, resource_size_t n,
+                     const char *name)
+{
+       struct resource res = {
+               .start = start,
+               .end   = start + n - 1,
+               .name  = name,
+               .flags = IORESOURCE_MEM,
+       };
+
+       return acpi_check_resource_conflict(&res);
+
+}
+EXPORT_SYMBOL(acpi_check_mem_region);
+
 /*
  * Acquire a spinlock.
  *
@@ -1152,6 +1391,34 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
        return (AE_OK);
 }
 
+/**
+ *     acpi_dmi_dump - dump DMI slots needed for blacklist entry
+ *
+ *     Returns 0 on success
+ */
+static int acpi_dmi_dump(void)
+{
+
+       if (!dmi_available)
+               return -1;
+
+       printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
+               dmi_get_system_info(DMI_SYS_VENDOR));
+       printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
+               dmi_get_system_info(DMI_PRODUCT_NAME));
+       printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
+               dmi_get_system_info(DMI_PRODUCT_VERSION));
+       printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
+               dmi_get_system_info(DMI_BOARD_NAME));
+       printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
+               dmi_get_system_info(DMI_BIOS_VENDOR));
+       printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
+               dmi_get_system_info(DMI_BIOS_DATE));
+
+       return 0;
+}
+
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_os_validate_interface
@@ -1171,13 +1438,29 @@ acpi_os_validate_interface (char *interface)
        if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
                return AE_OK;
        if (!strcmp("Linux", interface)) {
-               printk(KERN_WARNING PREFIX
-                       "System BIOS is requesting _OSI(Linux)\n");
-               printk(KERN_WARNING PREFIX
-                       "If \"acpi_osi=Linux\" works better,\n"
-                       "Please send dmidecode "
-                       "to linux-acpi@vger.kernel.org\n");
-               if(osi_linux)
+
+               printk(KERN_NOTICE PREFIX
+                       "BIOS _OSI(Linux) query %s%s\n",
+                       osi_linux.enable ? "honored" : "ignored",
+                       osi_linux.cmdline ? " via cmdline" :
+                       osi_linux.dmi ? " via DMI" : "");
+
+               if (!osi_linux.dmi) {
+                       if (acpi_dmi_dump())
+                               printk(KERN_NOTICE PREFIX
+                                       "[please extract dmidecode output]\n");
+                       printk(KERN_NOTICE PREFIX
+                               "Please send DMI info above to "
+                               "linux-acpi@vger.kernel.org\n");
+               }
+               if (!osi_linux.known && !osi_linux.cmdline) {
+                       printk(KERN_NOTICE PREFIX
+                               "If \"acpi_osi=%sLinux\" works better, "
+                               "please notify linux-acpi@vger.kernel.org\n",
+                               osi_linux.enable ? "!" : "");
+               }
+
+               if (osi_linux.enable)
                        return AE_OK;
        }
        return AE_SUPPORT;
@@ -1203,34 +1486,46 @@ acpi_status
 acpi_os_validate_address (
     u8                   space_id,
     acpi_physical_address   address,
-    acpi_size               length)
+    acpi_size               length,
+    char *name)
 {
+       struct acpi_res_list *res;
+       if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
+               return AE_OK;
 
-    return AE_OK;
-}
-
-#ifdef CONFIG_DMI
-static int dmi_osi_linux(const struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
-       enable_osi_linux(1);
-       return 0;
+       switch (space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               /* Only interference checks against SystemIO and SytemMemory
+                  are needed */
+               res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
+               if (!res)
+                       return AE_OK;
+               /* ACPI names are fixed to 4 bytes, still better use strlcpy */
+               strlcpy(res->name, name, 5);
+               res->start = address;
+               res->end = address + length - 1;
+               res->resource_type = space_id;
+               spin_lock(&acpi_res_lock);
+               list_add(&res->resource_list, &resource_list_head);
+               spin_unlock(&acpi_res_lock);
+               pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
+                        "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+                        ? "SystemIO" : "System Memory",
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end,
+                        res->name);
+               break;
+       case ACPI_ADR_SPACE_PCI_CONFIG:
+       case ACPI_ADR_SPACE_EC:
+       case ACPI_ADR_SPACE_SMBUS:
+       case ACPI_ADR_SPACE_CMOS:
+       case ACPI_ADR_SPACE_PCI_BAR_TARGET:
+       case ACPI_ADR_SPACE_DATA_TABLE:
+       case ACPI_ADR_SPACE_FIXED_HARDWARE:
+               break;
+       }
+       return AE_OK;
 }
 
-static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
-       /*
-        * Boxes that need _OSI(Linux)
-        */
-       {
-        .callback = dmi_osi_linux,
-        .ident = "Intel Napa CRB",
-        .matches = {
-                    DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
-                    DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
-                    },
-        },
-       {}
-};
-#endif /* CONFIG_DMI */
-
 #endif