📄 pciio.c
字号:
* 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(devfs_handle_t dev, /* which Crosstalk device */ device_desc_t dev_desc, /* device descriptor */ pciio_intr_line_t lines, /* INTR line(s) to attach */ devfs_handle_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, /* pciio intr resource handle */ intr_func_t intr_func, /* pciio intr handler */ intr_arg_t intr_arg, /* arg to intr handler */ void *thread){ /* intr thread to use */ return INTR_FUNC(intr_hdl, intr_connect) (CAST_INTR(intr_hdl), intr_func, intr_arg, thread);}/* * 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. */devfs_handle_tpciio_intr_cpu_get(pciio_intr_t intr_hdl){ return INTR_FUNC(intr_hdl, intr_cpu_get) (CAST_INTR(intr_hdl));}/* ===================================================================== * ERROR MANAGEMENT */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, "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( devfs_handle_t pciio_vhdl, pciio_slot_t pci_slot){ char namebuf[16]; pciio_info_t info = 0; devfs_handle_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( devfs_handle_t pciio_vhdl, int error_code, ioerror_mode_t mode, ioerror_t *ioerror){ pciio_info_t pciio_info; devfs_handle_t pconn_vhdl;#if USRPCI devfs_handle_t usrpci_v;#endif pciio_slot_t slot; int retval;#if defined(CONFIG_SGI_IO_ERROR_HANDLING) error_state_t e_state;#endif#if DEBUG && ERROR_DEBUG#if defined(SUPPORT_PRINTING_V_FORMAT) printk("%v: pciio_error_handler\n", pciio_vhdl);#else printk("0x%x: pciio_error_handler\n", pciio_vhdl);#endif#endif#if defined(SUPPORT_PRINTING_V_FORMAT) IOERR_PRINTF(printk("%v: PCI Bus Error: Error code: %d Error mode: %d\n", pciio_vhdl, error_code, mode));#else IOERR_PRINTF(printk("0x%x: PCI Bus Error: Error code: %d Error mode: %d\n", pciio_vhdl, error_code, mode));#endif /* 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);#if defined(CONFIG_SGI_IO_ERROR_HANDLING) e_state = error_state_get(pciio_vhdl); if (e_state == ERROR_STATE_ACTION) (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE) return(IOERROR_UNHANDLED);#endif 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)) { /* * NOTE : * widgetdev is a 4byte value encoded as slot in the higher order * 2 bytes and function in the lower order 2 bytes. */#ifdef LATER slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioerror, widgetdev));#else slot = 0;#endif /* If this slot has an error handler, * deliver the error to it. */ pciio_info = pciio_cardinfo_get(pciio_vhdl, slot); if (pciio_info != NULL) { if (pciio_info->c_efunc != NULL) { pconn_vhdl = pciio_info_dev_get(pciio_info);#if defined(CONFIG_SGI_IO_ERROR_HANDLING) e_state = error_state_get(pciio_vhdl); if (e_state == ERROR_STATE_ACTION) (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE) return(IOERROR_UNHANDLED);#endif retval = pciio_info->c_efunc (pciio_info->c_einfo, error_code, mode, ioerror); if (retval != IOERROR_UNHANDLED) return retval; }#if USRPCI /* If the USRPCI driver is available and * knows about this connection point, * deliver the error to it. * * OK to use pconn_vhdl here, even though we * have already UNREF'd it, since we know that * it is not going away. */ pconn_vhdl = pciio_info_dev_get(pciio_info); if (GRAPH_SUCCESS == hwgraph_traverse(pconn_vhdl, EDGE_LBL_USRPCI, &usrpci_v)) { retval = usrpci_error_handler (usrpci_v, error_code, IOERROR_GETVALUE(ioerror, busaddr)); hwgraph_vertex_unref(usrpci_v); if (retval != IOERROR_UNHANDLED) { /* * This unref is not needed. If this code is called often enough, * the system will crash, due to vertex reference count reaching 0, * causing vertex to be unallocated. -jeremy * hwgraph_vertex_unref(pconn_vhdl); */ return retval; } }#endif } } return (mode == MODE_DEVPROBE) ? IOERROR_HANDLED /* probes are OK */ : IOERROR_UNHANDLED; /* otherwise, foo! */}intpciio_error_devenable(devfs_handle_t pconn_vhdl, int error_code){ return DEV_FUNC(pconn_vhdl, error_devenable) (pconn_vhdl, error_code); /* no cleanup specific to this layer. */}/* ===================================================================== * CONFIGURATION MANAGEMENT *//* * Startup a crosstalk provider */voidpciio_provider_startup(devfs_handle_t pciio_provider){ DEV_FUNC(pciio_provider, provider_startup) (pciio_provider);}/* * Shutdown a crosstalk provider */voidpciio_provider_shutdown(devfs_handle_t pciio_provider){ DEV_FUNC(pciio_provider, provider_shutdown) (pciio_provider);}/* * Specify endianness constraints. The driver tells us what the device * does and how it would like to see things in memory. We reply with * how things will actually appear in memory. */pciio_endian_tpciio_endian_set(devfs_handle_t dev, pciio_endian_t device_end, pciio_endian_t desired_end){ ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE)); ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE));#if DEBUG#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_ALERT("%v: pciio_endian_set is going away.\n" "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", dev);#else PRINT_ALERT("0x%x: pciio_endian_set is going away.\n" "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", dev);#endif#endif return DEV_FUNC(dev, endian_set) (dev, device_end, desired_end);}/* * Specify PCI arbitration priority. */pciio_priority_tpciio_priority_set(devfs_handle_t dev, pciio_priority_t device_prio){ ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW)); return DEV_FUNC(dev, priority_set) (dev, device_prio);}/* * Read value of configuration register */uint64_tpciio_config_get(devfs_handle_t dev, unsigned reg, unsigned size){ uint64_t value = 0; unsigned shift = 0; /* handle accesses that cross words here, * since that's common code between all * possible providers. */ while (size > 0) { unsigned biw = 4 - (reg&3); if (biw > size) biw = size; value |= DEV_FUNC(dev, config_get) (dev, reg, biw) << shift; shift += 8*biw; reg += biw; size -= biw; } return value;}/* * Change value of configuration register */voidpciio_config_set(devfs_handle_t dev, unsigned reg, unsigned size, uint64_t value){ /* handle accesses that cross words here, * since that's common code between all * possible providers. */ while (size > 0) { unsigned biw = 4 - (reg&3); if (biw > size) biw = size; DEV_FUNC(dev, config_set) (dev, reg, biw, value); reg += biw; size -= biw; value >>= biw * 8; }}/* ===================================================================== * GENERIC PCI SUPPORT FUNCTIONS */pciio_slot_tpciio_error_extract(devfs_handle_t dev, pciio_space_t *space, iopaddr_t *offset){ ASSERT(dev != NODEV); return DEV_FUNC(dev,error_extract)(dev,space,offset);}/* * Issue a hardware reset to a card. */intpciio_reset(devfs_handle_t dev){ return DEV_FUNC(dev, reset) (dev);}/* * flush write gather buffers */intpciio_write_gather_flush(devfs_handle_t dev){ return DEV_FUNC(dev, write_gather_flush) (dev);}devfs_handle_tpciio_intr_dev_get(pciio_intr_t pciio_intr){ return (pciio_intr->pi_dev);}/****** Generic crosstalk pio interfaces ******/devfs_handle_tpciio_pio_dev_get(pciio_piomap_t pciio_piomap){ return (pciio_piomap->pp_dev);}pciio_slot_tpciio_pio_slot_get(pciio_piomap_t pciio_piomap){ return (pciio_piomap->pp_slot);}pciio_space_tpciio_pio_space_get(pciio_piomap_t pciio_piomap){ return (pciio_piomap->pp_space);}iopaddr_tpciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap){ return (pciio_piomap->pp_pciaddr);}ulongpciio_pio_mapsz_get(pciio_piomap_t pciio_piomap){ return (pciio_piomap->pp_mapsz);}caddr_tpciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap){ return (pciio_piomap->pp_kvaddr);}/****** Generic crosstalk dma interfaces ******/devfs_handle_tpciio_dma_dev_get(pciio_dmamap_t pciio_dmamap){ return (pciio_dmamap->pd_dev);}pciio_slot_tpciio_dma_slot_get(pciio_dmamap_t pciio_dmamap){ return (pciio_dmamap->pd_slot);}/****** Generic pci slot information interfaces ******/pciio_info_tpciio_info_chk(devfs_handle_t pciio){ arbitrary_info_t ainfo = 0; hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo); return (pciio_info_t) ainfo;}pciio_info_tpciio_info_get(devfs_handle_t pciio){ pciio_info_t pciio_info; pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio);#ifdef DEBUG_PCIIO { int pos; char dname[256]; pos = devfs_generate_path(pciio, dname, 256); printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); }#endif /* DEBUG_PCIIO */#ifdef BRINGUP if ((pciio_info != NULL) && (pciio_info->c_fingerprint != pciio_info_fingerprint) && (pciio_info->c_fingerprint != NULL)) {#else if ((pciio_info != NULL) && (pciio_info->c_fingerprint != pciio_info_fingerprint)) {#endif /* BRINGUP */ return((pciio_info_t)-1); /* Should panic .. */ } return pciio_info;}voidpciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info){ if (pciio_info != NULL) pciio_info->c_fingerprint = pciio_info_fingerprint; hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info); /* Also, mark this vertex as a PCI slot * and use the pciio_info, so pciio_info_chk * can work (and be fairly efficient). */ hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO, (arbitrary_info_t) pciio_info);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -