📄 pciio.c
字号:
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 * * 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, 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. */devfs_handle_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( 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;#ifdef EHE_ENABLE error_state_t e_state;#endif /* EHE_ENABLE */#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);#ifdef EHE_ENABLE 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)) { 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, * 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);#ifdef EHE_ENABLE 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 /* EHE_ENABLE */ 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)) { iopaddr_t busaddr; IOERROR_GETVALUE(busaddr, ioerror, busaddr); retval = usrpci_error_handler (usrpci_v, error_code, 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! */}/* ===================================================================== * 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) printk(KERN_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 printk(KERN_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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -