📄 pciba.c
字号:
break; /* "unable to set up ULI" */ } atomic_inc(&pciba_prevent_unload); pciio_intr_connect(intr, pciba_intr, uli, (void *) 0); /* NOTE: don't set the teardown function * until the interrupt is connected. */ uli->teardownarg1 = (__psint_t) intr; uli->teardown = pciba_clearuli; arg.uli.id = uli->index; if (!ABI_IS_64BIT(abi)) { struct uliargs32 uliargs32; uliargs_to_uliargs32(&arg.uli, &uliargs32); arg.uli32 = uliargs32; } err = 0; break;#endif case PCIBA_SPACE_UDMA: /* the "dma" vertex */ switch (cmd) { case PCIIOCDMAALLOC: /* PCIIOCDMAALLOC: allocate a chunk of physical * memory and set it up for DMA. Return the * PCI address that gets to it. * NOTE: this allocates memory local to the * CPU doing the ioctl, not local to the * device that will be doing the DMA. */ if (!_CAP_ABLE(CAP_DEVICE_MGT)) { err = EPERM; break; } /* separate the halves of the incoming parameter */ flags = arg.ud >> 32; bytes = arg.ud & 0xFFFFFFFF;#if DEBUG_PCIBA printf("pciba: user wants 0x%x bytes of DMA, flags 0x%x\n", bytes, flags);#endif /* round up the requested size to the next highest page */ pages = (bytes + NBPP - 1) / NBPP; /* make sure the requested size is something reasonable */ if (pages > pci_user_dma_max_pages) {#if DEBUG_PCIBA printf("pciba: request for too much buffer space\n");#endif err = EINVAL; break; /* "request for too much buffer space" */ } /* "correct" number of bytes */ bytes = pages * NBPP; /* allocate the space */ /* XXX- force to same node as the device? */ /* XXX- someday, we want to handle user buffers, * and noncontiguous pages, but this will * require either fancy mapping or handing * a list of blocks back to the user. For * now, just tell users to allocate a lot of * individual single-pages and manage their * scatter-gather manually. */ kaddr = kvpalloc(pages, VM_DIRECT | KM_NOSLEEP, 0); if (kaddr == 0) {#if DEBUG_PCIBA printf("pciba: unable to get %d contiguous pages\n", pages);#endif err = EAGAIN; /* "insufficient resources, try again later" */ break; }#if DEBUG_PCIBA printf("pciba: kaddr is 0x%x\n", kaddr);#endif paddr = kvtophys(kaddr); daddr = pciio_dmatrans_addr (soft->comm->conn, 0, paddr, bytes, flags); if (daddr == 0) { /* "no direct path available" */#if DEBUG_PCIBA printf("pciba: dmatrans failed, trying dmamap\n");#endif dmamap = pciio_dmamap_alloc (soft->comm->conn, 0, bytes, flags); if (dmamap == 0) {#if DEBUG_PCIBA printf("pciba: unable to allocate dmamap\n");#endif err = ENOMEM; break; /* "out of mapping resources" */ } daddr = pciio_dmamap_addr (dmamap, paddr, bytes); if (daddr == 0) {#if DEBUG_PCIBA printf("pciba: dmamap_addr failed\n");#endif err = EINVAL; break; /* "can't get there from here" */ } }#if DEBUG_PCIBA printf("pciba: daddr is 0x%x\n", daddr);#endif NEW(dmap); if (!dmap) { err = ENOMEM; break; /* "no memory available" */ } dmap->bytes = bytes; dmap->pages = pages; dmap->paddr = paddr; dmap->kaddr = kaddr; dmap->map = dmamap; dmap->daddr = daddr; dmap->handle = 0;#if DEBUG_PCIBA printf("pciba: dmap 0x%x contains va 0x%x bytes 0x%x pa 0x%x pages 0x%x daddr 0x%x\n", dmap, kaddr, bytes, paddr, pages, daddr);#endif arg.ud = dmap->daddr; err = 0; break; case PCIIOCDMAFREE: /* PCIIOCDMAFREE: Find the chunk of * User DMA memory, and release its * resources back to the system. */ if (!_CAP_ABLE(CAP_DEVICE_MGT)) { err = EPERM; /* "you can't do that" */ break; } if (soft->comm->dmap == NULL) { err = EINVAL; /* "no User DMA to free" */ break; } /* find the request. */ daddr = arg.ud; err = EINVAL; /* "block not found" */ pciba_soft_lock(soft); for (dmah = &soft->comm->dmap; dmap = *dmah; dmah = &dmap->next) { if (dmap->daddr == daddr) { if (dmap->handle != 0) { dmap = 0; /* don't DEL this dmap! */ err = EINVAL; /* "please unmap first" */ break; /* break outa for loop. */ } *dmah = dmap->next; if (dmamap = dmap->map) { pciio_dmamap_free(dmamap); dmamap = 0; /* don't free it twice! */ } kvpfree(dmap->kaddr, dmap->bytes / NBPP); DEL(dmap); dmap = 0; /* don't link this back into the list! */ err = 0; /* "all done" */ break; /* break outa for loop. */ } } pciba_soft_unlock(soft); break; /* break outa case PCIIOCDMAFREE: */ } break; /* break outa case PCIBA_SPACE_UDMA: */ case PCIIO_SPACE_CFG: /* PCIIOCCFG{RD,WR}: read and/or write * PCI configuration space. If both, * the read happens first (this becomes * a swap operation, atomic with respect * to other updates through this path). * * Should be *last* IOCTl command checked, * so other patterns can nip useless codes * out of the space this decodes. */ err = EINVAL; if ((psize > 0) || (psize <= 8) && (((cmd & 0xFF) + psize) <= 256) && (cmd & (IOC_IN | IOC_OUT))) { uint64_t rdata; uint64_t wdata; int shft; shft = 64 - (8 * psize); wdata = arg.ud >> shft; pciba_soft_lock(soft); if (cmd & IOC_OUT) rdata = pciio_config_get(soft->comm->conn, cmd & 0xFFFF, psize); if (cmd & IOC_IN) pciio_config_set(soft->comm->conn, cmd & 0xFFFF, psize, wdata); pciba_soft_unlock(soft); arg.ud = rdata << shft; err = 0; break; } break; } } /* done: come here if all went OK. */ if ((err == 0) && ((cmd & IOC_OUT) && (psize > 0)) && copyout(arg.data, uarg, psize)) err = EFAULT; /* This gets delayed until after the copyout so we * do not free the dmap on a copyout error, or * alternately end up with a dangling allocated * buffer that the user never got back. */ if ((err == 0) && dmap) { pciba_soft_lock(soft); dmap->next = soft->comm->dmap; soft->comm->dmap = dmap; pciba_soft_unlock(soft); } if (err) { /* Things went badly. Clean up. */#if ULI if (intr) { pciio_intr_disconnect(intr); pciio_intr_free(intr); } if (uli) free_uli(uli);#endif if (dmap) { if (dmap->map && (dmap->map != dmamap)) pciio_dmamap_free(dmap->map); DEL(dmap); } if (dmamap) pciio_dmamap_free(dmamap); if (kaddr) kvpfree(kaddr, pages); } return *rvalp = err;}/* ================================================================ * mapping support *//*ARGSUSED */intpciba_map(dev_t dev, vhandl_t *vt, off_t off, size_t len, uint32_t prot){ devfs_handle_t vhdl = dev_to_vhdl(dev); pciba_soft_t soft = pciba_soft_get(vhdl); devfs_handle_t conn = soft->comm->conn; pciio_space_t space = soft->space; size_t pages = (len + NBPP - 1) / NBPP; pciio_piomap_t pciio_piomap = 0; caddr_t kaddr; pciba_map_t map; pciba_dma_t dmap;#if DEBUG_PCIBA printf("pciba_map(%V,vt=0x%x)\n", dev, vt);#endif if (space == PCIBA_SPACE_UDMA) { pciba_soft_lock(soft); for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) { if (off == dmap->daddr) { if (pages != dmap->pages) { pciba_soft_unlock(soft); return EINVAL; /* "size mismatch" */ } v_mapphys(vt, dmap->kaddr, dmap->bytes); dmap->handle = v_gethandle(vt); pciba_soft_unlock(soft);#if DEBUG_PCIBA printf("pciba: mapped dma at kaddr 0x%x via handle 0x%x\n", dmap->kaddr, dmap->handle);#endif return 0; } } pciba_soft_unlock(soft); return EINVAL; /* "block not found" */ } if (soft->iomem == PCIIO_SPACE_NONE) return EINVAL; /* "mmap not supported" */ kaddr = (caddr_t) pciio_pio_addr (conn, 0, space, off, len, &pciio_piomap, soft->flags | PCIIO_FIXED );#if DEBUG_PCIBA printf("pciba: mapped %R[0x%x..0x%x] via map 0x%x to kaddr 0x%x\n", space, space_desc, off, off + len - 1, pciio_piomap, kaddr);#endif if (kaddr == NULL) return EINVAL; /* "you can't get there from here" */ NEW(map); if (map == NULL) { if (pciio_piomap) pciio_piomap_free(pciio_piomap); return ENOMEM; /* "unable to get memory resources */ }#ifdef LATER map->uthread = curuthread;#endif map->handle = v_gethandle(vt); map->uvaddr = v_getaddr(vt); map->map = pciio_piomap; map->space = soft->iomem; map->base = soft->base + off; map->size = len; pciba_map_push(soft->comm->bus, map); /* Inform the system of the correct * kvaddr corresponding to the thing * that is being mapped. */ v_mapphys(vt, kaddr, len); return 0;}/*ARGSUSED */intpciba_unmap(dev_t dev, vhandl_t *vt){ devfs_handle_t vhdl = dev_to_vhdl(dev); pciba_soft_t soft = pciba_soft_get(vhdl); pciba_bus_t bus = soft->comm->bus; pciba_map_t map; __psunsigned_t handle = v_gethandle(vt);#if DEBUG_PCIBA printf("pciba_unmap(%V,vt=%x)\n", dev, vt);#endif /* If this is a userDMA buffer, * make a note that it has been unmapped * so it can be released. */ if (soft->comm->dmap) { pciba_dma_t dmap; pciba_soft_lock(soft); for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) if (handle == dmap->handle) { dmap->handle = 0; pciba_soft_unlock(soft);#if DEBUG_PCIBA printf("pciba: unmapped dma at kaddr 0x%x via handle 0x%x\n", dmap->kaddr, handle);#endif return 0; /* found userPCI */ } pciba_soft_unlock(soft); } map = pciba_map_pop_hdl(bus, handle); if (map == NULL) return EINVAL; /* no match */ if (map->map) pciio_piomap_free(map->map); DEL(map); return (0); /* all done OK */}#if ULIvoidpciba_clearuli(struct uli *uli){ pciio_intr_t intr = (pciio_intr_t) uli->teardownarg1;#if DEBUG_PCIBA printf("pciba_clearuli(0x%x)\n", uli);#endif pciio_intr_disconnect(intr); pciio_intr_free(intr); atomic_dec(&pciba_prevent_unload);}voidpciba_intr(intr_arg_t arg){ struct uli *uli = (struct uli *) arg; int ulinum = uli->index; extern void frs_handle_uli(void); if (ulinum >= 0 && ulinum < MAX_ULIS) { uli_callup(ulinum); if (private.p_frs_flags) frs_handle_uli(); }}#endif#endif /* LATER - undef as we implement each routine */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -