pci_bus_cvlink.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 923 行 · 第 1/2 页
C
923 行
/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */#include <linux/vmalloc.h>#include <linux/slab.h>#include <asm/sn/sgi.h>#include <asm/sn/pci/pci_bus_cvlink.h>#include <asm/sn/sn_cpuid.h>#include <asm/sn/simulator.h>extern int bridge_rev_b_data_check_disable;vertex_hdl_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET];nasid_t busnum_to_nid[MAX_PCI_XWIDGET];void * busnum_to_atedmamaps[MAX_PCI_XWIDGET];unsigned char num_bridges;static int done_probing;extern irqpda_t *irqpdaindr;static int pci_bus_map_create(struct pcibr_list_s *softlistp, moduleid_t io_moduleid);vertex_hdl_t devfn_to_vertex(unsigned char busnum, unsigned int devfn);extern void register_pcibr_intr(int irq, pcibr_intr_t intr);static struct sn_flush_device_list *sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot);extern int cbrick_type_get_nasid(nasid_t);extern void ioconfig_bus_new_entries(void);extern void ioconfig_get_busnum(char *, int *);extern int iomoduleid_get(nasid_t);extern int pcibr_widget_to_bus(vertex_hdl_t);extern int isIO9(int);#define IS_OPUS(nasid) (cbrick_type_get_nasid(nasid) == MODULE_OPUSBRICK)#define IS_ALTIX(nasid) (cbrick_type_get_nasid(nasid) == MODULE_CBRICK)/* * Init the provider asic for a given device */static inline void __initset_pci_provider(struct sn_device_sysdata *device_sysdata){ pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); device_sysdata->pci_provider = pciio_info_pops_get(pciio_info);}/* * pci_bus_cvlink_init() - To be called once during initialization before * SGI IO Infrastructure init is called. */intpci_bus_cvlink_init(void){ extern int ioconfig_bus_init(void); memset(busnum_to_pcibr_vhdl, 0x0, sizeof(vertex_hdl_t) * MAX_PCI_XWIDGET); memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); num_bridges = 0; return ioconfig_bus_init();}/* * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated * pci bus vertex from the SGI IO Infrastructure. */static inline vertex_hdl_tpci_bus_to_vertex(unsigned char busnum){ vertex_hdl_t pci_bus = NULL; /* * First get the xwidget vertex. */ pci_bus = busnum_to_pcibr_vhdl[busnum]; return(pci_bus);}/* * devfn_to_vertex() - returns the vertex of the device given the bus, slot, * and function numbers. */vertex_hdl_tdevfn_to_vertex(unsigned char busnum, unsigned int devfn){ int slot = 0; int func = 0; char name[16]; vertex_hdl_t pci_bus = NULL; vertex_hdl_t device_vertex = (vertex_hdl_t)NULL; /* * Go get the pci bus vertex. */ pci_bus = pci_bus_to_vertex(busnum); if (!pci_bus) { /* * During probing, the Linux pci code invents non-existent * bus numbers and pci_dev structures and tries to access * them to determine existence. Don't crib during probing. */ if (done_probing) printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); return(NULL); } /* * Go get the slot&function vertex. * Should call pciio_slot_func_to_name() when ready. */ slot = PCI_SLOT(devfn); func = PCI_FUNC(devfn); /* * For a NON Multi-function card the name of the device looks like: * ../pci/1, ../pci/2 .. */ if (func == 0) { sprintf(name, "%d", slot); if (hwgraph_traverse(pci_bus, name, &device_vertex) == GRAPH_SUCCESS) { if (device_vertex) { return(device_vertex); } } } /* * This maybe a multifunction card. It's names look like: * ../pci/1a, ../pci/1b, etc. */ sprintf(name, "%d%c", slot, 'a'+func); if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { if (!device_vertex) { return(NULL); } } return(device_vertex);}/* * 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. */static struct pci_controller *sn_alloc_pci_sysdata(void){ struct pci_controller *pci_sysdata; pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL); if (!pci_sysdata) return NULL; memset(pci_sysdata, 0, sizeof(*pci_sysdata)); return pci_sysdata;}/* * sn_pci_fixup_bus() - This routine sets up a bus's resources * consistent with the Linux PCI abstraction layer. */static int __initsn_pci_fixup_bus(struct pci_bus *bus){ struct pci_controller *pci_sysdata; struct sn_widget_sysdata *widget_sysdata; pci_sysdata = sn_alloc_pci_sysdata(); if (!pci_sysdata) { printk(KERN_WARNING "sn_pci_fixup_bus(): Unable to " "allocate memory for pci_sysdata\n"); return -ENOMEM; } widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), GFP_KERNEL); if (!widget_sysdata) { printk(KERN_WARNING "sn_pci_fixup_bus(): Unable to " "allocate memory for widget_sysdata\n"); kfree(pci_sysdata); return -ENOMEM; } widget_sysdata->vhdl = pci_bus_to_vertex(bus->number); pci_sysdata->platform_data = (void *)widget_sysdata; bus->sysdata = pci_sysdata; return 0;}/* * 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. */static intsn_pci_fixup_slot(struct pci_dev *dev){ extern int bit_pos_to_irq(int); unsigned int irq; int idx; u16 cmd; vertex_hdl_t vhdl; unsigned long size; struct pci_controller *pci_sysdata; struct sn_device_sysdata *device_sysdata; pciio_intr_line_t lines = 0; vertex_hdl_t device_vertex; pciio_provider_t *pci_provider; pciio_intr_t intr_handle; /* Allocate a controller structure */ pci_sysdata = sn_alloc_pci_sysdata(); if (!pci_sysdata) { printk(KERN_WARNING "sn_pci_fixup_slot: Unable to " "allocate memory for pci_sysdata\n"); return -ENOMEM; } /* Set the device vertex */ device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), GFP_KERNEL); if (!device_sysdata) { printk(KERN_WARNING "sn_pci_fixup_slot: Unable to " "allocate memory for device_sysdata\n"); kfree(pci_sysdata); return -ENOMEM; } device_sysdata->vhdl = devfn_to_vertex(dev->bus->number, dev->devfn); pci_sysdata->platform_data = (void *) device_sysdata; dev->sysdata = pci_sysdata; set_pci_provider(device_sysdata); pci_read_config_word(dev, PCI_COMMAND, &cmd); /* * Set the resources address correctly. The assumption here * is that the addresses in the resource structure has been * read from the card and it was set in the card by our * Infrastructure. NOTE: PIC and TIOCP don't have big-window * upport for PCI I/O space. So by mapping the I/O space * first we will attempt to use Device(x) registers for I/O * BARs (which can't use big windows like MEM BARs can). */ vhdl = device_sysdata->vhdl; /* Allocate the IORESOURCE_IO space first */ for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { unsigned long start, end, addr; device_sysdata->pio_map[idx] = NULL; if (!(dev->resource[idx].flags & IORESOURCE_IO)) continue; start = dev->resource[idx].start; end = dev->resource[idx].end; size = end - start; if (!size) continue; addr = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, &device_sysdata->pio_map[idx], 0); if (!addr) { dev->resource[idx].start = 0; dev->resource[idx].end = 0; printk("sn_pci_fixup(): pio map failure for " "%s bar%d\n", dev->slot_name, idx); } else { addr |= __IA64_UNCACHED_OFFSET; dev->resource[idx].start = addr; dev->resource[idx].end = addr + size; dev->resource[idx].parent = &ioport_resource; } if (dev->resource[idx].flags & IORESOURCE_IO) cmd |= PCI_COMMAND_IO; } /* Allocate the IORESOURCE_MEM space next */ for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { unsigned long start, end, addr; if ((dev->resource[idx].flags & IORESOURCE_IO)) continue; start = dev->resource[idx].start; end = dev->resource[idx].end; size = end - start; if (!size) continue; addr = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, &device_sysdata->pio_map[idx], 0); if (!addr) { dev->resource[idx].start = 0; dev->resource[idx].end = 0; printk("sn_pci_fixup(): pio map failure for " "%s bar%d\n", dev->slot_name, idx); } else { addr |= __IA64_UNCACHED_OFFSET; dev->resource[idx].start = addr; dev->resource[idx].end = addr + size; dev->resource[idx].parent = &iomem_resource; } if (dev->resource[idx].flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } /* * Assign addresses to the ROMs, but don't enable them yet * Also note that we only map display card ROMs due to PIO mapping * space scarcity. */ if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { unsigned long addr; size = dev->resource[PCI_ROM_RESOURCE].end - dev->resource[PCI_ROM_RESOURCE].start; if (size) { addr = (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, size, 0, PIOMAP_FIXED); if (!addr) { dev->resource[PCI_ROM_RESOURCE].start = 0; dev->resource[PCI_ROM_RESOURCE].end = 0; printk("sn_pci_fixup(): ROM pio map failure " "for %s\n", dev->slot_name); } addr |= __IA64_UNCACHED_OFFSET; dev->resource[PCI_ROM_RESOURCE].start = addr; dev->resource[PCI_ROM_RESOURCE].end = addr + size; dev->resource[idx].parent = &iomem_resource; if (dev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } } else { /* * Remove other ROM resources since they don't have valid * CPU addresses. */ size = dev->resource[PCI_ROM_RESOURCE].end - dev->resource[PCI_ROM_RESOURCE].start; if (size) { dev->resource[PCI_ROM_RESOURCE].start = 0; dev->resource[PCI_ROM_RESOURCE].end = 0; dev->resource[PCI_ROM_RESOURCE].flags = 0; } } /* * Update the Command Word on the Card. */ cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ /* bit gets dropped .. no harm */ pci_write_config_word(dev, PCI_COMMAND, cmd); pci_read_config_byte(dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); device_vertex = device_sysdata->vhdl; pci_provider = device_sysdata->pci_provider; device_sysdata->intr_handle = NULL; if (!lines) return 0; irqpdaindr->curr = dev; intr_handle = (pci_provider->intr_alloc)(device_vertex, NULL, lines, device_vertex); if (intr_handle == NULL) { printk(KERN_WARNING "sn_pci_fixup: pcibr_intr_alloc() failed\n"); kfree(pci_sysdata); kfree(device_sysdata); return -ENOMEM; } device_sysdata->intr_handle = intr_handle; irq = intr_handle->pi_irq; irqpdaindr->device_dev[irq] = dev; (pci_provider->intr_connect)(intr_handle, (intr_func_t)0, (intr_arg_t)0); dev->irq = irq; register_pcibr_intr(irq, (pcibr_intr_t)intr_handle); for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { int ibits = ((pcibr_intr_t)intr_handle)->bi_ibits; int i; size = dev->resource[idx].end - dev->resource[idx].start; if (size == 0) continue; for (i=0; i<8; i++) { if (ibits & (1 << i) ) { extern pcibr_info_t pcibr_info_get(vertex_hdl_t); device_sysdata->dma_flush_list = sn_dma_flush_init(dev->resource[idx].start, dev->resource[idx].end, idx, i, PCIBR_INFO_SLOT_GET_EXT(pcibr_info_get(device_sysdata->vhdl))); } } } return 0;}#ifdef CONFIG_HOTPLUG_PCI_SGIvoidsn_dma_flush_clear(struct sn_flush_device_list *dma_flush_list, unsigned long start, unsigned long end){ int i; dma_flush_list->pin = -1; dma_flush_list->bus = -1; dma_flush_list->slot = -1; for (i = 0; i < PCI_ROM_RESOURCE; i++) if ((dma_flush_list->bar_list[i].start == start) && (dma_flush_list->bar_list[i].end == end)) { dma_flush_list->bar_list[i].start = 0; dma_flush_list->bar_list[i].end = 0; break; } }/* * sn_pci_unfixup_slot() - This routine frees a slot's resources * consistent with the Linux PCI abstraction layer. Resources released * back to our PCI provider include PIO maps to BAR space and interrupt * objects. */voidsn_pci_unfixup_slot(struct pci_dev *dev){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?