[IA64] Cleanup of arch/ia64/sn and include/asm-ia64/sn
[safe/jmp/linux-2.6] / arch / ia64 / sn / kernel / io_init.c
index a6649ba..233d551 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>
 #include <asm/sn/simulator.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/tioca_provider.h>
+#include <asm/sn/tioce_provider.h>
 #include "xtalk/hubdev.h"
 #include "xtalk/xwidgetdev.h"
 
-nasid_t master_nasid = INVALID_NASID;  /* Partition Master */
-
 static struct list_head sn_sysdata_list;
 
 /* sysdata list struct */
@@ -44,6 +43,9 @@ int sn_ioif_inited = 0;               /* SN I/O infrastructure initialized? */
 
 struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES];      /* indexed by asic type */
 
+static int max_segment_number = 0; /* Default highest segment number */
+static int max_pcibus_number = 255; /* Default highest pci bus number */
+
 /*
  * Hooks and struct for unsupported pci providers
  */
@@ -74,11 +76,12 @@ static struct sn_pcibus_provider sn_pci_default_provider = {
 };
 
 /*
- * Retrieve the DMA Flush List given nasid.  This list is needed 
- * to implement the WAR - Flush DMA data on PIO Reads.
+ * Retrieve the DMA Flush List given nasid, widget, and device.
+ * This list is needed to implement the WAR - Flush DMA data on PIO Reads.
  */
-static inline uint64_t
-sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address)
+static inline u64
+sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
+                            u64 address)
 {
 
        struct ia64_sal_retval ret_stuff;
@@ -86,17 +89,17 @@ sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address)
        ret_stuff.v0 = 0;
 
        SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
-                       (u64) nasid, (u64) widget_num, (u64) address, 0, 0, 0,
-                       0);
-       return ret_stuff.v0;
+                       (u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST,
+                       (u64) nasid, (u64) widget_num,
+                       (u64) device_num, (u64) address, 0, 0, 0);
+       return ret_stuff.status;
 
 }
 
 /*
  * Retrieve the hub device info structure for the given nasid.
  */
-static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address)
+static inline u64 sal_get_hubdev_info(u64 handle, u64 address)
 {
 
        struct ia64_sal_retval ret_stuff;
@@ -112,7 +115,7 @@ static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address)
 /*
  * Retrieve the pci bus information given the bus number.
  */
-static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
+static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
 {
 
        struct ia64_sal_retval ret_stuff;
@@ -128,9 +131,9 @@ static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
 /*
  * Retrieve the pci device information given the bus and device|function number.
  */
-static inline uint64_t
-sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, 
-                       u64 sn_irq_info)
+static inline u64
+sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
+                   u64 sn_irq_info)
 {
        struct ia64_sal_retval ret_stuff;
        ret_stuff.status = 0;
@@ -138,32 +141,65 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
 
        SAL_CALL_NOLOCK(ret_stuff,
                        (u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
-                       (u64) segment, (u64) bus_number, (u64) devfn, 
+                       (u64) segment, (u64) bus_number, (u64) devfn,
                        (u64) pci_dev,
                        sn_irq_info, 0, 0);
        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.
  */
 static void sn_fixup_ionodes(void)
 {
-
-       struct sn_flush_device_list *sn_flush_device_list;
+       struct sn_flush_device_kernel *sn_flush_device_kernel;
+       struct sn_flush_device_kernel *dev_entry;
        struct hubdev_info *hubdev;
-       uint64_t status;
-       uint64_t nasid;
-       int i, widget;
+       u64 status;
+       u64 nasid;
+       int i, widget, device;
 
-       for (i = 0; i < numionodes; i++) {
+       /*
+        * Get SGI Specific HUB chipset information.
+        * Inform Prom that this kernel can support domain bus numbering.
+        */
+       for (i = 0; i < num_cnodes; i++) {
                hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
                nasid = cnodeid_to_nasid(i);
-               status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev));
+               hubdev->max_segment_number = 0xffffffff;
+               hubdev->max_pcibus_number = 0xff;
+               status = sal_get_hubdev_info(nasid, (u64) __pa(hubdev));
                if (status)
                        continue;
 
+               /* Save the largest Domain and pcibus numbers found. */
+               if (hubdev->max_segment_number) {
+                       /*
+                        * Dealing with a Prom that supports segments.
+                        */
+                       max_segment_number = hubdev->max_segment_number;
+                       max_pcibus_number = hubdev->max_pcibus_number;
+               }
+
                /* Attach the error interrupt handlers */
                if (nasid & 1)
                        ice_error_init(hubdev);
@@ -178,37 +214,93 @@ static void sn_fixup_ionodes(void)
 
                hubdev->hdi_flush_nasid_list.widget_p =
                    kmalloc((HUB_WIDGET_ID_MAX + 1) *
-                           sizeof(struct sn_flush_device_list *), GFP_KERNEL);
-
+                           sizeof(struct sn_flush_device_kernel *),
+                           GFP_KERNEL);
                memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0,
                       (HUB_WIDGET_ID_MAX + 1) *
-                      sizeof(struct sn_flush_device_list *));
+                      sizeof(struct sn_flush_device_kernel *));
 
                for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
-                       sn_flush_device_list = kmalloc(DEV_PER_WIDGET *
-                                                      sizeof(struct
-                                                             sn_flush_device_list),
-                                                      GFP_KERNEL);
-                       memset(sn_flush_device_list, 0x0,
+                       sn_flush_device_kernel = kmalloc(DEV_PER_WIDGET *
+                                                        sizeof(struct
+                                                       sn_flush_device_kernel),
+                                                       GFP_KERNEL);
+                       if (!sn_flush_device_kernel)
+                               BUG();
+                       memset(sn_flush_device_kernel, 0x0,
                               DEV_PER_WIDGET *
-                              sizeof(struct sn_flush_device_list));
-
-                       status =
-                           sal_get_widget_dmaflush_list(nasid, widget,
-                                                        (uint64_t)
-                                                        __pa
-                                                        (sn_flush_device_list));
-                       if (status) {
-                               kfree(sn_flush_device_list);
-                               continue;
+                              sizeof(struct sn_flush_device_kernel));
+
+                       dev_entry = sn_flush_device_kernel;
+                       for (device = 0; device < DEV_PER_WIDGET;
+                            device++,dev_entry++) {
+                               dev_entry->common = kmalloc(sizeof(struct
+                                                       sn_flush_device_common),
+                                                           GFP_KERNEL);
+                               if (!dev_entry->common)
+                                       BUG();
+                               memset(dev_entry->common, 0x0, sizeof(struct
+                                                      sn_flush_device_common));
+
+                               status = sal_get_device_dmaflush_list(nasid,
+                                                                       widget,
+                                                                       device,
+                                                     (u64)(dev_entry->common));
+                               if (status)
+                                       BUG();
+
+                               spin_lock_init(&dev_entry->sfdl_flush_lock);
                        }
 
-                       hubdev->hdi_flush_nasid_list.widget_p[widget] =
-                           sn_flush_device_list;
-               }
+                       if (sn_flush_device_kernel)
+                               hubdev->hdi_flush_nasid_list.widget_p[widget] =
+                                                      sn_flush_device_kernel;
+               }
+       }
+}
 
+/*
+ * 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,
+                   s64 * 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)
@@ -228,21 +320,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 = 0;
+       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;
+       s64 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)
@@ -252,22 +346,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;
@@ -276,23 +382,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;
-       devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
-       host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
+       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];
@@ -302,11 +412,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);
        }
 }
@@ -320,9 +430,10 @@ 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;
+       void *provider_soft = NULL;
        struct sn_pcibus_provider *provider;
 
        status = sal_get_pcibus_info((u64) segment, (u64) busnum,
@@ -331,14 +442,20 @@ 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 = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
-       if (!controller)
-               BUG();
+       /* 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 (bus == NULL) {
                bus = pci_scan_bus(busnum, &pci_root_ops, controller);
                if (bus == NULL)
-                       return; /* error, or bus already scanned */
+                       goto error_return; /* error, or bus already scanned */
                bus->sysdata = NULL;
        }
 
@@ -351,28 +468,53 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
         */
 
        if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES)
-               return;         /* unsupported asic type */
+               goto error_return; /* unsupported asic type */
 
        if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB)
                goto error_return; /* no further fixup necessary */
 
        provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type];
        if (provider == NULL)
-               return;         /* no provider registerd for this asic */
+               goto error_return; /* no provider registerd for this asic */
 
-       provider_soft = NULL;
+       bus->sysdata = controller;
        if (provider->bus_fixup)
                provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr, controller);
 
-       if (provider_soft == NULL)
-               return;         /* fixup failed or not applicable */
+       if (provider_soft == NULL) {
+               /* fixup failed or not applicable */
+               bus->sysdata = NULL;
+               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.
         */
 
-       bus->sysdata = controller;
        PCI_CONTROLLER(bus)->platform_data = provider_soft;
        nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
        cnode = nasid_to_cnodeid(nasid);
@@ -387,7 +529,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        if (controller->node >= num_online_nodes()) {
                struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);
 
-               printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%lu"
+               printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u"
                                    "L_IO=%lx L_MEM=%lx BASE=%lx\n",
                        b->bs_asic_type, b->bs_xid, b->bs_persist_busnum,
                        b->bs_legacy_io, b->bs_legacy_mem, b->bs_base);
@@ -400,7 +542,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
 
 error_return:
 
-       kfree(controller);
+       kfree(sn_controller);
        return;
 }
 
@@ -408,12 +550,12 @@ void sn_bus_store_sysdata(struct pci_dev *dev)
 {
        struct sysdata_el *element;
 
-       element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL);
+       element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL);
        if (!element) {
                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);
 }
 
@@ -442,6 +584,7 @@ sn_sysdata_free_start:
 static int __init sn_pci_init(void)
 {
        int i = 0;
+       int j = 0;
        struct pci_dev *pci_dev = NULL;
        extern void sn_init_cpei_timer(void);
 #ifdef CONFIG_PROC_FS
@@ -461,6 +604,7 @@ static int __init sn_pci_init(void)
 
        pcibr_init_provider();
        tioca_init_provider();
+       tioce_init_provider();
 
        /*
         * This is needed to avoid bounce limit checks in the blk layer
@@ -476,8 +620,9 @@ static int __init sn_pci_init(void)
 #endif
 
        /* busses are not known yet ... */
-       for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
-               sn_pci_controller_fixup(0, i, NULL);
+       for (i = 0; i <= max_segment_number; i++)
+               for (j = 0; j <= max_pcibus_number; j++)
+                       sn_pci_controller_fixup(i, j, NULL);
 
        /*
         * Generic Linux PCI Layer has created the pci_bus and pci_dev