pci_bus_cvlink.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 907 行 · 第 1/2 页

C
907
字号
/* * 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;		}		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;		}		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;                        if (dev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_MEM)                                cmd |= PCI_COMMAND_MEMORY;                }        }	/*	 * 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){	struct sn_device_sysdata *device_sysdata;	vertex_hdl_t vhdl;	pciio_intr_t intr_handle;	unsigned int irq;	unsigned long size;	int idx;	device_sysdata = SN_DEVICE_SYSDATA(dev);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?