Pull ngam-maule-steiner into release branch
[sfrench/cifs-2.6.git] / arch / ia64 / sn / kernel / io_init.c
index a67f39e448cb47a0d0aec8429bcbabbf0888d0bc..4564ed0b5ff31e32aab74c819369e3762382f512 100644 (file)
@@ -18,6 +18,7 @@
 #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"
 
@@ -44,6 +45,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
  */
@@ -61,7 +65,7 @@ sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction)
 }
 
 static void *
-sn_default_pci_bus_fixup(struct pcibus_bussoft *soft)
+sn_default_pci_bus_fixup(struct pcibus_bussoft *soft, struct pci_controller *controller)
 {
        return NULL;
 }
@@ -157,13 +161,28 @@ static void sn_fixup_ionodes(void)
        uint64_t nasid;
        int i, widget;
 
+       /*
+        * Get SGI Specific HUB chipset information.
+        * Inform Prom that this kernel can support domain bus numbering.
+        */
        for (i = 0; i < numionodes; i++) {
                hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
                nasid = cnodeid_to_nasid(i);
+               hubdev->max_segment_number = 0xffffffff;
+               hubdev->max_pcibus_number = 0xff;
                status = sal_get_hubdev_info(nasid, (uint64_t) __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);
@@ -203,6 +222,7 @@ static void sn_fixup_ionodes(void)
                                continue;
                        }
 
+                       spin_lock_init(&sn_flush_device_list->sfdl_flush_lock);
                        hubdev->hdi_flush_nasid_list.widget_p[widget] =
                            sn_flush_device_list;
                }
@@ -229,7 +249,7 @@ void sn_pci_unfixup_slot(struct pci_dev *dev)
 void sn_pci_fixup_slot(struct pci_dev *dev)
 {
        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;
@@ -282,9 +302,9 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
         * PCI host_pci_dev struct and set up host bus linkages
         */
 
-       bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32;
+       bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff;
        devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
-       host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
+       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;
@@ -322,7 +342,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        struct pci_controller *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,
@@ -332,13 +352,14 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        prom_bussoft_ptr = __va(prom_bussoft_ptr);
 
        controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
+       controller->segment = segment;
        if (!controller)
                BUG();
 
        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 +372,30 @@ 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);
+               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;
+       }
 
        /*
         * 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);
@@ -380,6 +403,22 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
            &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
 
+       /*
+        * If the node information we obtained during the fixup phase is invalid
+        * then set controller->node to -1 (undetermined)
+        */
+       if (controller->node >= num_online_nodes()) {
+               struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);
+
+               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);
+               printk(KERN_WARNING "on node %d but only %d nodes online."
+                       "Association set to undetermined.\n",
+                       controller->node, num_online_nodes());
+               controller->node = -1;
+       }
        return;
 
 error_return:
@@ -426,6 +465,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
@@ -445,6 +485,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
@@ -460,8 +501,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