Module Name: src Committed By: skrll Date: Mon May 25 13:55:31 UTC 2020
Modified Files: src/sys/dev/usb: uhci.c Log Message: Be more careful with transfer descriptors and crossing page boundaries Enable USBMALLOC_MULTISEG To generate a diff of this commit: cvs rdiff -u -r1.301 -r1.302 src/sys/dev/usb/uhci.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/uhci.c diff -u src/sys/dev/usb/uhci.c:1.301 src/sys/dev/usb/uhci.c:1.302 --- src/sys/dev/usb/uhci.c:1.301 Fri May 15 06:15:42 2020 +++ src/sys/dev/usb/uhci.c Mon May 25 13:55:31 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: uhci.c,v 1.301 2020/05/15 06:15:42 skrll Exp $ */ +/* $NetBSD: uhci.c,v 1.302 2020/05/25 13:55:31 skrll Exp $ */ /* * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc. @@ -42,7 +42,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.301 2020/05/15 06:15:42 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.302 2020/05/25 13:55:31 skrll Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -582,6 +582,7 @@ uhci_init(uhci_softc_t *sc) sc->sc_bus.ub_methods = &uhci_bus_methods; sc->sc_bus.ub_pipesize = sizeof(struct uhci_pipe); sc->sc_bus.ub_usedma = true; + sc->sc_bus.ub_dmaflags = USBMALLOC_MULTISEG; UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */ @@ -2009,6 +2010,17 @@ uhci_alloc_std_chain(uhci_softc_t *sc, s return EINVAL; } size_t ntd = howmany(len, maxp); + /* + * if our transfer is bigger than PAGE_SIZE and maxp not a factor of + * PAGE_SIZE then we will need another TD per page. + */ + if (len > PAGE_SIZE && (PAGE_SIZE % maxp) != 0) { + ntd += howmany(len, PAGE_SIZE); + } + + /* + * Might need one more TD if we're writing a ZLP + */ if (!rd && (flags & USBD_FORCE_SHORT_XFER)) { ntd++; } @@ -2080,7 +2092,7 @@ uhci_reset_std_chain(uhci_softc_t *sc, s int tog = *toggle; int maxp; uint32_t status; - size_t i; + size_t i, offs; UHCIHIST_FUNC(); UHCIHIST_CALLED(); DPRINTFN(8, "xfer=%#jx len %jd isread %jd toggle %jd", (uintptr_t)xfer, @@ -2102,9 +2114,15 @@ uhci_reset_std_chain(uhci_softc_t *sc, s usb_syncmem(dma, 0, len, isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); std = prev = NULL; - for (i = 0; len != 0 && i < uxfer->ux_nstd; i++, prev = std) { + for (offs = i = 0; len != 0 && i < uxfer->ux_nstd; i++, prev = std) { int l = len; std = uxfer->ux_stds[i]; + + const bus_addr_t sbp = DMAADDR(dma, offs); + const bus_addr_t ebp = DMAADDR(dma, offs + l - 1); + if (((sbp ^ ebp) & ~PAGE_MASK) != 0) + l = PAGE_SIZE - (DMAADDR(dma, offs) & PAGE_MASK); + if (l > maxp) l = maxp; @@ -2129,7 +2147,7 @@ uhci_reset_std_chain(uhci_softc_t *sc, s UHCI_TD_SET_DT(tog) | UHCI_TD_SET_MAXLEN(l) ); - std->td.td_buffer = htole32(DMAADDR(dma, i * maxp)); + std->td.td_buffer = htole32(DMAADDR(dma, offs)); std->link.std = NULL; @@ -2137,6 +2155,7 @@ uhci_reset_std_chain(uhci_softc_t *sc, s BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); tog ^= 1; + offs += l; len -= l; } KASSERTMSG(len == 0, "xfer %p alen %d len %d mps %d ux_nqtd %zu i %zu", @@ -2933,17 +2952,20 @@ uhci_device_isoc_transfer(struct usbd_xf xfer->ux_status = USBD_IN_PROGRESS; ux->ux_curframe = next; - buf = DMAADDR(&xfer->ux_dmabuf, 0); offs = 0; status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) | UHCI_TD_ACTIVE | UHCI_TD_IOS); nframes = xfer->ux_nframes; for (i = 0; i < nframes; i++) { + buf = DMAADDR(&xfer->ux_dmabuf, offs); std = isoc->stds[next]; if (++next >= UHCI_VFRAMELIST_COUNT) next = 0; len = xfer->ux_frlengths[i]; + + KASSERTMSG(len <= __SHIFTOUT_MASK(UHCI_TD_MAXLEN_MASK), + "len %d", len); std->td.td_buffer = htole32(buf); usb_syncmem(&xfer->ux_dmabuf, offs, len, rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); @@ -2962,8 +2984,11 @@ uhci_device_isoc_transfer(struct usbd_xf DPRINTF("--- dump end ---", 0, 0, 0, 0); } #endif - buf += len; offs += len; + const bus_addr_t bend __diagused = + DMAADDR(&xfer->ux_dmabuf, offs - 1); + + KASSERT(((buf ^ bend) & ~PAGE_MASK) == 0); } isoc->next = next; isoc->inuse += xfer->ux_nframes;