📄 pciio.c
字号:
/* $Id: pciio.c,v 1.1.1.1 2004/02/04 12:55:33 laputa Exp $ * * 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 Silicon Graphics, Inc. * Copyright (C) 2000 by Colin Ngam */#define USRPCI 0#include <linux/types.h>#include <linux/config.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>#define DEBUG_PCIIO#undef DEBUG_PCIIO /* turn this on for yet more console output */#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))#define DEL(ptr) (kfree(ptr))char pciio_info_fingerprint[] = "pciio_info";cdl_p pciio_registry = NULL;intbadaddr_val(volatile void *addr, int len, volatile void *ptr){ int ret = 0; volatile void *new_addr; switch (len) { case 4: new_addr = (void *)(((u64) addr)^4); ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); break; default: printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len); } if (ret < 0) panic("badaddr_val: unexpected status (%d) in probing", ret); return(ret);}nasid_tget_console_nasid(void){ extern nasid_t console_nasid; return console_nasid;}inthub_dma_enabled(devfs_handle_t xconn_vhdl){ return(0);}inthub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code){ return(0);}voidioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror){}/****** ****** end hack defines ...... ******//* ===================================================================== * 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. */#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC/* * For the moment, we will assume that IP27 * only use Bridge ASICs to provide PCI support. */#include <asm/sn/pci/pcibr.h>#define DEV_FUNC(dev,func) pcibr_##func#define CAST_PIOMAP(x) ((pcibr_piomap_t)(x))#define CAST_DMAMAP(x) ((pcibr_dmamap_t)(x))#define CAST_INTR(x) ((pcibr_intr_t)(x))#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 *//* ===================================================================== * Function Table of Contents */#if !defined(DEV_FUNC)static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev);#endifpciio_piomap_t pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);void pciio_piomap_free(pciio_piomap_t);caddr_t pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t);void pciio_piomap_done(pciio_piomap_t);caddr_t pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned);caddr_t pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned);iopaddr_t pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t);void pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t);pciio_dmamap_t pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);void pciio_dmamap_free(pciio_dmamap_t);iopaddr_t pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);alenlist_t pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned);void pciio_dmamap_done(pciio_dmamap_t);iopaddr_t pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);alenlist_t pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);void pciio_dmamap_drain(pciio_dmamap_t);void pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t);void pciio_dmalist_drain(devfs_handle_t, alenlist_t);iopaddr_t pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned);pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);void pciio_intr_free(pciio_intr_t);int pciio_intr_connect(pciio_intr_t, intr_func_t, intr_arg_t, void *thread);void pciio_intr_disconnect(pciio_intr_t);devfs_handle_t pciio_intr_cpu_get(pciio_intr_t);void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t);static pciio_info_t pciio_cardinfo_get(devfs_handle_t, pciio_slot_t);int pciio_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *);int pciio_error_devenable(devfs_handle_t, int);void pciio_provider_startup(devfs_handle_t);void pciio_provider_shutdown(devfs_handle_t);pciio_endian_t pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t);pciio_priority_t pciio_priority_set(devfs_handle_t, pciio_priority_t);devfs_handle_t pciio_intr_dev_get(pciio_intr_t);devfs_handle_t pciio_pio_dev_get(pciio_piomap_t);pciio_slot_t pciio_pio_slot_get(pciio_piomap_t);pciio_space_t pciio_pio_space_get(pciio_piomap_t);iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t);ulong pciio_pio_mapsz_get(pciio_piomap_t);caddr_t pciio_pio_kvaddr_get(pciio_piomap_t);devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t);pciio_slot_t pciio_dma_slot_get(pciio_dmamap_t);pciio_info_t pciio_info_chk(devfs_handle_t);pciio_info_t pciio_info_get(devfs_handle_t);void pciio_info_set(devfs_handle_t, pciio_info_t);devfs_handle_t pciio_info_dev_get(pciio_info_t);pciio_slot_t pciio_info_slot_get(pciio_info_t);pciio_function_t pciio_info_function_get(pciio_info_t);pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t);pciio_device_id_t pciio_info_device_id_get(pciio_info_t);devfs_handle_t pciio_info_master_get(pciio_info_t);arbitrary_info_t pciio_info_mfast_get(pciio_info_t);pciio_provider_t *pciio_info_pops_get(pciio_info_t);error_handler_f *pciio_info_efunc_get(pciio_info_t);error_handler_arg_t *pciio_info_einfo_get(pciio_info_t);pciio_space_t pciio_info_bar_space_get(pciio_info_t, int);iopaddr_t pciio_info_bar_base_get(pciio_info_t, int);size_t pciio_info_bar_size_get(pciio_info_t, int);iopaddr_t pciio_info_rom_base_get(pciio_info_t);size_t pciio_info_rom_size_get(pciio_info_t);void pciio_init(void);int pciio_attach(devfs_handle_t);void pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns);void pciio_provider_unregister(devfs_handle_t);pciio_provider_t *pciio_provider_fns_get(devfs_handle_t);int pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned);void pciio_driver_unregister(char *driver_prefix);devfs_handle_t pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);void pciio_device_unregister(devfs_handle_t);pciio_info_t pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);void pciio_device_info_free(pciio_info_t);devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t);void pciio_device_info_unregister(devfs_handle_t, pciio_info_t);int pciio_device_attach(devfs_handle_t, int);int pciio_device_detach(devfs_handle_t, int);void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t);int pciio_reset(devfs_handle_t);int pciio_write_gather_flush(devfs_handle_t);int pciio_slot_inuse(devfs_handle_t);/* ===================================================================== * 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)static pciio_provider_t *pciio_to_provider_fns(devfs_handle_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)#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_PANIC("%v: provider_fns == NULL", dev);#else PRINT_PANIC("0x%x: provider_fns == NULL", dev);#endif 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(devfs_handle_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(devfs_handle_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(devfs_handle_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(devfs_handle_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 < NBPP) align = NBPP; return DEV_FUNC(dev, piospace_alloc) (dev, dev_desc, space, byte_count, align);}voidpciio_piospace_free(devfs_handle_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(devfs_handle_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);}alenlist_tpciio_dmamap_list(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ alenlist_t alenlist, /* map this Address/Length List */ unsigned flags){ return DMAMAP_FUNC(pciio_dmamap, dmamap_list) (CAST_DMAMAP(pciio_dmamap), alenlist, flags);}voidpciio_dmamap_done(pciio_dmamap_t pciio_dmamap){ DMAMAP_FUNC(pciio_dmamap, dmamap_done) (CAST_DMAMAP(pciio_dmamap));}iopaddr_tpciio_dmatrans_addr(devfs_handle_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);}alenlist_tpciio_dmatrans_list(devfs_handle_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system address/length list */ unsigned flags){ /* defined in dma.h */ return DEV_FUNC(dev, dmatrans_list) (dev, dev_desc, palenlist, flags);}iopaddr_tpciio_dma_addr(devfs_handle_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(devfs_handle_t dev, paddr_t addr, size_t size){ DEV_FUNC(dev, dmaaddr_drain) (dev, addr, size);}voidpciio_dmalist_drain(devfs_handle_t dev, alenlist_t list){ DEV_FUNC(dev, dmalist_drain) (dev, list);}/* ===================================================================== * INTERRUPT MANAGEMENT *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -