X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fia64%2Fsn%2Fkernel%2Fio_init.c;h=9ad843e0383b53a1745591defbf2497461a73471;hb=refs%2Fheads%2Fvserver;hp=9e07f5463f21d53fcac34ec658f443ca550b4222;hpb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;p=linux-2.6.git diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 9e07f5463..9ad843e03 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -3,95 +3,34 @@ * 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-2006 Silicon Graphics, Inc. All rights reserved. */ -#include -#include #include -#include #include +#include +#include +#include #include #include -#include "pci/pcibr_provider.h" -#include "xtalk/xwidgetdev.h" -#include +#include #include "xtalk/hubdev.h" -#include -#include -#include - -char master_baseio_wid; -nasid_t master_nasid = INVALID_NASID; /* Partition Master */ - -struct slab_info { - struct hubdev_info hubdev; -}; - -struct brick { - moduleid_t id; /* Module ID of this module */ - struct slab_info slab_info[MAX_SLABS + 1]; -}; - -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 */ /* - * Hooks and struct for unsupported pci providers + * The code in this file will only be executed when running with + * a PROM that does _not_ have base ACPI IO support. + * (i.e., SN_ACPI_BASE_SUPPORT() == 0) */ -static dma_addr_t -sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size) -{ - return 0; -} +static int max_segment_number; /* Default highest segment number */ +static int max_pcibus_number = 255; /* Default highest pci bus number */ -static void -sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction) -{ - return; -} - -static void * -sn_default_pci_bus_fixup(struct pcibus_bussoft *soft) -{ - return NULL; -} - -static struct sn_pcibus_provider sn_pci_default_provider = { - .dma_map = sn_default_pci_map, - .dma_map_consistent = sn_default_pci_map, - .dma_unmap = sn_default_pci_unmap, - .bus_fixup = sn_default_pci_bus_fixup, -}; - -/* - * Retrieve the DMA Flush List given nasid. 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) -{ - - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - 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; - -} /* * 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; ret_stuff.status = 0; ret_stuff.v0 = 0; @@ -105,9 +44,8 @@ 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; ret_stuff.status = 0; ret_stuff.v0 = 0; @@ -118,154 +56,153 @@ static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address) return ret_stuff.v0; } + /* - * Retrieve the pci device information given the bus and device|function number. + * sn_fixup_ionodes() - This routine initializes the HUB data structure for + * each node in the system. This function is only + * executed when running with a non-ACPI capable PROM. */ -static inline uint64_t -sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, - u64 sn_irq_info) +static void __init sn_fixup_ionodes(void) { - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_GET_PCIDEV_INFO, - (u64) segment, (u64) bus_number, (u64) devfn, - (u64) pci_dev, - sn_irq_info, 0, 0); - return ret_stuff.v0; + struct hubdev_info *hubdev; + u64 status; + u64 nasid; + int i; + extern void sn_common_hubdev_init(struct hubdev_info *); + + /* + * 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); + 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; + } + sn_common_hubdev_init(hubdev); + } } /* - * sn_alloc_pci_sysdata() - This routine allocates a pci controller - * which is expected as the pci_dev and pci_bus sysdata by the Linux - * PCI infrastructure. + * sn_pci_legacy_window_fixup - Create PCI controller windows for + * legacy IO and MEM space. This needs to + * be done here, as the PROM does not have + * ACPI support defining the root buses + * and their resources (_CRS), */ -static inline struct pci_controller *sn_alloc_pci_sysdata(void) +static void +sn_legacy_pci_window_fixup(struct pci_controller *controller, + u64 legacy_io, u64 legacy_mem) { - struct pci_controller *pci_sysdata; - - pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL); - if (!pci_sysdata) - BUG(); - - memset(pci_sysdata, 0, sizeof(*pci_sysdata)); - return pci_sysdata; + controller->window = kcalloc(2, sizeof(struct pci_window), + GFP_KERNEL); + if (controller->window == NULL) + BUG(); + controller->window[0].offset = legacy_io; + controller->window[0].resource.name = "legacy_io"; + controller->window[0].resource.flags = IORESOURCE_IO; + controller->window[0].resource.start = legacy_io; + controller->window[0].resource.end = + controller->window[0].resource.start + 0xffff; + controller->window[0].resource.parent = &ioport_resource; + controller->window[1].offset = legacy_mem; + controller->window[1].resource.name = "legacy_mem"; + controller->window[1].resource.flags = IORESOURCE_MEM; + controller->window[1].resource.start = 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; } /* - * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for - * each node in the system. + * sn_pci_window_fixup() - Create a pci_window for each device resource. + * It will setup pci_windows for use by + * pcibios_bus_to_resource(), pcibios_resource_to_bus(), + * etc. */ -static void sn_fixup_ionodes(void) +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); + } - struct sn_flush_device_list *sn_flush_device_list; - struct hubdev_info *hubdev; - uint64_t status; - uint64_t nasid; - int i, widget; - - for (i = 0; i < numionodes; i++) { - hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); - nasid = cnodeid_to_nasid(i); - status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev)); - if (status) - continue; - - /* Attach the error interrupt handlers */ - if (nasid & 1) - ice_error_init(hubdev); - else - hub_error_init(hubdev); - - for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) - hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev; - - if (!hubdev->hdi_flush_nasid_list.widget_p) + /* Setup a pci_window for each device resource. */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + if (pci_addrs[i] == -1) continue; - hubdev->hdi_flush_nasid_list.widget_p = - kmalloc((HUB_WIDGET_ID_MAX + 1) * - sizeof(struct sn_flush_device_list *), GFP_KERNEL); - - memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0, - (HUB_WIDGET_ID_MAX + 1) * - sizeof(struct sn_flush_device_list *)); - - 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, - 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; - } - - hubdev->hdi_flush_nasid_list.widget_p[widget] = - sn_flush_device_list; - } - + 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; } /* - * sn_pci_fixup_slot() - This routine sets up a slot's resources - * consistent with the Linux PCI abstraction layer. Resources acquired - * from our PCI provider include PIO maps to BAR space and interrupt - * objects. + * sn_more_slot_fixup() - We are not running with an ACPI capable PROM, + * and need to convert the pci_dev->resource + * 'start' and 'end' addresses to mapped addresses, + * and setup the pci_controller->window array entries. */ -static void sn_pci_fixup_slot(struct pci_dev *dev) +void +sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) { + unsigned int count = 0; int idx; - int segment = 0; - uint64_t size; - struct sn_irq_info *sn_irq_info; - struct pci_dev *host_pci_dev; - int status = 0; - struct pcibus_bussoft *bs; - - dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); - if (SN_PCIDEV_INFO(dev) <= 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) - BUG(); /* Cannot afford to run out of memory */ - memset(sn_irq_info, 0, sizeof(struct sn_irq_info)); - - /* 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(sn_irq_info)); - if (status) - BUG(); /* Cannot get platform pci device information information */ + s64 pci_addrs[PCI_ROM_RESOURCE + 1]; + unsigned long addr, end, size, start; /* 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; @@ -273,199 +210,106 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) dev->resource[idx].parent = &ioport_resource; else dev->resource[idx].parent = &iomem_resource; + /* If ROM, mark as shadowed in PROM */ + if (idx == PCI_ROM_RESOURCE) + dev->resource[idx].flags |= IORESOURCE_ROM_BIOS_COPY; } - - /* set up host bus linkages */ - bs = SN_PCIBUS_BUSSOFT(dev->bus); - host_pci_dev = - pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32, - SN_PCIDEV_INFO(dev)-> - pdi_slot_host_handle & 0xffffffff); - SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = - SN_PCIDEV_INFO(host_pci_dev); - SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; - SN_PCIDEV_INFO(dev)->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]; - } else { - SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider; - } - - /* 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; - sn_irq_fixup(dev, sn_irq_info); - } + /* Create a pci_window in the pci_controller struct for + * each device resource. + */ + if (count > 0) + sn_pci_window_fixup(dev, count, pci_addrs); } /* * sn_pci_controller_fixup() - This routine sets up a bus's resources - * consistent with the Linux PCI abstraction layer. + * consistent with the Linux PCI abstraction layer. */ -static void sn_pci_controller_fixup(int segment, int busnum) +static void +sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) { - int status = 0; - int nasid, cnode; - struct pci_bus *bus; + s64 status = 0; struct pci_controller *controller; struct pcibus_bussoft *prom_bussoft_ptr; - struct hubdev_info *hubdev_info; - void *provider_soft; - struct sn_pcibus_provider *provider; - - status = - sal_get_pcibus_info((u64) segment, (u64) busnum, - (u64) ia64_tpa(&prom_bussoft_ptr)); - if (status > 0) { - return; /* bus # does not exist */ - } + + status = sal_get_pcibus_info((u64) segment, (u64) busnum, + (u64) ia64_tpa(&prom_bussoft_ptr)); + if (status > 0) + return; /*bus # does not exist */ prom_bussoft_ptr = __va(prom_bussoft_ptr); - controller = sn_alloc_pci_sysdata(); - /* controller non-zero is BUG'd in sn_alloc_pci_sysdata */ - bus = pci_scan_bus(busnum, &pci_root_ops, controller); - if (bus == NULL) { - return; /* error, or bus already scanned */ - } + controller = kzalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) + BUG(); + controller->segment = segment; /* - * Per-provider fixup. Copies the contents from prom to local - * area and links SN_PCIBUS_BUSSOFT(). + * Temporarily save the prom_bussoft_ptr for use by sn_bus_fixup(). + * (platform_data will be overwritten later in sn_common_bus_fixup()) */ + controller->platform_data = prom_bussoft_ptr; - if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) { - return; /* unsupported asic type */ - } - - provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; - if (provider == NULL) { - return; /* no provider registerd for this asic */ - } - - provider_soft = NULL; - if (provider->bus_fixup) { - provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr); - } + bus = pci_scan_bus(busnum, &pci_root_ops, controller); + if (bus == NULL) + goto error_return; /* error, or bus already scanned */ - if (provider_soft == NULL) { - return; /* fixup failed or not applicable */ - } + bus->sysdata = controller; - /* - * Generic bus fixup goes here. Don't reference prom_bussoft_ptr - * after this point. - */ + return; - bus->sysdata = controller; - PCI_CONTROLLER(bus)->platform_data = provider_soft; +error_return: - nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); - cnode = nasid_to_cnodeid(nasid); - hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); - SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = - &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]); + kfree(controller); + return; } /* - * Ugly hack to get PCI setup until we have a proper ACPI namespace. + * sn_bus_fixup */ - -#define PCI_BUSES_TO_SCAN 256 - -static int __init sn_pci_init(void) +void +sn_bus_fixup(struct pci_bus *bus) { - int i = 0; struct pci_dev *pci_dev = NULL; - extern void sn_init_cpei_timer(void); -#ifdef CONFIG_PROC_FS - extern void register_sn_procfs(void); -#endif - - if (!ia64_platform_is("sn2") || IS_RUNNING_ON_SIMULATOR()) - return 0; - - /* - * prime sn_pci_provider[]. Individial provider init routines will - * override their respective default entries. - */ - - for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++) - sn_pci_provider[i] = &sn_pci_default_provider; - - pcibr_init_provider(); - tioca_init_provider(); - - /* - * This is needed to avoid bounce limit checks in the blk layer - */ - ia64_max_iommu_merge_mask = ~PAGE_MASK; - sn_fixup_ionodes(); - sn_irq = kmalloc(sizeof(struct sn_irq_info *) * NR_IRQS, GFP_KERNEL); - if (sn_irq <= 0) - BUG(); /* Canno afford to run out of memory. */ - memset(sn_irq, 0, sizeof(struct sn_irq_info *) * NR_IRQS); - - sn_init_cpei_timer(); - -#ifdef CONFIG_PROC_FS - register_sn_procfs(); -#endif - - for (i = 0; i < PCI_BUSES_TO_SCAN; i++) { - sn_pci_controller_fixup(0, i); - } - - /* - * Generic Linux PCI Layer has created the pci_bus and pci_dev - * structures - time for us to add our SN PLatform specific - * information. - */ - - while ((pci_dev = - pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { - sn_pci_fixup_slot(pci_dev); - } - - sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */ + struct pcibus_bussoft *prom_bussoft_ptr; + extern void sn_common_bus_fixup(struct pci_bus *, + struct pcibus_bussoft *); + + + if (!bus->parent) { /* If root bus */ + prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data; + if (prom_bussoft_ptr == NULL) { + printk(KERN_ERR + "sn_bus_fixup: 0x%04x:0x%02x Unable to " + "obtain prom_bussoft_ptr\n", + pci_domain_nr(bus), bus->number); + return; + } + sn_common_bus_fixup(bus, prom_bussoft_ptr); + sn_legacy_pci_window_fixup(PCI_CONTROLLER(bus), + prom_bussoft_ptr->bs_legacy_io, + prom_bussoft_ptr->bs_legacy_mem); + } + list_for_each_entry(pci_dev, &bus->devices, bus_list) { + sn_pci_fixup_slot(pci_dev); + } - return 0; } /* - * hubdev_init_node() - Creates the HUB data structure and link them to it's - * own NODE specific data area. + * sn_io_init - PROM does not have ACPI support to define nodes or root buses, + * so we need to do things the hard way, including initiating the + * bus scanning ourselves. */ -void hubdev_init_node(nodepda_t * npda, cnodeid_t node) -{ - struct hubdev_info *hubdev_info; - - if (node >= num_online_nodes()) /* Headless/memless IO nodes */ - hubdev_info = - (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(0), - sizeof(struct - hubdev_info)); - else - hubdev_info = - (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(node), - sizeof(struct - hubdev_info)); - npda->pdinfo = (void *)hubdev_info; - -} - -geoid_t -cnodeid_get_geoid(cnodeid_t cnode) +void __init sn_io_init(void) { + int i, j; - struct hubdev_info *hubdev; - - hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); - return hubdev->hdi_geoid; + sn_fixup_ionodes(); + /* busses are not known yet ... */ + for (i = 0; i <= max_segment_number; i++) + for (j = 0; j <= max_pcibus_number; j++) + sn_pci_controller_fixup(i, j, NULL); } - -subsys_initcall(sn_pci_init);