Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / drivers / pnp / pnpacpi / rsparser.c
index 5702b2c..35bb44a 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/acpi.h>
 #include <linux/pci.h>
 #include <linux/pnp.h>
+#include <linux/slab.h>
 #include "../base.h"
 #include "pnpacpi.h"
 
@@ -177,7 +178,8 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
 }
 
 static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
-                                              u64 len, int io_decode)
+                                              u64 len, int io_decode,
+                                              int window)
 {
        int flags = 0;
        u64 end = start + len - 1;
@@ -186,6 +188,8 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
                flags |= IORESOURCE_IO_16BIT_ADDR;
        if (len == 0 || end >= 0x10003)
                flags |= IORESOURCE_DISABLED;
+       if (window)
+               flags |= IORESOURCE_WINDOW;
 
        pnp_add_io_resource(dev, start, end, flags);
 }
@@ -247,7 +251,7 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,
 
 static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
                                                u64 start, u64 len,
-                                               int write_protect)
+                                               int write_protect, int window)
 {
        int flags = 0;
        u64 end = start + len - 1;
@@ -256,15 +260,47 @@ static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
                flags |= IORESOURCE_DISABLED;
        if (write_protect == ACPI_READ_WRITE_MEMORY)
                flags |= IORESOURCE_MEM_WRITEABLE;
+       if (window)
+               flags |= IORESOURCE_WINDOW;
 
        pnp_add_mem_resource(dev, start, end, flags);
 }
 
+static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev,
+                                               u64 start, u64 len)
+{
+       u64 end = start + len - 1;
+
+       pnp_add_bus_resource(dev, start, end);
+}
+
+static u64 addr_space_length(struct pnp_dev *dev, u64 min, u64 max, u64 len)
+{
+       u64 max_len;
+
+       max_len = max - min + 1;
+       if (len <= max_len)
+               return len;
+
+       /*
+        * Per 6.4.3.5, _LEN cannot exceed _MAX - _MIN + 1, but some BIOSes
+        * don't do this correctly, e.g.,
+        * https://bugzilla.kernel.org/show_bug.cgi?id=15480
+        */
+       dev_info(&dev->dev,
+                "resource length %#llx doesn't fit in %#llx-%#llx, trimming\n",
+                (unsigned long long) len, (unsigned long long) min,
+                (unsigned long long) max);
+       return max_len;
+}
+
 static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
                                                  struct acpi_resource *res)
 {
        struct acpi_resource_address64 addr, *p = &addr;
        acpi_status status;
+       int window;
+       u64 len;
 
        status = acpi_resource_to_address64(res, p);
        if (!ACPI_SUCCESS(status)) {
@@ -273,37 +309,39 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
                return;
        }
 
-       if (p->producer_consumer == ACPI_PRODUCER)
-               return;
+       len = addr_space_length(dev, p->minimum, p->maximum, p->address_length);
+       window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
 
        if (p->resource_type == ACPI_MEMORY_RANGE)
-               pnpacpi_parse_allocated_memresource(dev,
-                       p->minimum, p->address_length,
-                       p->info.mem.write_protect);
+               pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
+                       p->info.mem.write_protect, window);
        else if (p->resource_type == ACPI_IO_RANGE)
-               pnpacpi_parse_allocated_ioresource(dev,
-                       p->minimum, p->address_length,
+               pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
                        p->granularity == 0xfff ? ACPI_DECODE_10 :
-                               ACPI_DECODE_16);
+                               ACPI_DECODE_16, window);
+       else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
+               pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
 }
 
 static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
                                                      struct acpi_resource *res)
 {
        struct acpi_resource_extended_address64 *p = &res->data.ext_address64;
+       int window;
+       u64 len;
 
-       if (p->producer_consumer == ACPI_PRODUCER)
-               return;
+       len = addr_space_length(dev, p->minimum, p->maximum, p->address_length);
+       window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
 
        if (p->resource_type == ACPI_MEMORY_RANGE)
-               pnpacpi_parse_allocated_memresource(dev,
-                       p->minimum, p->address_length,
-                       p->info.mem.write_protect);
+               pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
+                       p->info.mem.write_protect, window);
        else if (p->resource_type == ACPI_IO_RANGE)
-               pnpacpi_parse_allocated_ioresource(dev,
-                       p->minimum, p->address_length,
+               pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
                        p->granularity == 0xfff ? ACPI_DECODE_10 :
-                               ACPI_DECODE_16);
+                               ACPI_DECODE_16, window);
+       else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
+               pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
 }
 
 static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
@@ -368,7 +406,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
                pnpacpi_parse_allocated_ioresource(dev,
                        io->minimum,
                        io->address_length,
-                       io->io_decode);
+                       io->io_decode, 0);
                break;
 
        case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -380,7 +418,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
                pnpacpi_parse_allocated_ioresource(dev,
                        fixed_io->address,
                        fixed_io->address_length,
-                       ACPI_DECODE_10);
+                       ACPI_DECODE_10, 0);
                break;
 
        case ACPI_RESOURCE_TYPE_VENDOR:
@@ -396,21 +434,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
                pnpacpi_parse_allocated_memresource(dev,
                        memory24->minimum,
                        memory24->address_length,
-                       memory24->write_protect);
+                       memory24->write_protect, 0);
                break;
        case ACPI_RESOURCE_TYPE_MEMORY32:
                memory32 = &res->data.memory32;
                pnpacpi_parse_allocated_memresource(dev,
                        memory32->minimum,
                        memory32->address_length,
-                       memory32->write_protect);
+                       memory32->write_protect, 0);
                break;
        case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
                fixed_memory32 = &res->data.fixed_memory32;
                pnpacpi_parse_allocated_memresource(dev,
                        fixed_memory32->address,
                        fixed_memory32->address_length,
-                       fixed_memory32->write_protect);
+                       fixed_memory32->write_protect, 0);
                break;
        case ACPI_RESOURCE_TYPE_ADDRESS16:
        case ACPI_RESOURCE_TYPE_ADDRESS32: