📄 pciba.c
字号:
pciba_bus_unlock(bus);}static pciba_map_tpciba_map_pop_hdl(pciba_bus_t bus, __psunsigned_t handle){ pciba_map_h hdl; pciba_map_t map; pciba_bus_lock(bus); for (hdl = &bus->maps; map = *hdl; hdl = &map->next) if (map->handle == handle) { *hdl = map->next; break; } pciba_bus_unlock(bus);#if DEBUG_PCIBA printk("pciba_map_pop_va(bus=0x%x, handle=0x%x) returns map=0x%x\n", bus, handle, map);#endif return map;}/* ================================================================ * driver teardown, unregister and unload */intpciba_unload(void){#if DEBUG_PCIBA printk("pciba_unload()\n");#endif if (atomic_read(&pciba_prevent_unload)) return -1; pciio_iterate("pciba_", pciba_unload_me); return 0;}intpciba_unreg(void){#if DEBUG_PCIBA printf("pciba_unreg()\n");#endif if (atomic_read(&pciba_prevent_unload)) return -1; pciio_driver_unregister("pciba_"); return 0;}intpciba_detach(devfs_handle_t conn){ devfs_handle_t base; pciba_bus_t bus; devfs_handle_t gconn; devfs_handle_t gbase; pciio_info_t pciio_info; devfs_handle_t master; arbitrary_info_t ainfo; int ret;#if DEBUG_PCIBA printf("pciba_detach(%v)\n", conn);#endif if ((GRAPH_SUCCESS != hwgraph_traverse(conn, ".guest", &gconn)) || (conn == gconn)) gconn = GRAPH_VERTEX_NONE; if (gconn != GRAPH_VERTEX_NONE) { pciba_sub_detach(gconn, PCIBA_EDGE_LBL_CFG); pciba_sub_detach(gconn, PCIBA_EDGE_LBL_DMA); pciba_sub_detach(gconn, PCIBA_EDGE_LBL_ROM);#if ULI pciba_sub_detach(gconn, PCIBA_EDGE_LBL_INTR);#endif if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &gbase)) { pciba_sub_detach(gconn, PCIBA_EDGE_LBL_MEM); pciba_sub_detach(gconn, PCIBA_EDGE_LBL_IO); pciba_sub_detach(gbase, "0"); pciba_sub_detach(gbase, "1"); pciba_sub_detach(gbase, "2"); pciba_sub_detach(gbase, "3"); pciba_sub_detach(gbase, "4"); pciba_sub_detach(gbase, "5"); hwgraph_vertex_unref(gbase); if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(gbase))) {#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/base) failed (%d)", conn, ret);#else PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)", conn, ret);#endif#if DEBUG_REFCT printk("\tretained refct %d\n", hwgraph_vertex_refct(gbase));#endif } } } pciba_sub_detach(conn, PCIBA_EDGE_LBL_CFG); pciba_sub_detach(conn, PCIBA_EDGE_LBL_DMA); pciba_sub_detach(conn, PCIBA_EDGE_LBL_ROM);#if ULI pciba_sub_detach(conn, PCIBA_EDGE_LBL_INTR);#endif if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &base)) { pciba_sub_detach(conn, PCIBA_EDGE_LBL_MEM); pciba_sub_detach(conn, PCIBA_EDGE_LBL_IO); pciba_sub_detach(base, "0"); pciba_sub_detach(base, "1"); pciba_sub_detach(base, "2"); pciba_sub_detach(base, "3"); pciba_sub_detach(base, "4"); pciba_sub_detach(base, "5"); hwgraph_vertex_unref(base); if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(base))) {#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(%v/base) failed (%d)", conn, ret);#else PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)", conn, ret);#endif#if DEBUG_REFCT printk("\tretained refct %d\n", hwgraph_vertex_refct(base));#endif } } bus = pciba_find_bus(conn, 0); if (bus && !--(bus->refct)) { pciio_info = pciio_info_get(conn); master = pciio_info_master_get(pciio_info); pciba_sub_detach(master, PCIBA_EDGE_LBL_IO); pciba_sub_detach(master, PCIBA_EDGE_LBL_MEM); pciba_sub_detach(master, PCIBA_EDGE_LBL_CFG); hwgraph_info_remove_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo);#if DEBUG_PCIBA printf("pcbia_detach: DEL(bus) at %v\n", master);#endif DEL(bus); } return 0;}static voidpciba_sub_detach1(devfs_handle_t conn, char *name, char *suf){ devfs_handle_t vhdl; pciba_soft_t soft; pciba_comm_t comm; int ret; char nbuf[128]; if (suf && *suf) { strcpy(nbuf, name); name = nbuf; strcat(name, suf); } if ((GRAPH_SUCCESS == hwgraph_edge_remove(conn, name, &vhdl)) && ((soft = pciba_soft_get(vhdl)) != NULL)) {#if DEBUG_PCIBA#if defined(SUPPORT_PRINTING_V_FORMAT) prink("pciba_sub_detach(%v,%s)\n", conn, name);#else prink("pciba_sub_detach(0x%x,%s)\n", conn, name);#endif#endif hwgraph_vertex_unref(soft->vhdl);#if DEBUG_REFCT printk("\tadjusted refct %d (soft ref: %d)\n", hwgraph_vertex_refct(vhdl), soft->refct);#endif if (!--(soft->refct)) { comm = soft->comm; if (!--(comm->refct)) { DEL(comm); } pciba_soft_set(vhdl, 0); DEL(soft); hwgraph_vertex_unref(vhdl); if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(vhdl))) {#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/%s) failed (%d)", conn, name, ret);#else PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/%s) failed (%d)", conn, name, ret);#endif#if DEBUG_REFCT printk("\tretained refct %d\n", hwgraph_vertex_refct(vhdl));#endif } } }}static voidpciba_sub_detach(devfs_handle_t conn, char *name){ pciba_sub_detach1(conn, name, ""); pciba_sub_detach1(conn, name, "_le"); pciba_sub_detach1(conn, name, "_be");}static voidpciba_unload_me(devfs_handle_t pconn_vhdl){ devfs_handle_t c_vhdl;#if DEBUG_PCIBA printf("pciba_unload_me(%v)\n", pconn_vhdl);#endif if (GRAPH_SUCCESS != hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &c_vhdl)) return; hwgraph_vertex_unref(c_vhdl);}/* ================================================================ * standard unix entry points *//*ARGSUSED */intpciba_open(dev_t *devp, int flag, int otyp, struct cred *crp){#if DEBUG_PCIBA printf("pciba_open(%V)\n", *devp);#endif return 0;}/*ARGSUSED */intpciba_close(dev_t dev){ devfs_handle_t vhdl = dev_to_vhdl(dev); pciba_soft_t soft = pciba_soft_get(vhdl);#if DEBUG_PCIBA printf("pciba_close(%V)\n", dev);#endif /* if there is pending DMA for this device, hit the * device over the head with a baseball bat and * release the system memory resources. */ if (soft && soft->comm->dmap) { pciba_dma_t next; pciba_dma_t dmap; pciba_soft_lock(soft); if (dmap = soft->comm->dmap) { soft->comm->dmap = 0; pciio_reset(soft->comm->conn); do { if (!dmap->kaddr) break; if (!dmap->paddr) break; if (dmap->bytes < NBPP) break; next = dmap->next; kvpfree(dmap->kaddr, dmap->bytes / NBPP); dmap->paddr = 0; dmap->bytes = 0; DEL(dmap); } while (dmap = next); } pciba_soft_unlock(soft); } return 0;}/* ARGSUSED */intpciba_read(dev_t dev, cred_t *crp){#if DEBUG_PCIBA printf("pciba_read(%V)\n", dev);#endif return EINVAL;}/* ARGSUSED */intpciba_write(dev_t dev, cred_t *crp){#if DEBUG_PCIBA printf("pciba_write(%V)\n", dev);#endif return EINVAL;}/*ARGSUSED */intpciba_ioctl(dev_t dev, int cmd, void *uarg, int mode, cred_t *crp, int *rvalp){ devfs_handle_t vhdl; pciba_soft_t soft; pciio_space_t space; ioctl_arg_buffer_t arg; int psize; int err = 0;#if ULI char abi = get_current_abi(); pciio_intr_t intr=0; device_desc_t desc; cpuid_t intrcpu; unsigned lines; struct uli *uli = 0;#endif unsigned flags; void *kaddr = 0; iopaddr_t paddr; pciba_dma_h dmah; pciba_dma_t dmap = 0; pciio_dmamap_t dmamap = 0; size_t bytes; int pages; pciaddr_t daddr;#if DEBUG_PCIBA printf("pciba_ioctl(%V,0x%x)\n", dev, cmd);#endif psize = (cmd >> 16) & IOCPARM_MASK;#if ULI ASSERT(sizeof(struct uliargs) > 8); /* prevent CFG access conflict */ ASSERT(sizeof(struct uliargs) <= IOCPARM_MASK);#endif arg.ca = uarg; if ((psize > 0) && (cmd & (IOC_OUT | IOC_IN))) { if (psize > sizeof(arg)) err = EINVAL; /* "bad parameter size */ else { if (cmd & IOC_OUT) bzero(arg.data, psize); if ((cmd & IOC_IN) && (copyin(uarg, arg.data, psize) < 0)) err = EFAULT; /* "parameter copyin failed" */ } } vhdl = dev_to_vhdl(dev); soft = pciba_soft_get(vhdl); space = soft->space; if (err == 0) { err = EINVAL; /* "invalid ioctl for this vertex" */ switch (space) {#if ULI case PCIIO_SPACE_NONE: /* the "intr" vertex */ /* PCIIOCSETULI: set up user interrupts. */ lines = cmd & 15; if (ABI_IS_64BIT(abi)) { if (cmd != PCIIOCSETULI(lines)) { err = EINVAL; /* "invalid ioctl for this vertex" */ break; } } else { struct uliargs uliargs; if (cmd != PCIIOCSETULI32(lines)) { err = EINVAL; /* "invalid ioctl for this vertex" */ break; } uliargs32_to_uliargs(&arg.uli32, &uliargs); arg.uli = uliargs; } desc = device_desc_dup(soft->comm->conn); device_desc_flags_set(desc, (device_desc_flags_get(desc) | D_INTR_NOTHREAD)); device_desc_intr_swlevel_set(desc, INTR_SWLEVEL_NOTHREAD_DEFAULT); device_desc_intr_name_set(desc, "PCIBA"); device_desc_default_set(soft->comm->conn, desc); /* When designating interrupts, the slot number * is taken from the connection point. * Bits 0..3 are used to select INTA..INTD; more * than one bit can be specified. These should * be constructed using PCIIO_INTR_LINE_[ABCD]. */ intr = pciio_intr_alloc (soft->comm->conn, desc, lines, soft->vhdl); if (intr == 0) { err = ENOMEM; /* "insufficient resources" */ break; } intrcpu = cpuvertex_to_cpuid(pciio_intr_cpu_get(intr)); if (err = new_uli(&arg.uli, &uli, intrcpu)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -