Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / ia64 / pci / pci.c
index 88641e5..ab829a2 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <asm/machvec.h>
 #include <asm/page.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/sal.h>
@@ -32,9 +31,6 @@
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
 
-
-static int pci_routeirq;
-
 /*
  * Low-level SAL-based PCI configuration access functions. Note that SAL
  * calls are already serialized (via sal_lock), so we don't need another
@@ -98,7 +94,7 @@ pci_sal_write (unsigned int seg, unsigned int bus, unsigned int devfn,
 }
 
 static struct pci_raw_ops pci_sal_ops = {
-       .read =         pci_sal_read,
+       .read =         pci_sal_read,
        .write =        pci_sal_write
 };
 
@@ -123,45 +119,6 @@ struct pci_ops pci_root_ops = {
        .write = pci_write,
 };
 
-#ifdef CONFIG_NUMA
-extern acpi_status acpi_map_iosapic(acpi_handle, u32, void *, void **);
-static void acpi_map_iosapics(void)
-{
-       acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL);
-}
-#else
-static void acpi_map_iosapics(void)
-{
-       return;
-}
-#endif /* CONFIG_NUMA */
-
-static int __init
-pci_acpi_init (void)
-{
-       struct pci_dev *dev = NULL;
-
-       printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-
-       acpi_map_iosapics();
-
-       if (pci_routeirq) {
-               /*
-                * PCI IRQ routing is set up by pci_enable_device(), but we
-                * also do it here in case there are still broken drivers that
-                * don't use pci_enable_device().
-                */
-               printk(KERN_INFO "PCI: Routing interrupts for all devices because \"pci=routeirq\" specified\n");
-               for_each_pci_dev(dev)
-                       acpi_pci_irq_enable(dev);
-       } else
-               printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\".  If it helps, post a report\n");
-
-       return 0;
-}
-
-subsys_initcall(pci_acpi_init);
-
 /* Called by ACPI when it finds a new root bus.  */
 
 static struct pci_controller * __devinit
@@ -175,38 +132,125 @@ alloc_pci_controller (int seg)
 
        memset(controller, 0, sizeof(*controller));
        controller->segment = seg;
+       controller->node = -1;
        return controller;
 }
 
-static u64 __devinit
-add_io_space (struct acpi_resource_address64 *addr)
+struct pci_root_info {
+       struct pci_controller *controller;
+       char *name;
+};
+
+static unsigned int
+new_space (u64 phys_base, int sparse)
 {
-       u64 offset;
-       int sparse = 0;
+       u64 mmio_base;
        int i;
 
-       if (addr->address_translation_offset == 0)
-               return IO_SPACE_BASE(0);        /* part of legacy IO space */
+       if (phys_base == 0)
+               return 0;       /* legacy I/O port space */
 
-       if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION)
-               sparse = 1;
-
-       offset = (u64) ioremap(addr->address_translation_offset, 0);
+       mmio_base = (u64) ioremap(phys_base, 0);
        for (i = 0; i < num_io_spaces; i++)
-               if (io_space[i].mmio_base == offset &&
+               if (io_space[i].mmio_base == mmio_base &&
                    io_space[i].sparse == sparse)
-                       return IO_SPACE_BASE(i);
+                       return i;
 
        if (num_io_spaces == MAX_IO_SPACES) {
-               printk("Too many IO port spaces\n");
+               printk(KERN_ERR "PCI: Too many IO port spaces "
+                       "(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES);
                return ~0;
        }
 
        i = num_io_spaces++;
-       io_space[i].mmio_base = offset;
+       io_space[i].mmio_base = mmio_base;
        io_space[i].sparse = sparse;
 
-       return IO_SPACE_BASE(i);
+       return i;
+}
+
+static u64 __devinit
+add_io_space (struct pci_root_info *info, struct acpi_resource_address64 *addr)
+{
+       struct resource *resource;
+       char *name;
+       u64 base, min, max, base_port;
+       unsigned int sparse = 0, space_nr, len;
+
+       resource = kzalloc(sizeof(*resource), GFP_KERNEL);
+       if (!resource) {
+               printk(KERN_ERR "PCI: No memory for %s I/O port space\n",
+                       info->name);
+               goto out;
+       }
+
+       len = strlen(info->name) + 32;
+       name = kzalloc(len, GFP_KERNEL);
+       if (!name) {
+               printk(KERN_ERR "PCI: No memory for %s I/O port space name\n",
+                       info->name);
+               goto free_resource;
+       }
+
+       min = addr->minimum;
+       max = min + addr->address_length - 1;
+       if (addr->info.io.translation_type == ACPI_SPARSE_TRANSLATION)
+               sparse = 1;
+
+       space_nr = new_space(addr->translation_offset, sparse);
+       if (space_nr == ~0)
+               goto free_name;
+
+       base = __pa(io_space[space_nr].mmio_base);
+       base_port = IO_SPACE_BASE(space_nr);
+       snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name,
+               base_port + min, base_port + max);
+
+       /*
+        * The SDM guarantees the legacy 0-64K space is sparse, but if the
+        * mapping is done by the processor (not the bridge), ACPI may not
+        * mark it as sparse.
+        */
+       if (space_nr == 0)
+               sparse = 1;
+
+       resource->name  = name;
+       resource->flags = IORESOURCE_MEM;
+       resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
+       resource->end   = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
+       insert_resource(&iomem_resource, resource);
+
+       return base_port;
+
+free_name:
+       kfree(name);
+free_resource:
+       kfree(resource);
+out:
+       return ~0;
+}
+
+static acpi_status __devinit resource_to_window(struct acpi_resource *resource,
+       struct acpi_resource_address64 *addr)
+{
+       acpi_status status;
+
+       /*
+        * We're only interested in _CRS descriptors that are
+        *      - address space descriptors for memory or I/O space
+        *      - non-zero size
+        *      - producers, i.e., the address space is routed downstream,
+        *        not consumed by the bridge itself
+        */
+       status = acpi_resource_to_address64(resource, addr);
+       if (ACPI_SUCCESS(status) &&
+           (addr->resource_type == ACPI_MEMORY_RANGE ||
+            addr->resource_type == ACPI_IO_RANGE) &&
+           addr->address_length &&
+           addr->producer_consumer == ACPI_PRODUCER)
+               return AE_OK;
+
+       return AE_ERROR;
 }
 
 static acpi_status __devinit
@@ -216,20 +260,13 @@ count_window (struct acpi_resource *resource, void *data)
        struct acpi_resource_address64 addr;
        acpi_status status;
 
-       status = acpi_resource_to_address64(resource, &addr);
+       status = resource_to_window(resource, &addr);
        if (ACPI_SUCCESS(status))
-               if (addr.resource_type == ACPI_MEMORY_RANGE ||
-                   addr.resource_type == ACPI_IO_RANGE)
-                       (*windows)++;
+               (*windows)++;
 
        return AE_OK;
 }
 
-struct pci_root_info {
-       struct pci_controller *controller;
-       char *name;
-};
-
 static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
 {
        struct pci_root_info *info = data;
@@ -239,21 +276,19 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
        unsigned long flags, offset = 0;
        struct resource *root;
 
-       status = acpi_resource_to_address64(res, &addr);
+       /* Return AE_OK for non-window resources to keep scanning for more */
+       status = resource_to_window(res, &addr);
        if (!ACPI_SUCCESS(status))
                return AE_OK;
 
-       if (!addr.address_length)
-               return AE_OK;
-
        if (addr.resource_type == ACPI_MEMORY_RANGE) {
                flags = IORESOURCE_MEM;
                root = &iomem_resource;
-               offset = addr.address_translation_offset;
+               offset = addr.translation_offset;
        } else if (addr.resource_type == ACPI_IO_RANGE) {
                flags = IORESOURCE_IO;
                root = &ioport_resource;
-               offset = add_io_space(&addr);
+               offset = add_io_space(info, &addr);
                if (offset == ~0)
                        return AE_OK;
        } else
@@ -262,8 +297,8 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
        window = &info->controller->window[info->controller->windows++];
        window->resource.name = info->name;
        window->resource.flags = flags;
-       window->resource.start = addr.min_address_range + offset;
-       window->resource.end = addr.max_address_range + offset;
+       window->resource.start = addr.minimum + offset;
+       window->resource.end = window->resource.start + addr.address_length - 1;
        window->resource.child = NULL;
        window->offset = offset;
 
@@ -306,6 +341,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
        unsigned int windows = 0;
        struct pci_bus *pbus;
        char *name;
+       int pxm;
 
        controller = alloc_pci_controller(domain);
        if (!controller)
@@ -313,10 +349,16 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
 
        controller->acpi_handle = device->handle;
 
+       pxm = acpi_get_pxm(controller->acpi_handle);
+#ifdef CONFIG_NUMA
+       if (pxm >= 0)
+               controller->node = pxm_to_nid_map[pxm];
+#endif
+
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
                        &windows);
-       controller->window = kmalloc(sizeof(*controller->window) * windows,
-                       GFP_KERNEL);
+       controller->window = kmalloc_node(sizeof(*controller->window) * windows,
+                       GFP_KERNEL, controller->node);
        if (!controller->window)
                goto out2;
 
@@ -330,7 +372,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window,
                        &info);
 
-       pbus = pci_scan_bus(bus, &pci_root_ops, controller);
+       pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
        if (pbus)
                pcibios_setup_root_windows(pbus, controller);
 
@@ -390,24 +432,54 @@ void pcibios_bus_to_resource(struct pci_dev *dev,
        res->start = region->start + offset;
        res->end = region->end + offset;
 }
+EXPORT_SYMBOL(pcibios_bus_to_resource);
 
-static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
+static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
+{
+       unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+       struct resource *devr = &dev->resource[idx];
+
+       if (!dev->bus)
+               return 0;
+       for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
+               struct resource *busr = dev->bus->resource[i];
+
+               if (!busr || ((busr->flags ^ devr->flags) & type_mask))
+                       continue;
+               if ((devr->start) && (devr->start >= busr->start) &&
+                               (devr->end <= busr->end))
+                       return 1;
+       }
+       return 0;
+}
+
+static void __devinit
+pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
 {
        struct pci_bus_region region;
        int i;
-       int limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? \
-               PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES;
 
-       for (i = 0; i < limit; i++) {
+       for (i = start; i < limit; i++) {
                if (!dev->resource[i].flags)
                        continue;
                region.start = dev->resource[i].start;
                region.end = dev->resource[i].end;
                pcibios_bus_to_resource(dev, &dev->resource[i], &region);
-               pci_claim_resource(dev, i);
+               if ((is_valid_resource(dev, i)))
+                       pci_claim_resource(dev, i);
        }
 }
 
+static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
+{
+       pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES);
+}
+
+static void __devinit pcibios_fixup_bridge_resources(struct pci_dev *dev)
+{
+       pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES);
+}
+
 /*
  *  Called after each bus is probed, but before its children are examined.
  */
@@ -416,6 +488,10 @@ pcibios_fixup_bus (struct pci_bus *b)
 {
        struct pci_dev *dev;
 
+       if (b->self) {
+               pci_read_bridge_bases(b);
+               pcibios_fixup_bridge_resources(b->self);
+       }
        list_for_each_entry(dev, &b->devices, bus_list)
                pcibios_fixup_device_resources(dev);
 
@@ -436,18 +512,24 @@ pcibios_enable_resources (struct pci_dev *dev, int mask)
        u16 cmd, old_cmd;
        int idx;
        struct resource *r;
+       unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
 
        if (!dev)
                return -EINVAL;
 
        pci_read_config_word(dev, PCI_COMMAND, &cmd);
        old_cmd = cmd;
-       for (idx=0; idx<6; idx++) {
+       for (idx=0; idx<PCI_NUM_RESOURCES; idx++) {
                /* Only set up the desired resources.  */
                if (!(mask & (1 << idx)))
                        continue;
 
                r = &dev->resource[idx];
+               if (!(r->flags & type_mask))
+                       continue;
+               if ((idx == PCI_ROM_RESOURCE) &&
+                               (!(r->flags & IORESOURCE_ROM_ENABLE)))
+                       continue;
                if (!r->start && r->end) {
                        printk(KERN_ERR
                               "PCI: Device %s not available because of resource collisions\n",
@@ -459,8 +541,6 @@ pcibios_enable_resources (struct pci_dev *dev, int mask)
                if (r->flags & IORESOURCE_MEM)
                        cmd |= PCI_COMMAND_MEMORY;
        }
-       if (dev->resource[PCI_ROM_RESOURCE].start)
-               cmd |= PCI_COMMAND_MEMORY;
        if (cmd != old_cmd) {
                printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
                pci_write_config_word(dev, PCI_COMMAND, cmd);
@@ -480,13 +560,11 @@ pcibios_enable_device (struct pci_dev *dev, int mask)
        return acpi_pci_irq_enable(dev);
 }
 
-#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
 void
 pcibios_disable_device (struct pci_dev *dev)
 {
        acpi_pci_irq_disable(dev);
 }
-#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
 
 void
 pcibios_align_resource (void *data, struct resource *res,
@@ -500,9 +578,7 @@ pcibios_align_resource (void *data, struct resource *res,
 char * __init
 pcibios_setup (char *str)
 {
-       if (!strcmp(str, "routeirq"))
-               pci_routeirq = 1;
-       return NULL;
+       return str;
 }
 
 int
@@ -630,9 +706,9 @@ int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
  *
  * Simply writes @size bytes of @val to @port.
  */
-int ia64_pci_legacy_write(struct pci_dev *bus, u16 port, u32 val, u8 size)
+int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
 {
-       int ret = 0;
+       int ret = size;
 
        switch (size) {
        case 1:
@@ -729,7 +805,7 @@ int pci_vector_resources(int last, int nr_released)
 {
        int count = nr_released;
 
-       count += (IA64_LAST_DEVICE_VECTOR - last);
+       count += (IA64_LAST_DEVICE_VECTOR - last);
 
        return count;
 }