From: mpi Date: Mon, 15 Dec 2014 17:10:44 +0000 (+0000) Subject: Stop using usb_{alloc,free}mem() for the rings and internal structures. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=b067e289affef06619cefe5dfdbeb10af2336a61;p=openbsd Stop using usb_{alloc,free}mem() for the rings and internal structures. Since xhci(4) does not allocate memory for its rings in interrupt context, it has no use for the free lists offered by the USB memory allocator. Using bus_dmamem_alloc(9) and friends also allows us to respect the boundary requirement for the various structures specified in Table 54. While here make use of defines for every alignment and boundary requirements which are different than a page size. --- diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index d47f8031ea5..4928be70f30 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xhci.c,v 1.45 2014/12/08 13:32:34 mpi Exp $ */ +/* $OpenBSD: xhci.c,v 1.46 2014/12/15 17:10:44 mpi Exp $ */ /* * Copyright (c) 2014 Martin Pieuchot @@ -52,7 +52,7 @@ int xhcidebug = 3; #define DEVNAME(sc) ((sc)->sc_bus.bdev.dv_xname) #define TRBOFF(r, trb) ((char *)(trb) - (char *)((r).trbs)) -#define DEQPTR(r) (DMAADDR(&(r).dma, sizeof(struct xhci_trb) * (r).index)) +#define DEQPTR(r) ((r).dma.paddr + (sizeof(struct xhci_trb) * (r).index)) struct pool *xhcixfer; @@ -67,7 +67,7 @@ struct xhci_pipe { * XXX used to pass the xfer pointer back to the * interrupt routine, better way? */ - struct usbd_xfer *pending_xfers[XHCI_MAX_TRANSFERS]; + struct usbd_xfer *pending_xfers[XHCI_MAX_XFER]; int halted; size_t free_trbs; }; @@ -85,7 +85,8 @@ int xhci_scratchpad_alloc(struct xhci_softc *, int); void xhci_scratchpad_free(struct xhci_softc *); int xhci_softdev_alloc(struct xhci_softc *, uint8_t); void xhci_softdev_free(struct xhci_softc *, uint8_t); -int xhci_ring_alloc(struct xhci_softc *, struct xhci_ring *, size_t); +int xhci_ring_alloc(struct xhci_softc *, struct xhci_ring *, size_t, + size_t); void xhci_ring_free(struct xhci_softc *, struct xhci_ring *); void xhci_ring_reset(struct xhci_softc *, struct xhci_ring *); struct xhci_trb *xhci_ring_dequeue(struct xhci_softc *, struct xhci_ring *, @@ -206,6 +207,68 @@ xhci_dump_trb(struct xhci_trb *trb) } #endif +int usbd_dma_contig_alloc(struct usbd_bus *, struct usbd_dma_info *, + void **, bus_size_t, bus_size_t, bus_size_t); +void usbd_dma_contig_free(struct usbd_bus *, struct usbd_dma_info *); + +int +usbd_dma_contig_alloc(struct usbd_bus *bus, struct usbd_dma_info *dma, + void **kvap, bus_size_t size, bus_size_t alignment, bus_size_t boundary) +{ + int error; + + dma->tag = bus->dmatag; + dma->size = size; + + error = bus_dmamap_create(dma->tag, size, 1, size, boundary, + BUS_DMA_NOWAIT, &dma->map); + if (error != 0) + goto fail; + + error = bus_dmamem_alloc(dma->tag, size, alignment, boundary, &dma->seg, + 1, &dma->nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO); + if (error != 0) + goto fail; + + error = bus_dmamem_map(dma->tag, &dma->seg, 1, size, &dma->vaddr, + BUS_DMA_NOWAIT | BUS_DMA_COHERENT); + if (error != 0) + goto fail; + + error = bus_dmamap_load_raw(dma->tag, dma->map, &dma->seg, 1, size, + BUS_DMA_NOWAIT); + if (error != 0) + goto fail; + + bus_dmamap_sync(dma->tag, dma->map, 0, size, BUS_DMASYNC_PREWRITE); + + dma->paddr = dma->map->dm_segs[0].ds_addr; + if (kvap != NULL) + *kvap = dma->vaddr; + + return (0); + +fail: usbd_dma_contig_free(bus, dma); + return (error); +} + +void +usbd_dma_contig_free(struct usbd_bus *bus, struct usbd_dma_info *dma) +{ + if (dma->map != NULL) { + if (dma->vaddr != NULL) { + bus_dmamap_sync(bus->dmatag, dma->map, 0, dma->size, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(bus->dmatag, dma->map); + bus_dmamem_unmap(bus->dmatag, dma->vaddr, dma->size); + bus_dmamem_free(bus->dmatag, &dma->seg, 1); + dma->vaddr = NULL; + } + bus_dmamap_destroy(bus->dmatag, dma->map); + dma->map = NULL; + } +} + int xhci_init(struct xhci_softc *sc) { @@ -266,56 +329,50 @@ xhci_init(struct xhci_softc *sc) DPRINTF(("%s: %d ports and %d slots\n", DEVNAME(sc), sc->sc_noport, sc->sc_noslot)); - /* - * Section 6.1 - Device Context Base Address Array - * shall be aligned to a 64 byte boundary. - */ - sc->sc_dcbaa.size = (sc->sc_noslot + 1) * sizeof(uint64_t); - error = usb_allocmem(&sc->sc_bus, sc->sc_dcbaa.size, 64, - &sc->sc_dcbaa.dma); + /* Setup Device Context Base Address Array. */ + error = usbd_dma_contig_alloc(&sc->sc_bus, &sc->sc_dcbaa.dma, + (void **)&sc->sc_dcbaa.segs, (sc->sc_noslot + 1) * sizeof(uint64_t), + XHCI_DCBAA_ALIGN, sc->sc_pagesize); if (error) return (ENOMEM); - sc->sc_dcbaa.segs = KERNADDR(&sc->sc_dcbaa.dma, 0); - memset(sc->sc_dcbaa.segs, 0, sc->sc_dcbaa.size); - usb_syncmem(&sc->sc_dcbaa.dma, 0, sc->sc_dcbaa.size, - BUS_DMASYNC_PREWRITE); /* Setup command ring. */ - error = xhci_ring_alloc(sc, &sc->sc_cmd_ring, XHCI_MAX_COMMANDS); + error = xhci_ring_alloc(sc, &sc->sc_cmd_ring, XHCI_MAX_CMDS, + XHCI_CMDS_RING_ALIGN); if (error) { printf("%s: could not allocate command ring.\n", DEVNAME(sc)); - usb_freemem(&sc->sc_bus, &sc->sc_dcbaa.dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_dcbaa.dma); return (error); } /* Setup one event ring and its segment table (ERST). */ - error = xhci_ring_alloc(sc, &sc->sc_evt_ring, XHCI_MAX_EVENTS); + error = xhci_ring_alloc(sc, &sc->sc_evt_ring, XHCI_MAX_EVTS, + XHCI_EVTS_RING_ALIGN); if (error) { printf("%s: could not allocate event ring.\n", DEVNAME(sc)); xhci_ring_free(sc, &sc->sc_cmd_ring); - usb_freemem(&sc->sc_bus, &sc->sc_dcbaa.dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_dcbaa.dma); return (error); } /* Allocate the required entry for the segment table. */ - sc->sc_erst.size = 1 * sizeof(struct xhci_erseg); - error = usb_allocmem(&sc->sc_bus, sc->sc_erst.size, 64, - &sc->sc_erst.dma); + error = usbd_dma_contig_alloc(&sc->sc_bus, &sc->sc_erst.dma, + (void **)&sc->sc_erst.segs, sizeof(struct xhci_erseg), + XHCI_ERST_ALIGN, XHCI_ERST_BOUNDARY); if (error) { printf("%s: could not allocate segment table.\n", DEVNAME(sc)); xhci_ring_free(sc, &sc->sc_evt_ring); xhci_ring_free(sc, &sc->sc_cmd_ring); - usb_freemem(&sc->sc_bus, &sc->sc_dcbaa.dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_dcbaa.dma); return (ENOMEM); } - sc->sc_erst.segs = KERNADDR(&sc->sc_erst.dma, 0); /* Set our ring address and size in its corresponding segment. */ - sc->sc_erst.segs[0].er_addr = htole64(DMAADDR(&sc->sc_evt_ring.dma, 0)); - sc->sc_erst.segs[0].er_size = htole32(XHCI_MAX_EVENTS); + sc->sc_erst.segs[0].er_addr = htole64(sc->sc_evt_ring.dma.paddr); + sc->sc_erst.segs[0].er_size = htole32(XHCI_MAX_EVTS); sc->sc_erst.segs[0].er_rsvd = 0; - usb_syncmem(&sc->sc_erst.dma, 0, sc->sc_erst.size, - BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->sc_erst.dma.tag, sc->sc_erst.dma.map, 0, + sc->sc_erst.dma.size, BUS_DMASYNC_PREWRITE); /* Get the number of scratch pages and configure them if necessary. */ hcr = XREAD4(sc, XHCI_HCSPARAMS2); @@ -324,10 +381,10 @@ xhci_init(struct xhci_softc *sc) if (npage > 0 && xhci_scratchpad_alloc(sc, npage)) { printf("%s: could not allocate scratchpad.\n", DEVNAME(sc)); - usb_freemem(&sc->sc_bus, &sc->sc_erst.dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_erst.dma); xhci_ring_free(sc, &sc->sc_evt_ring); xhci_ring_free(sc, &sc->sc_cmd_ring); - usb_freemem(&sc->sc_bus, &sc->sc_dcbaa.dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_dcbaa.dma); return (ENOMEM); } @@ -348,7 +405,7 @@ xhci_config(struct xhci_softc *sc) XOWRITE4(sc, XHCI_CONFIG, hcr | sc->sc_noslot); /* Set the device context base array address. */ - paddr = (uint64_t)DMAADDR(&sc->sc_dcbaa.dma, 0); + paddr = (uint64_t)sc->sc_dcbaa.dma.paddr; XOWRITE4(sc, XHCI_DCBAAP_LO, (uint32_t)paddr); XOWRITE4(sc, XHCI_DCBAAP_HI, (uint32_t)(paddr >> 32)); @@ -356,7 +413,7 @@ xhci_config(struct xhci_softc *sc) XOREAD4(sc, XHCI_DCBAAP_HI), XOREAD4(sc, XHCI_DCBAAP_LO))); /* Set the command ring address. */ - paddr = (uint64_t)DMAADDR(&sc->sc_cmd_ring.dma, 0); + paddr = (uint64_t)sc->sc_cmd_ring.dma.paddr; XOWRITE4(sc, XHCI_CRCR_LO, ((uint32_t)paddr) | XHCI_CRCR_LO_RCS); XOWRITE4(sc, XHCI_CRCR_HI, (uint32_t)(paddr >> 32)); @@ -367,7 +424,7 @@ xhci_config(struct xhci_softc *sc) XRWRITE4(sc, XHCI_ERSTSZ(0), XHCI_ERSTS_SET(1)); /* Set the segment table address. */ - paddr = (uint64_t)DMAADDR(&sc->sc_erst.dma, 0); + paddr = (uint64_t)sc->sc_erst.dma.paddr; XRWRITE4(sc, XHCI_ERSTBA_LO(0), (uint32_t)paddr); XRWRITE4(sc, XHCI_ERSTBA_HI(0), (uint32_t)(paddr >> 32)); @@ -375,7 +432,7 @@ xhci_config(struct xhci_softc *sc) XRREAD4(sc, XHCI_ERSTBA_HI(0)), XRREAD4(sc, XHCI_ERSTBA_LO(0)))); /* Set the ring dequeue address. */ - paddr = (uint64_t)DMAADDR(&sc->sc_evt_ring.dma, 0); + paddr = (uint64_t)sc->sc_evt_ring.dma.paddr; XRWRITE4(sc, XHCI_ERDP_LO(0), (uint32_t)paddr); XRWRITE4(sc, XHCI_ERDP_HI(0), (uint32_t)(paddr >> 32)); @@ -436,10 +493,10 @@ xhci_detach(struct device *self, int flags) if (sc->sc_spad.npage > 0) xhci_scratchpad_free(sc); - usb_freemem(&sc->sc_bus, &sc->sc_erst.dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_erst.dma); xhci_ring_free(sc, &sc->sc_evt_ring); xhci_ring_free(sc, &sc->sc_cmd_ring); - usb_freemem(&sc->sc_bus, &sc->sc_dcbaa.dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_dcbaa.dma); return (0); } @@ -665,7 +722,7 @@ xhci_event_xfer(struct xhci_softc *sc, uint64_t paddr, uint32_t status, code = XHCI_TRB_GET_CODE(status); remain = XHCI_TRB_REMAIN(status); - trb_idx = (paddr - DMAADDR(&xp->ring.dma, 0)) / sizeof(struct xhci_trb); + trb_idx = (paddr - xp->ring.dma.paddr) / sizeof(struct xhci_trb); if (trb_idx < 0 || trb_idx >= xp->ring.ntrb) { printf("%s: wrong trb index (%d) max is %zu\n", DEVNAME(sc), trb_idx, xp->ring.ntrb - 1); @@ -753,7 +810,7 @@ xhci_event_command(struct xhci_softc *sc, uint64_t paddr) uint8_t dci, slot; int i, trb_idx; - trb_idx = (paddr - DMAADDR(&sc->sc_cmd_ring.dma, 0)) / sizeof(*trb); + trb_idx = (paddr - sc->sc_cmd_ring.dma.paddr) / sizeof(*trb); if (trb_idx < 0 || trb_idx >= sc->sc_cmd_ring.ntrb) { printf("%s: wrong trb index (%d) max is %zu\n", DEVNAME(sc), trb_idx, sc->sc_cmd_ring.ntrb - 1); @@ -785,7 +842,7 @@ xhci_event_command(struct xhci_softc *sc, uint64_t paddr) xp->halted = 0; /* Complete all pending transfers. */ - for (i = 0; i < XHCI_MAX_TRANSFERS; i++) { + for (i = 0; i < XHCI_MAX_XFER; i++) { xfer = xp->pending_xfers[i]; if (xfer != NULL && xfer->done == 0) { if (xfer->status != USBD_STALLED) @@ -1135,7 +1192,8 @@ xhci_context_setup(struct xhci_softc *sc, struct usbd_pipe *pipe) /* Unmask the slot context */ sdev->input_ctx->add_flags |= htole32(XHCI_INCTX_MASK_DCI(0)); - usb_syncmem(&sdev->ictx_dma, 0, sc->sc_pagesize, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sdev->ictx_dma.tag, sdev->ictx_dma.map, 0, + sc->sc_pagesize, BUS_DMASYNC_PREWRITE); } int @@ -1153,7 +1211,7 @@ xhci_pipe_init(struct xhci_softc *sc, struct usbd_pipe *pipe) pipe->endpoint->edesc->bEndpointAddress); #endif - if (xhci_ring_alloc(sc, &xp->ring, XHCI_MAX_TRANSFERS)) + if (xhci_ring_alloc(sc, &xp->ring, XHCI_MAX_XFER, XHCI_XFER_RING_ALIGN)) return (ENOMEM); xp->free_trbs = xp->ring.ntrb; @@ -1174,10 +1232,10 @@ xhci_pipe_init(struct xhci_softc *sc, struct usbd_pipe *pipe) * descriptor. */ error = xhci_cmd_set_address(sc, xp->slot, - DMAADDR(&sdev->ictx_dma, 0), XHCI_TRB_BSR); + sdev->ictx_dma.paddr, XHCI_TRB_BSR); } else { error = xhci_cmd_configure_ep(sc, xp->slot, - DMAADDR(&sdev->ictx_dma, 0)); + sdev->ictx_dma.paddr); } if (error) { @@ -1218,9 +1276,10 @@ xhci_pipe_close(struct usbd_pipe *pipe) /* Clear the Endpoint Context */ memset(sdev->ep_ctx[xp->dci - 1], 0, sizeof(struct xhci_epctx)); - usb_syncmem(&sdev->ictx_dma, 0, sc->sc_pagesize, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sdev->ictx_dma.tag, sdev->ictx_dma.map, 0, + sc->sc_pagesize, BUS_DMASYNC_PREWRITE); - if (xhci_cmd_configure_ep(sc, xp->slot, DMAADDR(&sdev->ictx_dma, 0))) + if (xhci_cmd_configure_ep(sc, xp->slot, sdev->ictx_dma.paddr)) DPRINTF(("%s: error clearing ep (%d)\n", DEVNAME(sc), xp->dci)); xhci_ring_free(sc, &xp->ring); @@ -1258,19 +1317,18 @@ xhci_setaddr(struct usbd_device *dev, int addr) xhci_context_setup(sc, dev->default_pipe); - error = xhci_cmd_set_address(sc, xp->slot, - DMAADDR(&sdev->ictx_dma, 0), 0); + error = xhci_cmd_set_address(sc, xp->slot, sdev->ictx_dma.paddr, 0); #ifdef XHCI_DEBUG if (error == 0) { struct xhci_sctx *sctx; uint8_t addr; - usb_syncmem(&sdev->octx_dma, 0, sc->sc_pagesize, - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sdev->octx_dma.tag, sdev->octx_dma.map, 0, + sc->sc_pagesize, BUS_DMASYNC_POSTREAD); /* Get output slot context. */ - sctx = KERNADDR(&sdev->octx_dma, 0); + sctx = (struct xhci_sctx *)sdev->octx_dma.vaddr; addr = XHCI_SCTX_DEV_ADDR(letoh32(sctx->state)); error = (addr == 0); @@ -1300,35 +1358,33 @@ xhci_scratchpad_alloc(struct xhci_softc *sc, int npage) int error, i; /* Allocate the required entry for the table. */ - error = usb_allocmem(&sc->sc_bus, npage * sizeof(uint64_t), 64, - &sc->sc_spad.table_dma); + error = usbd_dma_contig_alloc(&sc->sc_bus, &sc->sc_spad.table_dma, + (void **)&pte, npage * sizeof(uint64_t), XHCI_SPAD_TABLE_ALIGN, + sc->sc_pagesize); if (error) return (ENOMEM); - pte = KERNADDR(&sc->sc_spad.table_dma, 0); - /* Alloccate space for the pages. */ - error = usb_allocmem(&sc->sc_bus, npage * sc->sc_pagesize, - sc->sc_pagesize, &sc->sc_spad.pages_dma); + /* Allocate pages. XXX does not need to be contiguous. */ + error = usbd_dma_contig_alloc(&sc->sc_bus, &sc->sc_spad.pages_dma, + NULL, npage * sc->sc_pagesize, sc->sc_pagesize, 0); if (error) { - usb_freemem(&sc->sc_bus, &sc->sc_spad.table_dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_spad.table_dma); return (ENOMEM); } - memset(KERNADDR(&sc->sc_spad.pages_dma, 0), 0, npage * sc->sc_pagesize); - usb_syncmem(&sc->sc_spad.pages_dma, 0, npage * sc->sc_pagesize, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); for (i = 0; i < npage; i++) { pte[i] = htole64( - DMAADDR(&sc->sc_spad.pages_dma, i * sc->sc_pagesize) + sc->sc_spad.pages_dma.paddr + (i * sc->sc_pagesize) ); } - usb_syncmem(&sc->sc_spad.table_dma, 0, npage * sizeof(uint64_t), - BUS_DMASYNC_PREWRITE); + + bus_dmamap_sync(sc->sc_spad.table_dma.tag, sc->sc_spad.table_dma.map, 0, + npage * sizeof(uint64_t), BUS_DMASYNC_PREWRITE); /* Entry 0 points to the table of scratchpad pointers. */ - sc->sc_dcbaa.segs[0] = htole64(DMAADDR(&sc->sc_spad.table_dma, 0)); - usb_syncmem(&sc->sc_dcbaa.dma, 0, sizeof(uint64_t), - BUS_DMASYNC_PREWRITE); + sc->sc_dcbaa.segs[0] = htole64(sc->sc_spad.table_dma.paddr); + bus_dmamap_sync(sc->sc_dcbaa.dma.tag, sc->sc_dcbaa.dma.map, 0, + sizeof(uint64_t), BUS_DMASYNC_PREWRITE); sc->sc_spad.npage = npage; @@ -1339,25 +1395,27 @@ void xhci_scratchpad_free(struct xhci_softc *sc) { sc->sc_dcbaa.segs[0] = 0; - usb_syncmem(&sc->sc_dcbaa.dma, 0, sizeof(uint64_t), - BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->sc_dcbaa.dma.tag, sc->sc_dcbaa.dma.map, 0, + sizeof(uint64_t), BUS_DMASYNC_PREWRITE); - usb_freemem(&sc->sc_bus, &sc->sc_spad.pages_dma); - usb_freemem(&sc->sc_bus, &sc->sc_spad.table_dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_spad.pages_dma); + usbd_dma_contig_free(&sc->sc_bus, &sc->sc_spad.table_dma); } - int -xhci_ring_alloc(struct xhci_softc *sc, struct xhci_ring *ring, size_t ntrb) +xhci_ring_alloc(struct xhci_softc *sc, struct xhci_ring *ring, size_t ntrb, + size_t alignment) { size_t size; + int error; size = ntrb * sizeof(struct xhci_trb); - if (usb_allocmem(&sc->sc_bus, size, 16, &ring->dma) != 0) - return (ENOMEM); + error = usbd_dma_contig_alloc(&sc->sc_bus, &ring->dma, + (void **)&ring->trbs, size, alignment, XHCI_RING_BOUNDARY); + if (error) + return (error); - ring->trbs = KERNADDR(&ring->dma, 0); ring->ntrb = ntrb; xhci_ring_reset(sc, ring); @@ -1368,7 +1426,7 @@ xhci_ring_alloc(struct xhci_softc *sc, struct xhci_ring *ring, size_t ntrb) void xhci_ring_free(struct xhci_softc *sc, struct xhci_ring *ring) { - usb_freemem(&sc->sc_bus, &ring->dma); + usbd_dma_contig_free(&sc->sc_bus, &ring->dma); } void @@ -1390,10 +1448,11 @@ xhci_ring_reset(struct xhci_softc *sc, struct xhci_ring *ring) if (ring != &sc->sc_evt_ring) { struct xhci_trb *trb = &ring->trbs[ring->ntrb - 1]; - trb->trb_paddr = htole64(DMAADDR(&ring->dma, 0)); + trb->trb_paddr = htole64(ring->dma.paddr); trb->trb_flags = htole32(XHCI_TRB_TYPE_LINK | XHCI_TRB_LINKSEG); } - usb_syncmem(&ring->dma, 0, size, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(ring->dma.tag, ring->dma.map, 0, size, + BUS_DMASYNC_PREWRITE); } struct xhci_trb* @@ -1404,8 +1463,8 @@ xhci_ring_dequeue(struct xhci_softc *sc, struct xhci_ring *ring, int cons) KASSERT(idx < ring->ntrb); - usb_syncmem(&ring->dma, idx * sizeof(struct xhci_trb), - sizeof(struct xhci_trb), BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(ring->dma.tag, ring->dma.map, idx * sizeof(*trb), + sizeof(*trb), BUS_DMASYNC_POSTREAD); trb = &ring->trbs[idx]; @@ -1422,8 +1481,9 @@ xhci_ring_dequeue(struct xhci_softc *sc, struct xhci_ring *ring, int cons) else ring->trbs[idx].trb_flags &= ~htole32(XHCI_TRB_CYCLE); - usb_syncmem(&ring->dma, sizeof(struct xhci_trb) * idx, - sizeof(struct xhci_trb), BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(ring->dma.tag, ring->dma.map, + sizeof(struct xhci_trb) * idx, sizeof(struct xhci_trb), + BUS_DMASYNC_PREWRITE); ring->index = 0; ring->toggle ^= 1; @@ -1466,8 +1526,10 @@ xhci_command_submit(struct xhci_softc *sc, struct xhci_trb *trb0, int timeout) if (trb == NULL) return (EAGAIN); memcpy(trb, trb0, sizeof(struct xhci_trb)); - usb_syncmem(&sc->sc_cmd_ring.dma, TRBOFF(sc->sc_cmd_ring, trb), - sizeof(struct xhci_trb), BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->sc_cmd_ring.dma.tag, sc->sc_cmd_ring.dma.map, + TRBOFF(sc->sc_cmd_ring, trb), sizeof(struct xhci_trb), + BUS_DMASYNC_PREWRITE); + if (timeout == 0) { XDWRITE4(sc, XHCI_DOORBELL(0), 0); @@ -1683,43 +1745,42 @@ xhci_softdev_alloc(struct xhci_softc *sc, uint8_t slot) { struct xhci_soft_dev *sdev = &sc->sc_sdevs[slot]; int i, error; + uint8_t *kva; /* * Setup input context. Even with 64 byte context size, it * fits into the smallest supported page size, so use that. */ - error = usb_allocmem(&sc->sc_bus, sc->sc_pagesize, sc->sc_pagesize, - &sdev->ictx_dma); + error = usbd_dma_contig_alloc(&sc->sc_bus, &sdev->ictx_dma, + (void **)&kva, sc->sc_pagesize, XHCI_ICTX_ALIGN, sc->sc_pagesize); if (error) return (ENOMEM); - memset(KERNADDR(&sdev->ictx_dma, 0), 0, sc->sc_pagesize); - sdev->input_ctx = KERNADDR(&sdev->ictx_dma, 0); - sdev->slot_ctx = KERNADDR(&sdev->ictx_dma, sc->sc_ctxsize); + sdev->input_ctx = (struct xhci_inctx *)kva; + sdev->slot_ctx = (struct xhci_sctx *)(kva + sc->sc_ctxsize); for (i = 0; i < 31; i++) sdev->ep_ctx[i] = - KERNADDR(&sdev->ictx_dma, (i + 2) * sc->sc_ctxsize); + (struct xhci_epctx *)(kva + (i + 2) * sc->sc_ctxsize); DPRINTF(("%s: dev %d, input=%p slot=%p ep0=%p\n", DEVNAME(sc), slot, sdev->input_ctx, sdev->slot_ctx, sdev->ep_ctx[0])); /* Setup output context */ - error = usb_allocmem(&sc->sc_bus, sc->sc_pagesize, sc->sc_pagesize, - &sdev->octx_dma); + error = usbd_dma_contig_alloc(&sc->sc_bus, &sdev->octx_dma, NULL, + sc->sc_pagesize, XHCI_OCTX_ALIGN, sc->sc_pagesize); if (error) { - usb_freemem(&sc->sc_bus, &sdev->ictx_dma); + usbd_dma_contig_free(&sc->sc_bus, &sdev->ictx_dma); return (ENOMEM); } - memset(KERNADDR(&sdev->octx_dma, 0), 0, sc->sc_pagesize); memset(&sdev->pipes, 0, sizeof(sdev->pipes)); DPRINTF(("%s: dev %d, setting DCBAA to 0x%016llx\n", DEVNAME(sc), - slot, (long long)DMAADDR(&sdev->octx_dma, 0))); + slot, (long long)sdev->octx_dma.paddr)); - sc->sc_dcbaa.segs[slot] = htole64(DMAADDR(&sdev->octx_dma, 0)); - usb_syncmem(&sc->sc_dcbaa.dma, slot * sizeof(uint64_t), - sizeof(uint64_t), BUS_DMASYNC_PREWRITE); + sc->sc_dcbaa.segs[slot] = htole64(sdev->octx_dma.paddr); + bus_dmamap_sync(sc->sc_dcbaa.dma.tag, sc->sc_dcbaa.dma.map, + slot * sizeof(uint64_t), sizeof(uint64_t), BUS_DMASYNC_PREWRITE); return (0); } @@ -1730,11 +1791,11 @@ xhci_softdev_free(struct xhci_softc *sc, uint8_t slot) struct xhci_soft_dev *sdev = &sc->sc_sdevs[slot]; sc->sc_dcbaa.segs[slot] = 0; - usb_syncmem(&sc->sc_dcbaa.dma, slot * sizeof(uint64_t), - sizeof(uint64_t), BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->sc_dcbaa.dma.tag, sc->sc_dcbaa.dma.map, + slot * sizeof(uint64_t), sizeof(uint64_t), BUS_DMASYNC_PREWRITE); - usb_freemem(&sc->sc_bus, &sdev->octx_dma); - usb_freemem(&sc->sc_bus, &sdev->ictx_dma); + usbd_dma_contig_free(&sc->sc_bus, &sdev->octx_dma); + usbd_dma_contig_free(&sc->sc_bus, &sdev->ictx_dma); memset(sdev, 0, sizeof(struct xhci_soft_dev)); } @@ -2306,8 +2367,9 @@ xhci_device_ctrl_start(struct usbd_xfer *xfer) trb0->trb_flags |= htole32(toggle0); - usb_syncmem(&xp->ring.dma, TRBOFF(xp->ring, trb0), - 3 * sizeof(struct xhci_trb), BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(xp->ring.dma.tag, xp->ring.dma.map, + TRBOFF(xp->ring, trb0), 3 * sizeof(struct xhci_trb), + BUS_DMASYNC_PREWRITE); s = splusb(); XDWRITE4(sc, XHCI_DOORBELL(xp->slot), xp->dci); @@ -2371,8 +2433,9 @@ xhci_device_generic_start(struct usbd_xfer *xfer) if (usbd_xfer_isread(xfer)) trb->trb_flags |= htole32(XHCI_TRB_ISP); - usb_syncmem(&xp->ring.dma, TRBOFF(xp->ring, trb), - sizeof(struct xhci_trb), BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(xp->ring.dma.tag, xp->ring.dma.map, + TRBOFF(xp->ring, trb), sizeof(struct xhci_trb), + BUS_DMASYNC_PREWRITE); s = splusb(); XDWRITE4(sc, XHCI_DOORBELL(xp->slot), xp->dci); diff --git a/sys/dev/usb/xhcireg.h b/sys/dev/usb/xhcireg.h index 97a2df7b614..a4db01c2043 100644 --- a/sys/dev/usb/xhcireg.h +++ b/sys/dev/usb/xhcireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: xhcireg.h,v 1.6 2014/12/08 13:32:34 mpi Exp $ */ +/* $OpenBSD: xhcireg.h,v 1.7 2014/12/15 17:10:44 mpi Exp $ */ /*- * Copyright (c) 2014 Martin Pieuchot. All rights reserved. @@ -26,12 +26,25 @@ * SUCH DAMAGE. */ -#ifndef _XHCIREG_H_ +#ifndef _XHCIREG_H_ #define _XHCIREG_H_ /* Default command execution time (implementation defined). */ #define XHCI_COMMAND_TIMEOUT 500 /* ms */ +/* Data Structure Boundary and Alignment Requirement. */ +#define XHCI_DCBAA_ALIGN 64 +#define XHCI_ICTX_ALIGN 64 +#define XHCI_SCTX_ALIGN 32 +#define XHCI_OCTX_ALIGN 32 +#define XHCI_XFER_RING_ALIGN 16 +#define XHCI_CMDS_RING_ALIGN 64 +#define XHCI_EVTS_RING_ALIGN 64 +#define XHCI_RING_BOUNDARY (64 * 1024) +#define XHCI_ERST_ALIGN 64 +#define XHCI_ERST_BOUNDARY 0 +#define XHCI_SPAD_TABLE_ALIGN 64 + /* XHCI PCI config registers */ #define PCI_CBMEM 0x10 /* configuration base MEM */ diff --git a/sys/dev/usb/xhcivar.h b/sys/dev/usb/xhcivar.h index 992d4239775..fad436ead25 100644 --- a/sys/dev/usb/xhcivar.h +++ b/sys/dev/usb/xhcivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: xhcivar.h,v 1.5 2014/10/30 18:25:08 mpi Exp $ */ +/* $OpenBSD: xhcivar.h,v 1.6 2014/12/15 17:10:44 mpi Exp $ */ /* * Copyright (c) 2014 Martin Pieuchot @@ -19,10 +19,19 @@ #ifndef _XHCIVAR_H_ #define _XHCIVAR_H_ -#define XHCI_MAX_COMMANDS (16 * 1) -#define XHCI_MAX_EVENTS (16 * 13) -#define XHCI_MAX_TRANSFERS (16 * 16) - +#define XHCI_MAX_CMDS (16 * 1) +#define XHCI_MAX_EVTS (16 * 13) +#define XHCI_MAX_XFER (16 * 16) + +struct usbd_dma_info { + bus_dma_tag_t tag; + bus_dmamap_t map; + bus_dma_segment_t seg; + int nsegs; + bus_addr_t paddr; + caddr_t vaddr; + bus_size_t size; +}; struct xhci_xfer { struct usbd_xfer xfer; @@ -33,7 +42,7 @@ struct xhci_xfer { struct xhci_ring { struct xhci_trb *trbs; size_t ntrb; - struct usb_dma dma; + struct usbd_dma_info dma; uint32_t index; uint32_t toggle; /* Producer/Consumer bit */ @@ -43,9 +52,9 @@ struct xhci_soft_dev { struct xhci_inctx *input_ctx; /* Input context */ struct xhci_sctx *slot_ctx; struct xhci_epctx *ep_ctx[31]; - struct usb_dma ictx_dma; + struct usbd_dma_info ictx_dma; - struct usb_dma octx_dma; /* Output context */ + struct usbd_dma_info octx_dma; /* Output context */ struct xhci_pipe *pipes[31]; }; @@ -53,22 +62,19 @@ struct xhci_soft_dev { /* Device context segment table. */ struct xhci_devctx { uint64_t *segs; /* at most USB_MAX_DEVICES+1 */ - size_t size; - struct usb_dma dma; + struct usbd_dma_info dma; }; /* Event ring segment table. */ struct xhci_erst { struct xhci_erseg *segs; /* One segment per event ring */ - size_t size; - struct usb_dma dma; + struct usbd_dma_info dma; }; struct xhci_scratchpad { - struct usb_dma table_dma; - struct usb_dma pages_dma; + struct usbd_dma_info table_dma; + struct usbd_dma_info pages_dma; int npage; - }; struct xhci_softc {