Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Fix the error check on completion of an xfer. J...



details:   https://anonhg.NetBSD.org/src/rev/ef2415e96918
branches:  trunk
changeset: 580622:ef2415e96918
user:      augustss <augustss%NetBSD.org@localhost>
date:      Sun May 01 19:24:39 2005 +0000

description:
Fix the error check on completion of an xfer.  Just because the qTD status
field has error bits set doesn't mean there has been an error, unless the
HALTED bit is set as well.  The old behaviour could result in a transfer
being considered failed by the software, but a success by the device.
This seems to have affected mostly mass storage devices.

Pointed out by Dan Ellis in kern/29731.

diffstat:

 sys/dev/usb/ehci.c    |  35 ++++++++++++++++++++++-------------
 sys/dev/usb/ehcireg.h |   4 ++--
 2 files changed, 24 insertions(+), 15 deletions(-)

diffs (99 lines):

diff -r 9e51a55f4999 -r ef2415e96918 sys/dev/usb/ehci.c
--- a/sys/dev/usb/ehci.c        Sun May 01 19:19:25 2005 +0000
+++ b/sys/dev/usb/ehci.c        Sun May 01 19:24:39 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ehci.c,v 1.97 2005/05/01 14:21:27 augustss Exp $ */
+/*     $NetBSD: ehci.c,v 1.98 2005/05/01 19:24:39 augustss Exp $ */
 
 /*
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -65,7 +65,7 @@
 */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.97 2005/05/01 14:21:27 augustss Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.98 2005/05/01 19:24:39 augustss Exp $");
 
 #include "ohci.h"
 #include "uhci.h"
@@ -809,10 +809,6 @@
                        break;
 
                status = nstatus;
-               /* halt is ok if descriptor is last, and complete */
-               if (sqtd->qtd.qtd_next == EHCI_NULL &&
-                   EHCI_QTD_GET_BYTES(status) == 0)
-                       status &= ~EHCI_QTD_HALTED;
                if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP)
                        actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);
        }
@@ -840,20 +836,18 @@
            UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);
        epipe->nexttoggle ^= pkts_left % 2;
 
-       status &= EHCI_QTD_STATERRS;
        DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n",
                           xfer->length, actlen, status));
        xfer->actlen = actlen;
-       if (status != 0) {
+       if (status & EHCI_QTD_HALTED) {
 #ifdef EHCI_DEBUG
                char sbuf[128];
 
                bitmask_snprintf((u_int32_t)status,
                                 "\20\7HALTED\6BUFERR\5BABBLE\4XACTERR"
-                                "\3MISSED", sbuf, sizeof(sbuf));
-
-               DPRINTFN((status == EHCI_QTD_HALTED) ? 2 : 0,
-                        ("ehci_idone: error, addr=%d, endpt=0x%02x, "
+                                "\3MISSED\1PINGSTATE", sbuf, sizeof(sbuf));
+
+               DPRINTFN(2, ("ehci_idone: error, addr=%d, endpt=0x%02x, "
                          "status 0x%s\n",
                          xfer->pipe->device->address,
                          xfer->pipe->endpoint->edesc->bEndpointAddress,
@@ -863,10 +857,25 @@
                        ehci_dump_sqtds(ex->sqtdstart);
                }
 #endif
-               if (status == EHCI_QTD_HALTED)
+               /* low&full speed has an extra error flag */
+               if (EHCI_QH_GET_EPS(epipe->sqh->qh.qh_endp) !=
+                   EHCI_QH_SPEED_HIGH)
+                       status &= EHCI_QTD_STATERRS | EHCI_QTD_PINGSTATE;
+               else
+                       status &= EHCI_QTD_STATERRS;
+               if (status == 0) /* no other errors means a stall */
                        xfer->status = USBD_STALLED;
                else
                        xfer->status = USBD_IOERROR; /* more info XXX */
+               /* XXX need to reset TT on missed microframe */
+               if (status & EHCI_QTD_MISSEDMICRO) {
+                       ehci_softc_t *sc = (ehci_softc_t *)
+                           xfer->pipe->device->bus;
+
+                       printf("%s: missed microframe, TT reset not "
+                           "implemented, hub might be inoperational\n",
+                           USBDEVNAME(sc->sc_bus.bdev));
+               }
        } else {
                xfer->status = USBD_NORMAL_COMPLETION;
        }
diff -r 9e51a55f4999 -r ef2415e96918 sys/dev/usb/ehcireg.h
--- a/sys/dev/usb/ehcireg.h     Sun May 01 19:19:25 2005 +0000
+++ b/sys/dev/usb/ehcireg.h     Sun May 01 19:24:39 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ehcireg.h,v 1.20 2005/03/02 11:37:27 mycroft Exp $     */
+/*     $NetBSD: ehcireg.h,v 1.21 2005/05/01 19:24:39 augustss Exp $    */
 
 /*
  * Copyright (c) 2001, 2004 The NetBSD Foundation, Inc.
@@ -215,7 +215,7 @@
 #define  EHCI_QTD_MISSEDMICRO  0x04
 #define  EHCI_QTD_SPLITXSTATE  0x02
 #define  EHCI_QTD_PINGSTATE    0x01
-#define  EHCI_QTD_STATERRS     0x7c
+#define  EHCI_QTD_STATERRS     0x3c
 #define EHCI_QTD_GET_PID(x)    (((x) >>  8) & 0x3)
 #define EHCI_QTD_SET_PID(x)    ((x) <<  8)
 #define  EHCI_QTD_PID_OUT      0x0



Home | Main Index | Thread Index | Old Index