[coreboot] [SeaBIOS] USB Problems geode lx800

Christian Gmeiner christian.gmeiner at gmail.com
Tue Oct 16 16:11:08 CEST 2012


2012/10/15 Kevin O'Connor <kevin at koconnor.net>:
> On Sun, Oct 14, 2012 at 07:48:00PM +0000, Christian Gmeiner wrote:
>> On 11 Oct 2012 16:42, "Christian Gmeiner" <christian.gmeiner at gmail.com>
>> wrote:
>> > 2012/10/11 Christian Gmeiner <christian.gmeiner at gmail.com>:
>> > > 2012/10/11 Kevin O'Connor <kevin at koconnor.net>:
>> > >> On Tue, Oct 09, 2012 at 02:31:05PM +0200, Christian Gmeiner wrote:
>> > >>> 2012/10/9 Kevin O'Connor <kevin at koconnor.net>:
>> > >>> > On Mon, Oct 08, 2012 at 02:14:03PM +0200, Christian Gmeiner wrote:
>> > >>> >> HI all
>> > >>> >>
>> > >>> >> I am running into some usb problems with coreboot & seabios:
>> > >>> > Can you set the debug level to 8 and post the whole log?  Also, for
>> > >>> > timeout issues, having timestamps (via tools/readserial.py tool)
>> > >>> > sometimes helps.
> [...]
>> Kevin do you have an idea what could be wrong?
>
> I haven't had a chance to take a look at it.  Something odd is going
> on, as it appears the transfer that's failing isn't even being
> started.  I'll see if I can take a look this week.
>
> -Kevin

He Kevin,

I have made some success to get USB working - current SeaBios ehci
driver does not support toggling between
DATA0 and DATA1. Here is my current patch to get a little bit more running:

diff --git a/src/blockcmd.c b/src/blockcmd.c
index 77c690f..a66d7ed 100644
--- a/src/blockcmd.c
+++ b/src/blockcmd.c
@@ -189,6 +189,7 @@ scsi_init_drive(struct drive_s *drive, const char
*s, int prio)
 int
 cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
 {
+    dprintf(1, "%s\n", __func__);
     struct cdb_request_sense cmd;
     memset(&cmd, 0, sizeof(cmd));
     cmd.command = CDB_CMD_INQUIRY;
@@ -202,6 +203,7 @@ cdb_get_inquiry(struct disk_op_s *op, struct
cdbres_inquiry *data)
 int
 cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
 {
+    dprintf(1, "%s\n", __func__);
     struct cdb_request_sense cmd;
     memset(&cmd, 0, sizeof(cmd));
     cmd.command = CDB_CMD_REQUEST_SENSE;
@@ -215,6 +217,7 @@ cdb_get_sense(struct disk_op_s *op, struct
cdbres_request_sense *data)
 int
 cdb_test_unit_ready(struct disk_op_s *op)
 {
+    dprintf(1, "%s\n", __func__);
     struct cdb_request_sense cmd;
     memset(&cmd, 0, sizeof(cmd));
     cmd.command = CDB_CMD_TEST_UNIT_READY;
@@ -227,6 +230,7 @@ cdb_test_unit_ready(struct disk_op_s *op)
 int
 cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
 {
+    dprintf(1, "%s\n", __func__);
     struct cdb_read_capacity cmd;
     memset(&cmd, 0, sizeof(cmd));
     cmd.command = CDB_CMD_READ_CAPACITY;
diff --git a/src/usb-ehci.c b/src/usb-ehci.c
index 2676615..02463c7 100644
--- a/src/usb-ehci.c
+++ b/src/usb-ehci.c
@@ -204,6 +204,7 @@ ehci_waittick(struct usb_ehci_s *cntl)
         yield();
     }
     // Ring "doorbell"
+    dprintf(1, "ring 'doorbell'\n");
     writel(&cntl->regs->usbcmd, cmd | CMD_IAAD);
     // Wait for completion
     for (;;) {
@@ -217,6 +218,7 @@ ehci_waittick(struct usb_ehci_s *cntl)
         yield();
     }
     // Ack completion
+    dprintf(1, "Ack completion\n");
     writel(&cntl->regs->usbsts, STS_IAA);
 }

@@ -495,6 +497,9 @@ ehci_alloc_pipe(struct usbdevice_s *usbdev
         return usbpipe;
     }

+    /* initial value */
+    usbpipe->toogle = 0;
+
     // Allocate a new queue head.
     struct ehci_pipe *pipe;
     if (eptype == USB_ENDPOINT_XFER_CONTROL)
@@ -641,6 +646,34 @@ ehci_control(struct usb_pipe *p, int dir, const
void *cmd, int cmdsize
     return ret;
 }

+static int ehci_set_async_schedule(struct usb_ehci_s *ehcic, int enable)
+{
+    dprintf(7, "%s: enable %d\n", __func__, enable);
+
+    // Set async schedule status.
+    u32 cmd = readl(&ehcic->regs->usbcmd);
+    if (enable)
+        cmd |= CMD_ASE;
+    else
+        cmd &= ~CMD_ASE;
+
+    writel(&ehcic->regs->usbcmd, cmd);
+
+    /* Wait for the controller to accept async schedule status.
+     * This shouldn't take too long, but we should timeout nevertheless.
+     */
+    enable = enable ? STS_ASS : 0;
+    int timeout = 100; /* time out after 100ms */
+    while (((readl(&ehcic->regs->usbsts) & STS_ASS) != enable)
+            && timeout--)
+        mdelay(1);
+    if (timeout < 0) {
+        dprintf(7, "ehci async schedule status change timed out.\n");
+        return 1;
+    }
+    return 0;
+}
+
 #define STACKQTDS 4

 int
@@ -652,6 +685,12 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void
*data, int datasize)
     dprintf(7, "ehci_send_bulk qh=%p dir=%d data=%p size=%d\n"
             , &pipe->qh, dir, data, datasize);

+    struct usb_ehci_s *ehcic = container_of(
+        GET_LOWFLAT(pipe->pipe.cntl), struct usb_ehci_s, usb);
+
+    // stop async schedule
+    ehci_set_async_schedule(ehcic, 0);
+
     // Allocate 4 tds on stack (with required alignment)
     u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1];
     struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN);
@@ -661,12 +700,23 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void
*data, int datasize)

     u16 maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket);
     int tdpos = 0;
+    struct ehci_qtd *last = &tds[0];
+
+    int count = 0;
     while (datasize) {
         struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
+#if 0
         int ret = ehci_wait_td(pipe, td, 5000);
-        if (ret)
+        if (ret) {
+	    int i;
+	    for(i=0; i<STACKQTDS; i++)
+            {
+                dprintf(1, "td%d: q=%x a=%x t=%xn",
+                    i, tds[i].qtd_next, tds[i].alt_next, tds[i].token);
+            }
             return -1;
-
+	}
+#endif
         struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
                                                  , &tds[tdpos % STACKQTDS]);

@@ -679,15 +729,42 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void
*data, int datasize)

         data += transfer;
         datasize -= transfer;
+        last = td;
+        count++;
     }
+
+    dprintf(1, "added %d TDs\n", count);
+    dprintf(1, "ep%d toogle %d\n", pipe->pipe.ep, pipe->pipe.toogle);
+
+    /* update based on endpoint toggle */
+    tds[0].token  |= (pipe->pipe.toogle?QTD_TOGGLE:0);
+    pipe->qh.token|= (pipe->pipe.toogle?QTD_TOGGLE:0);
+
+
+    ehci_set_async_schedule(ehcic, 1);
+
     int i;
     for (i=0; i<STACKQTDS; i++) {
         struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
         int ret = ehci_wait_td(pipe, td, 5000);
-        if (ret)
-            return -1;
+
+        if (ret) {
+            int i;
+            for(i=0; i<STACKQTDS; i++)
+            {
+                dprintf(1, "b td%d: q=%x a=%x t=%x\n",
+                    i, tds[i].qtd_next, tds[i].alt_next, tds[i].token);
+            }
+        }
+
     }

+    /* update endpoint toggle based on device */
+    pipe->pipe.toogle = (last->token & QTD_TOGGLE) >> 31;
+
+    // stop async schedule
+    ehci_set_async_schedule(ehcic, 0);
+
     return 0;
 }

diff --git a/src/usb-ehci.h b/src/usb-ehci.h
index 32e4109..739dca8 100644
--- a/src/usb-ehci.h
+++ b/src/usb-ehci.h
@@ -163,6 +163,7 @@ struct ehci_qtd {
 #define QTD_STS_MMF     (1 << 2)
 #define QTD_STS_STS     (1 << 1)
 #define QTD_STS_PING    (1 << 0)
+#define QTD_STS_MASK    0xff

 #define ehci_explen(len) (((len) << QTD_LENGTH_SHIFT) & QTD_LENGTH_MASK)

diff --git a/src/usb-msc.c b/src/usb-msc.c
index 83c7397..002f54d 100644
--- a/src/usb-msc.c
+++ b/src/usb-msc.c
@@ -65,7 +65,7 @@ usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16
blocksize)
     if (!CONFIG_USB_MSC)
         return 0;

-    dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
+    dprintf(1, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
             , op->drive_g, 0, op->count, blocksize, op->buf_fl);
     struct usbdrive_s *udrive_g = container_of(
         op->drive_g, struct usbdrive_s, drive);
@@ -83,19 +83,29 @@ usb_cmd_data(struct disk_op_s *op, void *cdbcmd,
u16 blocksize)
     cbw.bCBWCBLength = USB_CDB_SIZE;

     // Transfer cbw to device.
+    dprintf(1, "cbw to device\n");
     int ret = usb_msc_send(udrive_g, USB_DIR_OUT
                            , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw));
     if (ret)
         goto fail;

     // Transfer data to/from device.
+    if ((cbw.bmCBWFlags & 0x80) == 0)
+    {
+        dprintf(1, "Data-Out from host to the device - %d bytes\n", bytes);
+    }
+    else
+    {
+        dprintf(1, "Data-In from the device to the host - %d bytes\n", bytes);
+    }
     if (bytes) {
         ret = usb_msc_send(udrive_g, cbw.bmCBWFlags, op->buf_fl, bytes);
         if (ret)
             goto fail;
     }

-    // Transfer csw info.
+    // Transfer csw info from device to host.
+    dprintf(1, "Transfer csw info.\n");
     struct csw_s csw;
     ret = usb_msc_send(udrive_g, USB_DIR_IN
                         , MAKE_FLATPTR(GET_SEG(SS), &csw), sizeof(csw));
diff --git a/src/usb.h b/src/usb.h
index a43e829..d272306 100644
--- a/src/usb.h
+++ b/src/usb.h
@@ -14,6 +14,7 @@ struct usb_pipe {
     u8 ep;
     u8 devaddr;
     u8 speed;
+    u8 toogle;
     u16 maxpacket;
     u8 eptype;
 };

The log matching this patch to 99% can be found here: http://dpaste.com/814237/

cdb_get_inquiry() works but cdb_test_unit_ready() fails...

---
Christian Gmeiner, MSc




More information about the coreboot mailing list