⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pciio.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id$ * * 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/init.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/pci_ids.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/slab.h>#include <asm/sn/sgi.h>#include <asm/sn/xtalk/xbow.h>	/* Must be before iograph.h to get MAX_PORT_NUM */#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/hcl_util.h>#include <asm/sn/labelcl.h>#include <asm/sn/pci/bridge.h>#include <asm/sn/ioerror_handling.h>#include <asm/sn/pci/pciio.h>#include <asm/sn/pci/pciio_private.h>#include <asm/sn/sn_sal.h>#include <asm/sn/io.h>#include <asm/sn/pci/pci_bus_cvlink.h>#include <asm/sn/simulator.h>#define DEBUG_PCIIO#undef DEBUG_PCIIO	/* turn this on for yet more console output */char                    pciio_info_fingerprint[] = "pciio_info";/* ===================================================================== *    PCI Generic Bus Provider * Implement PCI provider operations.  The pciio* layer provides a * platform-independent interface for PCI devices.  This layer * switches among the possible implementations of a PCI adapter. *//* ===================================================================== *    Provider Function Location SHORTCUT * * On platforms with only one possible PCI provider, macros can be * set up at the top that cause the table lookups and indirections to * completely disappear. *//* ===================================================================== *    Function Table of Contents */#if !defined(DEV_FUNC)extern pciio_provider_t *pciio_to_provider_fns(vertex_hdl_t dev);#endif/* ===================================================================== *    Provider Function Location * *      If there is more than one possible provider for *      this platform, we need to examine the master *      vertex of the current vertex for a provider *      function structure, and indirect through the *      appropriately named member. */#if !defined(DEV_FUNC)pciio_provider_t *pciio_to_provider_fns(vertex_hdl_t dev){    pciio_info_t            card_info;    pciio_provider_t       *provider_fns;    /*     * We're called with two types of vertices, one is     * the bridge vertex (ends with "pci") and the other is the     * pci slot vertex (ends with "pci/[0-8]").  For the first type     * we need to get the provider from the PFUNCS label.  For     * the second we get it from fastinfo/c_pops.     */    provider_fns = pciio_provider_fns_get(dev);    if (provider_fns == NULL) {	card_info = pciio_info_get(dev);	if (card_info != NULL) {		provider_fns = pciio_info_pops_get(card_info);	}    }    if (provider_fns == NULL) {	char devname[MAXDEVNAME];	panic("%s: provider_fns == NULL", vertex_to_name(dev, devname, MAXDEVNAME));    }    return provider_fns;}#define DEV_FUNC(dev,func)	pciio_to_provider_fns(dev)->func#define CAST_PIOMAP(x)		((pciio_piomap_t)(x))#define CAST_DMAMAP(x)		((pciio_dmamap_t)(x))#define CAST_INTR(x)		((pciio_intr_t)(x))#endif/* * Many functions are not passed their vertex * information directly; rather, they must * dive through a resource map. These macros * are available to coordinate this detail. */#define PIOMAP_FUNC(map,func)		DEV_FUNC((map)->pp_dev,func)#define DMAMAP_FUNC(map,func)		DEV_FUNC((map)->pd_dev,func)#define INTR_FUNC(intr_hdl,func)	DEV_FUNC((intr_hdl)->pi_dev,func)/* ===================================================================== *          PIO MANAGEMENT * *      For mapping system virtual address space to *      pciio space on a specified card */pciio_piomap_tpciio_piomap_alloc(vertex_hdl_t dev,	/* set up mapping for this device */		   device_desc_t dev_desc,	/* device descriptor */		   pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */		   iopaddr_t addr,	/* lowest address (or offset in window) */		   size_t byte_count,	/* size of region containing our mappings */		   size_t byte_count_max,	/* maximum size of a mapping */		   unsigned flags){					/* defined in sys/pio.h */    return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc)	(dev, dev_desc, space, addr, byte_count, byte_count_max, flags);}voidpciio_piomap_free(pciio_piomap_t pciio_piomap){    PIOMAP_FUNC(pciio_piomap, piomap_free)	(CAST_PIOMAP(pciio_piomap));}caddr_tpciio_piomap_addr(pciio_piomap_t pciio_piomap,	/* mapping resources */		  iopaddr_t pciio_addr,	/* map for this pciio address */		  size_t byte_count){					/* map this many bytes */    pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr)	(CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count);    return pciio_piomap->pp_kvaddr;}voidpciio_piomap_done(pciio_piomap_t pciio_piomap){    PIOMAP_FUNC(pciio_piomap, piomap_done)	(CAST_PIOMAP(pciio_piomap));}caddr_tpciio_piotrans_addr(vertex_hdl_t dev,	/* translate for this device */		    device_desc_t dev_desc,	/* device descriptor */		    pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */		    iopaddr_t addr,	/* starting address (or offset in window) */		    size_t byte_count,	/* map this many bytes */		    unsigned flags){					/* (currently unused) */    return DEV_FUNC(dev, piotrans_addr)	(dev, dev_desc, space, addr, byte_count, flags);}caddr_tpciio_pio_addr(vertex_hdl_t dev,	/* translate for this device */	       device_desc_t dev_desc,	/* device descriptor */	       pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */	       iopaddr_t addr,		/* starting address (or offset in window) */	       size_t byte_count,	/* map this many bytes */	       pciio_piomap_t *mapp,	/* where to return the map pointer */	       unsigned flags){					/* PIO flags */    pciio_piomap_t          map = 0;    int			    errfree = 0;    caddr_t                 res;    if (mapp) {	map = *mapp;			/* possible pre-allocated map */	*mapp = 0;			/* record "no map used" */    }    res = pciio_piotrans_addr	(dev, dev_desc, space, addr, byte_count, flags);    if (res)	return res;			/* pciio_piotrans worked */    if (!map) {	map = pciio_piomap_alloc	    (dev, dev_desc, space, addr, byte_count, byte_count, flags);	if (!map)	    return res;			/* pciio_piomap_alloc failed */	errfree = 1;    }    res = pciio_piomap_addr	(map, addr, byte_count);    if (!res) {	if (errfree)	    pciio_piomap_free(map);	return res;			/* pciio_piomap_addr failed */    }    if (mapp)	*mapp = map;			/* pass back map used */    return res;				/* pciio_piomap_addr succeeded */}iopaddr_tpciio_piospace_alloc(vertex_hdl_t dev,	/* Device requiring space */		     device_desc_t dev_desc,	/* Device descriptor */		     pciio_space_t space,	/* MEM32/MEM64/IO */		     size_t byte_count,	/* Size of mapping */		     size_t align){					/* Alignment needed */    if (align < PAGE_SIZE)	align = PAGE_SIZE;    return DEV_FUNC(dev, piospace_alloc)	(dev, dev_desc, space, byte_count, align);}voidpciio_piospace_free(vertex_hdl_t dev,	/* Device freeing space */		    pciio_space_t space,	/* Type of space        */		    iopaddr_t pciaddr,	/* starting address */		    size_t byte_count){					/* Range of address   */    DEV_FUNC(dev, piospace_free)	(dev, space, pciaddr, byte_count);}/* ===================================================================== *          DMA MANAGEMENT * *      For mapping from pci space to system *      physical space. */pciio_dmamap_tpciio_dmamap_alloc(vertex_hdl_t dev,	/* set up mappings for this device */		   device_desc_t dev_desc,	/* device descriptor */		   size_t byte_count_max,	/* max size of a mapping */		   unsigned flags){					/* defined in dma.h */    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)	(dev, dev_desc, byte_count_max, flags);}voidpciio_dmamap_free(pciio_dmamap_t pciio_dmamap){    DMAMAP_FUNC(pciio_dmamap, dmamap_free)	(CAST_DMAMAP(pciio_dmamap));}iopaddr_tpciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */		  paddr_t paddr,	/* map for this address */		  size_t byte_count){					/* map this many bytes */    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)	(CAST_DMAMAP(pciio_dmamap), paddr, byte_count);}voidpciio_dmamap_done(pciio_dmamap_t pciio_dmamap){    DMAMAP_FUNC(pciio_dmamap, dmamap_done)	(CAST_DMAMAP(pciio_dmamap));}iopaddr_tpciio_dmatrans_addr(vertex_hdl_t dev,	/* translate for this device */		    device_desc_t dev_desc,	/* device descriptor */		    paddr_t paddr,	/* system physical address */		    size_t byte_count,	/* length */		    unsigned flags){					/* defined in dma.h */    return DEV_FUNC(dev, dmatrans_addr)	(dev, dev_desc, paddr, byte_count, flags);}iopaddr_tpciio_dma_addr(vertex_hdl_t dev,	/* translate for this device */	       device_desc_t dev_desc,	/* device descriptor */	       paddr_t paddr,		/* system physical address */	       size_t byte_count,	/* length */	       pciio_dmamap_t *mapp,	/* map to use, then map we used */	       unsigned flags){					/* PIO flags */    pciio_dmamap_t          map = 0;    int			    errfree = 0;    iopaddr_t               res;    if (mapp) {	map = *mapp;			/* possible pre-allocated map */	*mapp = 0;			/* record "no map used" */    }    res = pciio_dmatrans_addr	(dev, dev_desc, paddr, byte_count, flags);    if (res)	return res;			/* pciio_dmatrans worked */    if (!map) {	map = pciio_dmamap_alloc	    (dev, dev_desc, byte_count, flags);	if (!map)	    return res;			/* pciio_dmamap_alloc failed */	errfree = 1;    }    res = pciio_dmamap_addr	(map, paddr, byte_count);    if (!res) {	if (errfree)	    pciio_dmamap_free(map);	return res;			/* pciio_dmamap_addr failed */    }    if (mapp)	*mapp = map;			/* pass back map used */    return res;				/* pciio_dmamap_addr succeeded */}voidpciio_dmamap_drain(pciio_dmamap_t map){    DMAMAP_FUNC(map, dmamap_drain)	(CAST_DMAMAP(map));}voidpciio_dmaaddr_drain(vertex_hdl_t dev, paddr_t addr, size_t size){    DEV_FUNC(dev, dmaaddr_drain)	(dev, addr, size);}voidpciio_dmalist_drain(vertex_hdl_t dev, alenlist_t list){    DEV_FUNC(dev, dmalist_drain)	(dev, list);}/* ===================================================================== *          INTERRUPT MANAGEMENT * *      Allow crosstalk devices to establish interrupts *//* * Allocate resources required for an interrupt as specified in intr_desc. * Return resource handle in intr_hdl. */pciio_intr_tpciio_intr_alloc(vertex_hdl_t dev,	/* which Crosstalk device */		 device_desc_t dev_desc,	/* device descriptor */		 pciio_intr_line_t lines,	/* INTR line(s) to attach */		 vertex_hdl_t owner_dev){					/* owner of this interrupt */    return (pciio_intr_t) DEV_FUNC(dev, intr_alloc)	(dev, dev_desc, lines, owner_dev);}/* * Free resources consumed by intr_alloc. */voidpciio_intr_free(pciio_intr_t intr_hdl){    INTR_FUNC(intr_hdl, intr_free)	(CAST_INTR(intr_hdl));}/* * Associate resources allocated with a previous pciio_intr_alloc call with the * described handler, arg, name, etc. * * Returns 0 on success, returns <0 on failure. */intpciio_intr_connect(pciio_intr_t intr_hdl,		intr_func_t intr_func, intr_arg_t intr_arg)	/* pciio intr resource handle */{    return INTR_FUNC(intr_hdl, intr_connect)	(CAST_INTR(intr_hdl), intr_func, intr_arg);}/* * Disassociate handler with the specified interrupt. */voidpciio_intr_disconnect(pciio_intr_t intr_hdl){    INTR_FUNC(intr_hdl, intr_disconnect)	(CAST_INTR(intr_hdl));}/* * Return a hwgraph vertex that represents the CPU currently * targeted by an interrupt. */vertex_hdl_tpciio_intr_cpu_get(pciio_intr_t intr_hdl){    return INTR_FUNC(intr_hdl, intr_cpu_get)	(CAST_INTR(intr_hdl));}voidpciio_slot_func_to_name(char		       *name,			pciio_slot_t		slot,			pciio_function_t	func){    /*     * standard connection points:     *     * PCIIO_SLOT_NONE:	.../pci/direct     * PCIIO_FUNC_NONE: .../pci/<SLOT>			ie. .../pci/3     * multifunction:   .../pci/<SLOT><FUNC>		ie. .../pci/3c     */    if (slot == PCIIO_SLOT_NONE)	sprintf(name, EDGE_LBL_DIRECT);    else if (func == PCIIO_FUNC_NONE)	sprintf(name, "%d", slot);    else	sprintf(name, "%d%c", slot, 'a'+func);}/* * pciio_cardinfo_get * * Get the pciio info structure corresponding to the * specified PCI "slot" (we like it when the same index * number is used for the PCI IDSEL, the REQ/GNT pair, * and the interrupt line being used for INTA. We like * it so much we call it the slot number). */static pciio_info_tpciio_cardinfo_get(		      vertex_hdl_t pciio_vhdl,		      pciio_slot_t pci_slot){    char                    namebuf[16];    pciio_info_t	    info = 0;    vertex_hdl_t	    conn;    pciio_slot_func_to_name(namebuf, pci_slot, PCIIO_FUNC_NONE);    if (GRAPH_SUCCESS ==	hwgraph_traverse(pciio_vhdl, namebuf, &conn)) {	info = pciio_info_chk(conn);	hwgraph_vertex_unref(conn);    }    return info;}/* * pciio_error_handler: * dispatch an error to the appropriate * pciio connection point, or process * it as a generic pci error. * Yes, the first parameter is the * provider vertex at the middle of * the bus; we get to the pciio connect * point using the ioerror widgetdev field. * * This function is called by the * specific PCI provider, after it has figured * out where on the PCI bus (including which slot, * if it can tell) the error came from. *//*ARGSUSED */intpciio_error_handler(		       vertex_hdl_t pciio_vhdl,		       int error_code,		       ioerror_mode_t mode,		       ioerror_t *ioerror){    pciio_info_t            pciio_info;    vertex_hdl_t            pconn_vhdl;    pciio_slot_t            slot;    int                     retval;#if DEBUG && ERROR_DEBUG    printk("%v: pciio_error_handler\n", pciio_vhdl);#endif    IOERR_PRINTF(printk(KERN_NOTICE "%v: PCI Bus Error: Error code: %d Error mode: %d\n",			 pciio_vhdl, error_code, mode));    /* If there is an error handler sitting on     * the "no-slot" connection point, give it     * first crack at the error. NOTE: it is     * quite possible that this function may     * do further refining of the ioerror.     */    pciio_info = pciio_cardinfo_get(pciio_vhdl, PCIIO_SLOT_NONE);    if (pciio_info && pciio_info->c_efunc) {	pconn_vhdl = pciio_info_dev_get(pciio_info);	retval = pciio_info->c_efunc	    (pciio_info->c_einfo, error_code, mode, ioerror);	if (retval != IOERROR_UNHANDLED)	    return retval;    }    /* Is the error associated with a particular slot?     */    if (IOERROR_FIELDVALID(ioerror, widgetdev)) {	short widgetdev;	/*	 * NOTE : 	 * widgetdev is a 4byte value encoded as slot in the higher order	 * 2 bytes and function in the lower order 2 bytes.	 */	IOERROR_GETVALUE(widgetdev, ioerror, widgetdev);	slot = pciio_widgetdev_slot_get(widgetdev);	/* If this slot has an error handler,

⌨️ 快捷键说明

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