[IA64-SGI] altix: pci_window fixup
authorJohn Keller <jpk@sgi.com>
Tue, 29 Nov 2005 22:36:32 +0000 (16:36 -0600)
committerTony Luck <tony.luck@intel.com>
Tue, 6 Dec 2005 17:09:23 +0000 (09:09 -0800)
Altix only patch to add fixup code that sets up
pci_controller->window. This code is a temporary
fix until ACPI support on Altix is added.

Also, corrects the usage of pci_dev->sysdata,
which had previously been used to reference
platform specific device info, to now point to
a pci_controller struct.

Signed-off-by: John Keller <jpk@sgi.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
arch/ia64/sn/kernel/io_init.c
include/asm-ia64/sn/pcidev.h

index 05e4ea8899818f8bc06cff895246a3cd55906bbe..318087e35b66c2ad2cef6114469d4e873d5fe6b1 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/bootmem.h>
@@ -146,6 +146,24 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
        return ret_stuff.v0;
 }
 
+/*
+ * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
+ *                       device.
+ */
+inline struct pcidev_info *
+sn_pcidev_info_get(struct pci_dev *dev)
+{
+       struct pcidev_info *pcidev;
+
+       list_for_each_entry(pcidev,
+                           &(SN_PCI_CONTROLLER(dev)->pcidev_info), pdi_list) {
+               if (pcidev->pdi_linux_pcidev == dev) {
+                       return pcidev;
+               }
+       }
+       return NULL;
+}
+
 /*
  * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for 
  *     each node in the system.
@@ -229,6 +247,50 @@ static void sn_fixup_ionodes(void)
 
 }
 
+/*
+ * sn_pci_window_fixup() - Create a pci_window for each device resource.
+ *                        Until ACPI support is added, we need this code
+ *                        to setup pci_windows for use by
+ *                        pcibios_bus_to_resource(),
+ *                        pcibios_resource_to_bus(), etc.
+ */
+static void
+sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
+                   int64_t * pci_addrs)
+{
+       struct pci_controller *controller = PCI_CONTROLLER(dev->bus);
+       unsigned int i;
+       unsigned int idx;
+       unsigned int new_count;
+       struct pci_window *new_window;
+
+       if (count == 0)
+               return;
+       idx = controller->windows;
+       new_count = controller->windows + count;
+       new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL);
+       if (new_window == NULL)
+               BUG();
+       if (controller->window) {
+               memcpy(new_window, controller->window,
+                      sizeof(struct pci_window) * controller->windows);
+               kfree(controller->window);
+       }
+
+       /* Setup a pci_window for each device resource. */
+       for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+               if (pci_addrs[i] == -1)
+                       continue;
+
+               new_window[idx].offset = dev->resource[i].start - pci_addrs[i];
+               new_window[idx].resource = dev->resource[i];
+               idx++;
+       }
+
+       controller->windows = new_count;
+       controller->window = new_window;
+}
+
 void sn_pci_unfixup_slot(struct pci_dev *dev)
 {
        struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;
@@ -246,21 +308,23 @@ void sn_pci_unfixup_slot(struct pci_dev *dev)
  */
 void sn_pci_fixup_slot(struct pci_dev *dev)
 {
+       unsigned int count = 0;
        int idx;
        int segment = pci_domain_nr(dev->bus);
        int status = 0;
        struct pcibus_bussoft *bs;
        struct pci_bus *host_pci_bus;
        struct pci_dev *host_pci_dev;
+       struct pcidev_info *pcidev_info;
+       int64_t pci_addrs[PCI_ROM_RESOURCE + 1];
        struct sn_irq_info *sn_irq_info;
        unsigned long size;
        unsigned int bus_no, devfn;
 
        pci_dev_get(dev); /* for the sysdata pointer */
-       dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
-       if (SN_PCIDEV_INFO(dev) <= 0)
+       pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
+       if (pcidev_info <= 0)
                BUG();          /* Cannot afford to run out of memory */
-       memset(SN_PCIDEV_INFO(dev), 0, sizeof(struct pcidev_info));
 
        sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
        if (sn_irq_info <= 0)
@@ -270,22 +334,34 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
        /* Call to retrieve pci device information needed by kernel. */
        status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, 
                                     dev->devfn,
-                                    (u64) __pa(SN_PCIDEV_INFO(dev)),
+                                    (u64) __pa(pcidev_info),
                                     (u64) __pa(sn_irq_info));
        if (status)
                BUG(); /* Cannot get platform pci device information */
 
+       /* Add pcidev_info to list in sn_pci_controller struct */
+       list_add_tail(&pcidev_info->pdi_list,
+                     &(SN_PCI_CONTROLLER(dev->bus)->pcidev_info));
+
        /* Copy over PIO Mapped Addresses */
        for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
                unsigned long start, end, addr;
 
-               if (!SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx])
+               if (!pcidev_info->pdi_pio_mapped_addr[idx]) {
+                       pci_addrs[idx] = -1;
                        continue;
+               }
 
                start = dev->resource[idx].start;
                end = dev->resource[idx].end;
                size = end - start;
-               addr = SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx];
+               if (size == 0) {
+                       pci_addrs[idx] = -1;
+                       continue;
+               }
+               pci_addrs[idx] = start;
+               count++;
+               addr = pcidev_info->pdi_pio_mapped_addr[idx];
                addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET;
                dev->resource[idx].start = addr;
                dev->resource[idx].end = addr + size;
@@ -294,23 +370,27 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
                else
                        dev->resource[idx].parent = &iomem_resource;
        }
+       /* Create a pci_window in the pci_controller struct for
+        * each device resource.
+        */
+       if (count > 0)
+               sn_pci_window_fixup(dev, count, pci_addrs);
 
        /*
         * Using the PROMs values for the PCI host bus, get the Linux
         * PCI host_pci_dev struct and set up host bus linkages
         */
 
-       bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff;
-       devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
+       bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
+       devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff;
        host_pci_bus = pci_find_bus(segment, bus_no);
        host_pci_dev = pci_get_slot(host_pci_bus, devfn);
 
-       SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
-       SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
-                                               SN_PCIDEV_INFO(host_pci_dev);
-       SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
+       pcidev_info->host_pci_dev = host_pci_dev;
+       pcidev_info->pdi_linux_pcidev = dev;
+       pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev);
        bs = SN_PCIBUS_BUSSOFT(dev->bus);
-       SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs;
+       pcidev_info->pdi_pcibus_info = bs;
 
        if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
                SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type];
@@ -320,11 +400,11 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
 
        /* Only set up IRQ stuff if this device has a host bus context */
        if (bs && sn_irq_info->irq_irq) {
-               SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
-               dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
+               pcidev_info->pdi_sn_irq_info = sn_irq_info;
+               dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq;
                sn_irq_fixup(dev, sn_irq_info);
        } else {
-               SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL;
+               pcidev_info->pdi_sn_irq_info = NULL;
                kfree(sn_irq_info);
        }
 }
@@ -338,6 +418,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        int status = 0;
        int nasid, cnode;
        struct pci_controller *controller;
+       struct sn_pci_controller *sn_controller;
        struct pcibus_bussoft *prom_bussoft_ptr;
        struct hubdev_info *hubdev_info;
        void *provider_soft = NULL;
@@ -349,10 +430,15 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
                return;         /*bus # does not exist */
        prom_bussoft_ptr = __va(prom_bussoft_ptr);
 
-       controller = kzalloc(sizeof(struct pci_controller), GFP_KERNEL);
+       /* Allocate a sn_pci_controller, which has a pci_controller struct
+        * as the first member.
+        */
+       sn_controller = kzalloc(sizeof(struct sn_pci_controller), GFP_KERNEL);
+       if (!sn_controller)
+               BUG();
+       INIT_LIST_HEAD(&sn_controller->pcidev_info);
+       controller = &sn_controller->pci_controller;
        controller->segment = segment;
-       if (!controller)
-               BUG();
 
        if (bus == NULL) {
                bus = pci_scan_bus(busnum, &pci_root_ops, controller);
@@ -389,6 +475,29 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
                goto error_return;
        }
 
+       /*
+        * Setup pci_windows for legacy IO and MEM space.
+        * (Temporary until ACPI support is in place.)
+        */
+       controller->window = kcalloc(2, sizeof(struct pci_window), GFP_KERNEL);
+       if (controller->window == NULL)
+               BUG();
+       controller->window[0].offset = prom_bussoft_ptr->bs_legacy_io;
+       controller->window[0].resource.name = "legacy_io";
+       controller->window[0].resource.flags = IORESOURCE_IO;
+       controller->window[0].resource.start = prom_bussoft_ptr->bs_legacy_io;
+       controller->window[0].resource.end =
+           controller->window[0].resource.start + 0xffff;
+       controller->window[0].resource.parent = &ioport_resource;
+       controller->window[1].offset = prom_bussoft_ptr->bs_legacy_mem;
+       controller->window[1].resource.name = "legacy_mem";
+       controller->window[1].resource.flags = IORESOURCE_MEM;
+       controller->window[1].resource.start = prom_bussoft_ptr->bs_legacy_mem;
+       controller->window[1].resource.end =
+           controller->window[1].resource.start + (1024 * 1024) - 1;
+       controller->window[1].resource.parent = &iomem_resource;
+       controller->windows = 2;
+
        /*
         * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
         * after this point.
@@ -421,7 +530,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
 
 error_return:
 
-       kfree(controller);
+       kfree(sn_controller);
        return;
 }
 
@@ -434,7 +543,7 @@ void sn_bus_store_sysdata(struct pci_dev *dev)
                dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
                return;
        }
-       element->sysdata = dev->sysdata;
+       element->sysdata = SN_PCIDEV_INFO(dev);
        list_add(&element->entry, &sn_sysdata_list);
 }
 
index 49711d00ad04f77d90467daf33bfd13d549e2109..f65d222ca5e82caec06b9739a0e2e7196b066495 100644 (file)
@@ -3,15 +3,27 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_PCI_PCIDEV_H
 #define _ASM_IA64_SN_PCI_PCIDEV_H
 
 #include <linux/pci.h>
 
-#define SN_PCIDEV_INFO(pci_dev) \
-        ((struct pcidev_info *)(pci_dev)->sysdata)
+/*
+ * In ia64, pci_dev->sysdata must be a *pci_controller. To provide access to
+ * the pcidev_info structs for all devices under a controller, we extend the
+ * definition of pci_controller, via sn_pci_controller, to include a list
+ * of pcidev_info.
+ */
+struct sn_pci_controller {
+       struct pci_controller pci_controller;
+       struct list_head pcidev_info;
+};
+
+#define SN_PCI_CONTROLLER(dev) ((struct sn_pci_controller *) dev->sysdata)
+
+#define SN_PCIDEV_INFO(dev)    sn_pcidev_info_get(dev)
 
 #define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \
        (struct pcibus_info *)((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
@@ -53,11 +65,13 @@ struct pcidev_info {
        struct sn_irq_info      *pdi_sn_irq_info;
        struct sn_pcibus_provider *pdi_provider;        /* sn pci ops */
        struct pci_dev          *host_pci_dev;          /* host bus link */
+       struct list_head        pdi_list;               /* List of pcidev_info */
 };
 
 extern void sn_irq_fixup(struct pci_dev *pci_dev,
                         struct sn_irq_info *sn_irq_info);
 extern void sn_irq_unfixup(struct pci_dev *pci_dev);
+extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *);
 extern void sn_pci_controller_fixup(int segment, int busnum,
                                    struct pci_bus *bus);
 extern void sn_bus_store_sysdata(struct pci_dev *dev);