Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/nick-nhusb]: src/sys/dev/usb Deal with ZLP (zero length packets) properly
details: https://anonhg.NetBSD.org/src/rev/80acfc565991
branches: nick-nhusb
changeset: 334466:80acfc565991
user: skrll <skrll%NetBSD.org@localhost>
date: Fri Apr 01 14:20:05 2016 +0000
description:
Deal with ZLP (zero length packets) properly
diffstat:
sys/dev/usb/ohci.c | 107 ++++++++++++++++++++++++++++++++++------------------
1 files changed, 69 insertions(+), 38 deletions(-)
diffs (211 lines):
diff -r 9589903d5e36 -r 80acfc565991 sys/dev/usb/ohci.c
--- a/sys/dev/usb/ohci.c Fri Apr 01 14:17:24 2016 +0000
+++ b/sys/dev/usb/ohci.c Fri Apr 01 14:20:05 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ohci.c,v 1.254.2.67 2016/04/01 14:17:24 skrll Exp $ */
+/* $NetBSD: ohci.c,v 1.254.2.68 2016/04/01 14:20:05 skrll Exp $ */
/*
* Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.67 2016/04/01 14:17:24 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.68 2016/04/01 14:20:05 skrll Exp $");
#include "opt_usb.h"
@@ -546,8 +546,12 @@
DPRINTFN(8, "xfer %p nstd %d mps %d", xfer, nstd, mps, 0);
+ /*
+ * Assign next for the len == 0 case where we don't go through the
+ * main loop.
+ */
len = alen;
- cur = ohci_alloc_std(sc);
+ cur = next = ohci_alloc_std(sc);
if (cur == NULL)
goto nomem;
@@ -557,16 +561,24 @@
(rd ? OHCI_TD_IN : OHCI_TD_OUT) |
OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR);
- for (size_t j = 0;;) {
+ size_t curoffs = 0;
+ size_t j = 0;
+ for (; j < ox->ox_nstd && len != 0;) {
ox->ox_stds[j++] = cur;
next = ohci_alloc_std(sc);
if (next == NULL)
goto nomem;
-
- /* The OHCI hardware can handle at most one page crossing. */
- if (OHCI_PAGE(dataphys) == dataphysend ||
- OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) {
- /* we can handle it in this TD */
+ curlen = 0;
+ dataphys = DMAADDR(dma, curoffs);
+ dataphysend = DMAADDR(dma, curoffs + len - 1);
+
+ ohci_physaddr_t sphyspg = OHCI_PAGE(dataphys);
+ ohci_physaddr_t ephyspg = OHCI_PAGE(dataphysend);
+ /*
+ * The OHCI hardware can handle at most one page
+ * crossing per TD
+ */
+ if (sphyspg == ephyspg || sphyspg + 1 == ephyspg) {
curlen = len;
} else {
/* must use multiple TDs, fill as much as possible. */
@@ -574,8 +586,8 @@
(dataphys & (OHCI_PAGE_SIZE - 1));
/* the length must be a multiple of the max size */
curlen -= curlen % mps;
- KASSERT(curlen != 0);
}
+ KASSERT(curlen != 0);
DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x "
"len=%d curlen=%d", dataphys, dataphysend, len, curlen);
len -= curlen;
@@ -591,31 +603,37 @@
DPRINTFN(10, "cbp=0x%08x be=0x%08x", dataphys,
dataphys + curlen - 1, 0, 0);
- if (len == 0)
- break;
+
+ curoffs += curlen;
+ len -= curlen;
+
+ if (len != 0)
+ cur = next;
+
DPRINTFN(10, "extend chain", 0, 0, 0, 0);
- dataphys += curlen;
- cur = next;
}
- if (!rd && (flags & USBD_FORCE_SHORT_XFER) &&
- alen % mps == 0) {
+
+ /* Allocate a TD for a 0 length transfer at the end. */
+ if (!rd && (flags & USBD_FORCE_SHORT_XFER)) {
/* Force a 0 length transfer at the end. */
+ KASSERT(j < ox->ox_nstd);
+ KASSERT(next != NULL);
cur = next;
- next = ohci_alloc_std(sc);
- if (next == NULL)
- goto nomem;
+ ox->ox_stds[j++] = cur;
cur->td.td_flags = tdflags;
cur->td.td_cbp = 0; /* indicate 0 length packet */
- cur->td.td_nexttd = HTOO32(next->physaddr);
+ cur->td.td_nexttd = 0;
cur->td.td_be = ~0;
- cur->nexttd = next;
+ cur->nexttd = NULL;
cur->len = 0;
cur->flags = 0;
cur->xfer = xfer;
DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0);
+ } else {
+ ohci_free_std(sc, next);
}
return USBD_NORMAL_COMPLETION;
@@ -667,28 +685,38 @@
int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize);
+ /*
+ * Assign next for the len == 0 case where we don't go through the
+ * main loop.
+ */
len = alen;
- cur = sp;
-
- dataphys = DMAADDR(dma, 0);
- dataphysend = OHCI_PAGE(dataphys + len - 1);
+ cur = next = sp;
+
usb_syncmem(dma, 0, len,
rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
const uint32_t tdflags = HTOO32(
(rd ? OHCI_TD_IN : OHCI_TD_OUT) |
OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR);
- for (size_t j = 1;;) {
+ size_t curoffs = 0;
+ for (size_t j = 1; len != 0;) {
if (j == ox->ox_nstd)
next = NULL;
else
next = ox->ox_stds[j++];
KASSERT(next != cur);
- /* The OHCI hardware can handle at most one page crossing. */
- if (OHCI_PAGE(dataphys) == dataphysend ||
- OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) {
- /* we can handle it in this TD */
+ curlen = 0;
+ dataphys = DMAADDR(dma, curoffs);
+ dataphysend = DMAADDR(dma, curoffs + len - 1);
+
+ ohci_physaddr_t sphyspg = OHCI_PAGE(dataphys);
+ ohci_physaddr_t ephyspg = OHCI_PAGE(dataphysend);
+ /*
+ * The OHCI hardware can handle at most one page
+ * crossing per TD
+ */
+ if (sphyspg == ephyspg || sphyspg + 1 == ephyspg) {
curlen = len;
} else {
/* must use multiple TDs, fill as much as possible. */
@@ -696,8 +724,8 @@
(dataphys & (OHCI_PAGE_SIZE - 1));
/* the length must be a multiple of the max size */
curlen -= curlen % mps;
- KASSERT(curlen != 0);
}
+ KASSERT(curlen != 0);
DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x "
"len=%d curlen=%d", dataphys, dataphysend, len, curlen);
len -= curlen;
@@ -716,12 +744,15 @@
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
DPRINTFN(10, "cbp=0x%08x be=0x%08x", dataphys,
dataphys + curlen - 1, 0, 0);
- if (len == 0)
- break;
- KASSERT(next != NULL);
- DPRINTFN(10, "extend chain", 0, 0, 0, 0);
- dataphys += curlen;
- cur = next;
+
+ curoffs += curlen;
+ len -= curlen;
+
+ if (len != 0) {
+ KASSERT(next != NULL);
+ DPRINTFN(10, "extend chain", 0, 0, 0, 0);
+ cur = next;
+ }
}
cur->td.td_flags |=
(xfer->ux_flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0);
@@ -736,7 +767,7 @@
cur->td.td_flags = tdflags;
cur->td.td_cbp = 0; /* indicate 0 length packet */
- cur->td.td_nexttd = HTOO32(next->physaddr);
+ cur->td.td_nexttd = 0;
cur->td.td_be = ~0;
cur->nexttd = NULL;
cur->len = 0;
Home |
Main Index |
Thread Index |
Old Index