Port-arm archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: panic when using mpd on evbarm/kirkwood
Hi,
> please type 'tr' here and report. This will tell us what is using
> the pool in interrupt context.
This is the whole trace:
panic: pool 'pvepl' is IPL_NONE, but called from interrupt context
Stopped in pid 0.3 (system) at netbsd:cpu_Debugger+0x4: bx r14
db> tr
netbsd:vpanic+0x10
scp=0xc021e170 rlv=0xc021e3fc (netbsd:printf_nolog)
rsp=0xc9fc3cfc rfp=0xc9fc3d10
r7=0x00000002
netbsd:panic+0x14
scp=0xc021e3e8 rlv=0xc0219b28 (netbsd:pool_get+0x214)
rsp=0xc9fc3d24 rfp=0xc9fc3d50
netbsd:pool_get+0x10
scp=0xc0219924 rlv=0xc01a8f08 (netbsd:pmap_enter+0x6e8)
rsp=0xc9fc3d54 rfp=0xc9fc3da4
r10=0xc04b0640 r9=0x01251552
r8=0x00000000 r7=0x0000000f r6=0xcacb7000 r5=0xc104510c
r4=0xc04b0640
netbsd:pmap_enter+0x10
scp=0xc01a8830 rlv=0xc0024d24 (netbsd:_bus_dmamem_map+0xe8)
rsp=0xc9fc3da8 rfp=0xc9fc3de4
r10=0xc04b0640 r9=0x00000004
r8=0xc04bae20 r7=0x00001000 r6=0xc19fb798 r5=0xcacb7000
r4=0x01251000
netbsd:_bus_dmamem_map+0x10
scp=0xc0024c4c rlv=0xc02ac828 (netbsd:usb_block_allocmem+0x188)
rsp=0xc9fc3de8 rfp=0xc9fc3e24
r10=0x00000001 r9=0xc9fc3e9c
r8=0x00000000 r7=0xc19fb78c r6=0x00001000 r5=0x00001000
r4=0xc04a02f4
netbsd:usb_block_allocmem+0x10
scp=0xc02ac6b0 rlv=0xc02ac914 (netbsd:usb_allocmem+0x3c)
rsp=0xc9fc3e28 rfp=0xc9fc3e68
r10=0x00000009 r9=0xcacb6be0
r8=0x00000630 r7=0xc9fc3e9c r6=0xc04a02f4 r5=0xc19f0b8c
r4=0x00000000
netbsd:usb_allocmem+0x10
scp=0xc02ac8e8 rlv=0xc005b8d4 (netbsd:ehci_device_fs_isoc_start+0x178)
rsp=0xc9fc3e6c rfp=0xc9fc3ecc
r10=0x00000009 r9=0xcacb6be0
r8=0x00000630 r7=0xc1b3df14 r6=0xc1aa6008 r5=0xc19f0b8c
r4=0x00000000
netbsd:ehci_device_fs_isoc_start+0x10
scp=0xc005b76c rlv=0xc02af638 (netbsd:usbd_transfer+0xd4)
rsp=0xc9fc3ed0 rfp=0xc9fc3ef8
r10=0xc1b3df50 r9=0xc1aa6008
r8=0x00000001 r7=0x00000000 r6=0x00000000 r5=0xc21a3a9c
r4=0xc1b3df14
netbsd:usbd_transfer+0x10
scp=0xc02af574 rlv=0xc026b254 (netbsd:uaudio_chan_pintr+0xb4)
rsp=0xc9fc3efc rfp=0xc9fc3f1c
r10=0x00000001 r9=0xc1aa6008
r8=0x00000000 r7=0x00000000 r6=0x00000000 r5=0xc1b3c898
r4=0xc1b3c820
netbsd:uaudio_chan_pintr+0x10
scp=0xc026b1b0 rlv=0xc02b00cc (netbsd:usb_transfer_complete+0x29c)
rsp=0xc9fc3f20 rfp=0xc9fc3f44
r5=0xc21a3a9c r4=0xc1b3d8f4
netbsd:usb_transfer_complete+0x10
scp=0xc02afe40 rlv=0xc0058f54 (netbsd:ehci_softintr+0x1f4)
rsp=0xc9fc3f48 rfp=0xc9fc3f74
r10=0xc1b3d814 r8=0xc1b3d8f4
r7=0x00000000 r6=0xc03b3148 r5=0xc9fc0154 r4=0xcacb6640
netbsd:ehci_softintr+0x10
scp=0xc0058d70 rlv=0xc0128370 (netbsd:softint_thread+0xb0)
rsp=0xc9fc3f78 rfp=0xc9fc3fb0
r10=0xc03465d0 r9=0x00000226
r8=0xc19f9a80 r7=0x00000000 r6=0xc03b3148 r5=0xc9fc0154
r4=0xc9fc02b4
netbsd:softint_thread+0x10
scp=0xc01282d0 rlv=0xc003fc54 (netbsd:lwp_trampoline+0x14)
rsp=0xc9fc3fb4 rfp=0x00000000
r10=0x00000000 r9=0x00000000
r8=0x00000000 r7=0xbfffffff r6=0xffffffff r5=0xc9fc0154
r4=0xc01282c0
db>
It seems to me that it is related to the patch: ehci_device_fs_isoc_start() is
indeed an addition brung by the isochronous TT patch.
I've attached the patch to this email. It is basically the patch that Masao
kindly provided me and that was initially against a 3+ years old codebase.
I *guess* the patch does not handle memory allocation properly with the modern
codebase...
Thanks !
--
Sebastien
Index: ehci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehci.c,v
retrieving revision 1.183
diff -u -r1.183 ehci.c
--- ehci.c 23 Dec 2011 00:51:43 -0000 1.183
+++ ehci.c 24 Mar 2013 18:04:25 -0000
@@ -98,6 +98,7 @@
union {
ehci_soft_qtd_t *qtd;
/* ehci_soft_itd_t *itd; */
+ /* ehci_soft_sitd_t *sitd; */
} tail;
union {
/* Control pipe */
@@ -129,6 +130,7 @@
Static void ehci_check_intr(ehci_softc_t *, struct ehci_xfer *);
Static void ehci_check_qh_intr(ehci_softc_t *, struct ehci_xfer *);
Static void ehci_check_itd_intr(ehci_softc_t *, struct ehci_xfer *);
+Static void ehci_check_sitd_intr(ehci_softc_t *, struct ehci_xfer
*);
Static void ehci_idone(struct ehci_xfer *);
Static void ehci_timeout(void *);
Static void ehci_timeout_task(void *);
@@ -176,6 +178,12 @@
Static void ehci_device_isoc_close(usbd_pipe_handle);
Static void ehci_device_isoc_done(usbd_xfer_handle);
+Static usbd_status ehci_device_fs_isoc_transfer(usbd_xfer_handle);
+Static usbd_status ehci_device_fs_isoc_start(usbd_xfer_handle);
+Static void ehci_device_fs_isoc_abort(usbd_xfer_handle);
+Static void ehci_device_fs_isoc_close(usbd_pipe_handle);
+Static void ehci_device_fs_isoc_done(usbd_xfer_handle);
+
Static void ehci_device_clear_toggle(usbd_pipe_handle pipe);
Static void ehci_noop(usbd_pipe_handle pipe);
@@ -194,9 +202,12 @@
ehci_soft_qtd_t *);
Static ehci_soft_itd_t *ehci_alloc_itd(ehci_softc_t *sc);
+Static ehci_soft_sitd_t *ehci_alloc_sitd(ehci_softc_t *sc);
Static void ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd);
+Static void ehci_free_sitd(ehci_softc_t *sc, ehci_soft_sitd_t *);
Static void ehci_rem_free_itd_chain(ehci_softc_t *sc,
struct ehci_xfer *exfer);
+Static void ehci_rem_free_sitd_chain(ehci_softc_t *sc,
struct
ehci_xfer *exfer);
Static void ehci_abort_isoc_xfer(usbd_xfer_handle xfer,
usbd_status status);
@@ -309,6 +320,15 @@
ehci_device_isoc_done,
};
+Static const struct usbd_pipe_methods ehci_device_fs_isoc_methods = {
+ ehci_device_fs_isoc_transfer,
+ ehci_device_fs_isoc_start,
+ ehci_device_fs_isoc_abort,
+ ehci_device_fs_isoc_close,
+ ehci_noop,
+ ehci_device_fs_isoc_done,
+};
+
static const uint8_t revbits[EHCI_MAX_POLLRATE] = {
0x00,0x40,0x20,0x60,0x10,0x50,0x30,0x70,0x08,0x48,0x28,0x68,0x18,0x58,0x38,0x78,
0x04,0x44,0x24,0x64,0x14,0x54,0x34,0x74,0x0c,0x4c,0x2c,0x6c,0x1c,0x5c,0x3c,0x7c,
@@ -436,6 +456,7 @@
if (sc->sc_softitds == NULL)
return ENOMEM;
LIST_INIT(&sc->sc_freeitds);
+ LIST_INIT(&sc->sc_freesitds);
TAILQ_INIT(&sc->sc_intrhead);
mutex_init(&sc->sc_intrhead_lock, MUTEX_DEFAULT, IPL_USB);
@@ -724,13 +745,18 @@
ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
{
int attr;
+ usbd_device_handle dev;
DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex));
attr = ex->xfer.pipe->endpoint->edesc->bmAttributes;
- if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS)
- ehci_check_itd_intr(sc, ex);
- else
+ dev = ex->xfer.pipe->device;
+ if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) {
+ if (dev->speed == USB_SPEED_HIGH)
+ ehci_check_itd_intr(sc, ex);
+ else
+ ehci_check_sitd_intr(sc, ex);
+ } else
ehci_check_qh_intr(sc, ex);
return;
@@ -844,6 +870,43 @@
ehci_idone(ex);
}
+void
+ehci_check_sitd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) {
+ ehci_soft_sitd_t *sitd;
+
+ if (&ex->xfer != SIMPLEQ_FIRST(&ex->xfer.pipe->queue))
+ return;
+
+ if (ex->sitdstart == NULL) {
+ printf("ehci_check_sitd_intr: not valid sitd\n");
+ return;
+ }
+
+ sitd = ex->sitdend;
+#ifdef DIAGNOSTIC
+ if (sitd == NULL) {
+ printf("ehci_check_sitd_intr: sitdend == 0\n");
+ return;
+ }
+#endif
+
+ /*
+ * check no active transfers in last sitd, meaning we're finished
+ */
+
+ usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_buffer),
+ sizeof(sitd->sitd.sitd_buffer), BUS_DMASYNC_POSTWRITE |
+ BUS_DMASYNC_POSTREAD);
+
+ if (le32toh(sitd->sitd.sitd_trans) & EHCI_SITD_ACTIVE)
+ return;
+
+ DPRINTFN(12, ("ehci_check_sitd_intr: ex=%p done\n", ex));
+ callout_stop(&(ex->xfer.timeout_handle));
+ ehci_idone(ex);
+}
+
+
Static void
ehci_idone(struct ehci_xfer *ex)
{
@@ -885,9 +948,13 @@
/* The transfer is done, compute actual length and status. */
- if (UE_GET_XFERTYPE(xfer->pipe->endpoint->edesc->bmAttributes)
- == UE_ISOCHRONOUS) {
- /* Isoc transfer */
+ u_int xfertype, speed;
+
+ xfertype = UE_GET_XFERTYPE(xfer->pipe->endpoint->edesc->bmAttributes);
+ speed = xfer->pipe->device->speed;
+ if (xfertype == UE_ISOCHRONOUS && speed == USB_SPEED_HIGH) {
+ /* HS isoc transfer */
+
struct ehci_soft_itd *itd;
int i, nframes, len, uframes;
@@ -930,6 +997,53 @@
goto end;
}
+ if (xfertype == UE_ISOCHRONOUS && speed == USB_SPEED_FULL) {
+ /* FS isoc transfer */
+ struct ehci_soft_sitd *sitd;
+ int nframes, len;
+
+ nframes = 0;
+ actlen = 0;
+
+ for (sitd = ex->sitdstart; sitd != NULL; sitd =
sitd->xfer_next) {
+ usb_syncmem(&sitd->dma,sitd->offs +
offsetof(ehci_sitd_t, sitd_buffer),
+ sizeof(sitd->sitd.sitd_buffer),
BUS_DMASYNC_POSTWRITE |
+ BUS_DMASYNC_POSTREAD);
+
+ /* XXX - driver didn't fill in the frame full
+ * of uframes. This leads to scheduling
+ * inefficiencies, but working around
+ * this doubles complexity of tracking
+ * an xfer.
+ */
+ if (nframes >= xfer->nframes)
+ break;
+
+ status = le32toh(sitd->sitd.sitd_trans);
+ len = EHCI_SITD_GET_LEN(status);
+ if (status & (EHCI_SITD_ERR|EHCI_SITD_BUFERR|
+ EHCI_SITD_BABBLE|EHCI_SITD_XACTERR|EHCI_SITD_MISS))
{
+ /* No valid data on error */
+ len = xfer->frlengths[nframes];
+ }
+
+ /*
+ * frlengths[i]: # of bytes to send
+ * len: # of bytes host didn't send
+ */
+ xfer->frlengths[nframes] -= len;
+ /* frlengths[i]: # of bytes host sent */
+ actlen += xfer->frlengths[nframes++];
+
+ if (nframes >= xfer->nframes)
+ break;
+ }
+
+ xfer->actlen = actlen;
+ xfer->status = USBD_NORMAL_COMPLETION;
+ goto end;
+ }
+
/* Continue processing xfers using queue heads */
lsqtd = ex->sqtdend;
@@ -1594,14 +1708,7 @@
case USB_SPEED_HIGH: speed = EHCI_QH_SPEED_HIGH; break;
default: panic("ehci_open: bad device speed %d", dev->speed);
}
- if (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_ISOCHRONOUS) {
- aprint_error_dev(sc->sc_dev, "error opening low/full speed "
- "isoc endpoint.\n");
- aprint_normal_dev(sc->sc_dev, "a low/full speed device is "
- "attached to a USB2 hub, and transaction translations are "
- "not yet supported.\n");
- aprint_normal_dev(sc->sc_dev, "reattach the device to the "
- "root hub instead.\n");
+ if (speed == EHCI_QH_SPEED_LOW && xfertype == UE_ISOCHRONOUS) {
DPRINTFN(1,("ehci_open: hshubaddr=%d hshubport=%d\n",
hshubaddr, hshubport));
return USBD_INVAL;
@@ -1697,7 +1804,10 @@
goto bad;
break;
case UE_ISOCHRONOUS:
- pipe->methods = &ehci_device_isoc_methods;
+ if (speed == EHCI_QH_SPEED_HIGH)
+ pipe->methods = &ehci_device_isoc_methods;
+ else
+ pipe->methods = &ehci_device_fs_isoc_methods;
if (ed->bInterval == 0 || ed->bInterval > 16) {
printf("ehci: opening pipe with invalid bInterval\n");
err = USBD_INVAL;
@@ -1893,6 +2003,56 @@
exfer->itdend = NULL;
}
+/*Call at splusb*/
+void
+ehci_rem_free_sitd_chain(ehci_softc_t *sc, struct ehci_xfer *exfer)
+{
+ struct ehci_soft_sitd *sitd, *prev;
+
+ prev = NULL;
+
+ if (exfer->sitdstart == NULL || exfer->sitdend == NULL)
+ panic("ehci isoc xfer being freed, but with no sitd chain\n");
+
+ for (sitd = exfer->sitdstart; sitd != NULL; sitd = sitd->xfer_next) {
+ prev = sitd->u.frame_list.prev;
+ /* Unlink sitd from hardware chain, or frame array */
+ if (prev == NULL) { /* We're at the table head */
+ sc->sc_softsitds[sitd->slot] = sitd->u.frame_list.next;
+ sc->sc_flist[sitd->slot] = sitd->sitd.sitd_next;
+ usb_syncmem(&sc->sc_fldma,
+ sizeof(ehci_link_t) * sitd->slot,
+ sizeof(ehci_link_t),
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ if (sitd->u.frame_list.next != NULL)
+ sitd->u.frame_list.next->u.frame_list.prev =
NULL;
+ } else {
+ /* XXX this part is untested... */
+ prev->sitd.sitd_next = sitd->sitd.sitd_next;
+ usb_syncmem(&sitd->dma,
+ sitd->offs + offsetof(ehci_sitd_t, sitd_next),
+ sizeof(sitd->sitd.sitd_next), BUS_DMASYNC_PREWRITE);
+
+ prev->u.frame_list.next = sitd->u.frame_list.next;
+ if (sitd->u.frame_list.next != NULL)
+ sitd->u.frame_list.next->u.frame_list.prev =
prev;
+ }
+ }
+
+ prev = NULL;
+ for (sitd = exfer->sitdstart; sitd != NULL; sitd = sitd->xfer_next) {
+ if (prev != NULL)
+ ehci_free_sitd(sc, prev);
+ prev = sitd;
+ }
+ if (prev)
+ ehci_free_sitd(sc, prev);
+ exfer->sitdstart = NULL;
+ exfer->sitdend = NULL;
+}
+
+
/***********/
/*
@@ -2853,6 +3013,70 @@
return itd;
}
+Static ehci_soft_sitd_t *
+ehci_alloc_sitd(ehci_softc_t *sc)
+{
+ struct ehci_soft_sitd *sitd, *freesitd;
+ usbd_status err;
+ int i, s, offs, frindex, previndex;
+ usb_dma_t dma;
+
+ s = splusb();
+
+ /* Find an sitd that wasn't freed this frame or last frame. This can
+ * discard sitds that were freed before frindex wrapped around
+ * XXX - can this lead to thrashing? Could fix by enabling wrap-around
+ * interrupt and fiddling with list when that happens */
+ frindex = (EOREAD4(sc, EHCI_FRINDEX) + 1) >> 3;
+ previndex = (frindex != 0) ? frindex - 1 : sc->sc_flsize;
+
+ freesitd = NULL;
+ LIST_FOREACH(sitd, &sc->sc_freesitds, u.free_list) {
+ if (sitd == NULL)
+ break;
+ if (sitd->slot != frindex && sitd->slot != previndex) {
+ freesitd = sitd;
+ break;
+ }
+ }
+
+ if (freesitd == NULL) {
+ DPRINTFN(2, ("ehci_alloc_sitd allocating chunk\n"));
+ err = usb_allocmem(&sc->sc_bus, EHCI_SITD_SIZE *
EHCI_SITD_CHUNK,
+ EHCI_PAGE_SIZE, &dma);
+
+ if (err) {
+ DPRINTF(("ehci_alloc_sitd, alloc returned %d\n", err));
+ return NULL;
+ }
+
+ for (i = 0; i < EHCI_SITD_CHUNK; i++) {
+ offs = i * EHCI_SITD_SIZE;
+ sitd = KERNADDR(&dma, offs);
+ sitd->physaddr = DMAADDR(&dma, offs);
+ sitd->dma = dma;
+ sitd->offs = offs;
+ LIST_INSERT_HEAD(&sc->sc_freesitds, sitd, u.free_list);
+ }
+ freesitd = LIST_FIRST(&sc->sc_freesitds);
+ }
+
+ sitd = freesitd;
+ LIST_REMOVE(sitd, u.free_list);
+ memset(&sitd->sitd, 0, sizeof(ehci_sitd_t));
+ usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_next),
+ sizeof(sitd->sitd.sitd_next), BUS_DMASYNC_PREWRITE |
+ BUS_DMASYNC_PREREAD);
+
+ sitd->u.frame_list.next = NULL;
+ sitd->u.frame_list.prev = NULL;
+ sitd->xfer_next = NULL;
+ sitd->slot = 0;
+ splx(s);
+
+ return sitd;
+}
+
Static void
ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd)
{
@@ -2863,6 +3087,16 @@
splx(s);
}
+Static void
+ehci_free_sitd(ehci_softc_t *sc, ehci_soft_sitd_t *sitd)
+{
+ int s;
+
+ s = splusb();
+ LIST_INSERT_HEAD(&sc->sc_freesitds, sitd, u.free_list);
+ splx(s);
+}
+
/****************/
/*
@@ -3053,6 +3287,7 @@
struct ehci_xfer *exfer;
ehci_softc_t *sc;
struct ehci_soft_itd *itd;
+ struct ehci_soft_sitd *sitd;
int s, i, wake;
epipe = (struct ehci_pipe *) xfer->pipe;
@@ -3108,6 +3343,21 @@
sizeof(itd->itd.itd_ctl),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
}
+ for (sitd = exfer->sitdstart; sitd != NULL; sitd = sitd->xfer_next) {
+ usb_syncmem(&sitd->dma,
+ sitd->offs + offsetof(ehci_sitd_t, sitd_buffer),
+ sizeof(sitd->sitd.sitd_buffer),
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+
+ trans_status = le32toh(sitd->sitd.sitd_trans);
+ trans_status &= ~EHCI_SITD_ACTIVE;
+ sitd->sitd.sitd_trans = htole32(trans_status);
+
+ usb_syncmem(&sitd->dma,
+ sitd->offs + offsetof(ehci_sitd_t, sitd_buffer),
+ sizeof(sitd->sitd.sitd_buffer),
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+ }
splx(s);
s = splusb();
@@ -4156,3 +4406,320 @@
BUS_DMASYNC_POSTREAD);
}
+
+Static usbd_status
+ehci_device_fs_isoc_transfer(usbd_xfer_handle xfer)
+{
+ usbd_status err;
+
+ err = usb_insert_transfer(xfer);
+ if (err && err != USBD_IN_PROGRESS)
+ return err;
+
+ return ehci_device_fs_isoc_start(xfer);
+}
+
+Static usbd_status
+ehci_device_fs_isoc_start(usbd_xfer_handle xfer)
+{
+ struct ehci_pipe *epipe;
+ usbd_device_handle dev;
+ ehci_softc_t *sc;
+ struct ehci_xfer *exfer;
+ ehci_soft_sitd_t *sitd, *prev, *start, *stop;
+ usb_dma_t *dma_buf;
+ int i, j, k, frames;
+ int s, offs, total_length;
+ int frindex;
+ u_int huba, dir;
+
+ start = NULL;
+ prev = NULL;
+ sitd = NULL;
+ total_length = 0;
+ exfer = (struct ehci_xfer *) xfer;
+ sc = xfer->pipe->device->bus->hci_private;
+ dev = xfer->pipe->device;
+ epipe = (struct ehci_pipe *)xfer->pipe;
+
+ /*
+ * To allow continuous transfers, above we start all transfers
+ * immediately. However, we're still going to get usbd_start_next call
+ * this when another xfer completes. So, check if this is already
+ * in progress or not
+ */
+
+ if (exfer->sitdstart != NULL)
+ return USBD_IN_PROGRESS;
+
+ DPRINTFN(2, ("ehci_device_fs_isoc_start: xfer %p len %d flags %d\n",
+ xfer, xfer->length, xfer->flags));
+
+ if (sc->sc_dying)
+ return USBD_IOERROR;
+
+ /*
+ * To avoid complication, don't allow a request right now that'll span
+ * the entire frame table. To within 4 frames, to allow some leeway
+ * on either side of where the hc currently is.
+ */
+ if (epipe->pipe.endpoint->edesc->bInterval *
+ xfer->nframes >= sc->sc_flsize - 4) {
+ printf("ehci: isoc descriptor requested that spans the entire
frametable, too many frames\n");
+ return USBD_INVAL;
+ }
+
+#ifdef DIAGNOSTIC
+ if (xfer->rqflags & URQ_REQUEST)
+ panic("ehci_device_fs_isoc_start: request\n");
+
+ if (!exfer->isdone)
+ printf("ehci_device_fs_isoc_start: not done, ex = %p\n", exfer);
+ exfer->isdone = 0;
+#endif
+
+ /*
+ * Step 1: Allocate and initialize sitds.
+ */
+
+ i = epipe->pipe.endpoint->edesc->bInterval;
+ if (i > 16 || i == 0) {
+ /* Spec page 271 says intervals > 16 are invalid */
+ DPRINTF(("ehci_device_fs_isoc_start: bInvertal %d invalid\n",
i));
+ return USBD_INVAL;
+ }
+
+ frames = xfer->nframes;
+
+ if (frames == 0) {
+ DPRINTF(("ehci_device_fs_isoc_start: frames == 0\n"));
+ return USBD_INVAL;
+ }
+
+ dma_buf = &xfer->dmabuf;
+ offs = 0;
+
+ for (i = 0; i < frames; i++) {
+ sitd = ehci_alloc_sitd(sc);
+
+ if (prev)
+ prev->xfer_next = sitd;
+ else
+ start = sitd;
+
+#ifdef DIAGNOSTIC
+ if (xfer->frlengths[i] > 0x3ff) {
+ printf("ehci: invalid frame length\n");
+ xfer->frlengths[i] = 0x3ff;
+ }
+#endif
+
+ sitd->sitd.sitd_trans = htole32(EHCI_SITD_ACTIVE |
+ EHCI_SITD_SET_LEN(xfer->frlengths[i]));
+
+ /* Set page0 index and offset. */
+ sitd->sitd.sitd_buffer[0] = htole32(DMAADDR(dma_buf, offs));
+
+ total_length += xfer->frlengths[i];
+ offs += xfer->frlengths[i];
+
+ sitd->sitd.sitd_buffer[1] =
+ htole32(EHCI_SITD_SET_BPTR(DMAADDR(dma_buf, offs - 1)));
+
+ huba = dev->myhsport->parent->address;
+
+/* if (sc->sc_flags & EHCIF_FREESCALE) {
+ // Set hub address to 0 if embedded TT is used.
+ if (huba == sc->sc_addr)
+ huba = 0;
+ }
+*/
+
+ k = epipe->pipe.endpoint->edesc->bEndpointAddress;
+ dir = UE_GET_DIR(k) ? 1 : 0;
+ sitd->sitd.sitd_endp =
+ htole32(EHCI_SITD_SET_ENDPT(UE_GET_ADDR(k)) |
+ EHCI_SITD_SET_DADDR(dev->address) |
+ EHCI_SITD_SET_PORT(dev->myhsport->portno) |
+ EHCI_SITD_SET_HUBA(huba) |
+ EHCI_SITD_SET_DIR(dir));
+
+ sitd->sitd.sitd_back = htole32(EHCI_LINK_TERMINATE);
+
+ /* XXX */
+ u_char sa, sb;
+ u_int temp, tlen;
+ sa = 0;
+
+ if (dir == 0) { /* OUT */
+ temp = 0;
+ tlen = xfer->frlengths[i];
+ if (tlen <= 188) {
+ temp |= 1; /* T-count = 1, TP = ALL */
+ tlen = 1;
+ } else {
+ tlen += 187;
+ tlen /= 188;
+ temp |= tlen; /* T-count = [1..6] */
+ temp |= 8; /* TP = Begin */
+ }
+ sitd->sitd.sitd_buffer[1] |= htole32(temp);
+
+ tlen += sa;
+
+ if (tlen >= 8) {
+ sb = 0;
+ } else {
+ sb = (1 << tlen);
+ }
+
+ sa = (1 << sa);
+ sa = (sb - sa) & 0x3F;
+ sb = 0;
+ } else {
+ sb = (-(4 << sa)) & 0xFE;
+ sa = (1 << sa) & 0x3F;
+ sa = 0x01;
+ sb = 0xfc;
+ }
+
+ sitd->sitd.sitd_sched = htole32(EHCI_SITD_SET_SMASK(sa) |
+ EHCI_SITD_SET_CMASK(sb));
+
+ prev = sitd;
+ } /* End of frame */
+
+ sitd->sitd.sitd_trans |= htole32(EHCI_SITD_IOC);
+
+ stop = sitd;
+ stop->xfer_next = NULL;
+ exfer->isoc_len = total_length;
+
+ usb_syncmem(&exfer->xfer.dmabuf, 0, total_length,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Part 2: Transfer descriptors have now been set up, now they must
+ * be scheduled into the periodic frame list. Erk. Not wanting to
+ * complicate matters, transfer is denied if the transfer spans
+ * more than the period frame list.
+ */
+
+ s = splusb();
+
+ /* Start inserting frames */
+ if (epipe->u.isoc.cur_xfers > 0) {
+ frindex = epipe->u.isoc.next_frame;
+ } else {
+ frindex = EOREAD4(sc, EHCI_FRINDEX);
+ frindex = frindex >> 3; /* Erase microframe index */
+ frindex += 2;
+ }
+
+ if (frindex >= sc->sc_flsize)
+ frindex &= (sc->sc_flsize - 1);
+
+ /* Whats the frame interval? */
+ i = epipe->pipe.endpoint->edesc->bInterval;
+
+ sitd = start;
+ for (j = 0; j < frames; j++) {
+ if (sitd == NULL)
+ panic("ehci: unexpectedly ran out of isoc sitds\n");
+
+ sitd->sitd.sitd_next = sc->sc_flist[frindex];
+ if (sitd->sitd.sitd_next == 0)
+ /* FIXME: frindex table gets initialized to NULL
+ * or EHCI_NULL? */
+ sitd->sitd.sitd_next = EHCI_NULL;
+
+ usb_syncmem(&sitd->dma,
+ sitd->offs + offsetof(ehci_sitd_t, sitd_next),
+ sizeof(ehci_sitd_t),
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ sc->sc_flist[frindex] =
+ htole32(EHCI_LINK_SITD | sitd->physaddr);
+
+ usb_syncmem(&sc->sc_fldma,
+ sizeof(ehci_link_t) * frindex,
+ sizeof(ehci_link_t),
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ sitd->u.frame_list.next = sc->sc_softsitds[frindex];
+ sc->sc_softsitds[frindex] = sitd;
+ if (sitd->u.frame_list.next != NULL)
+ sitd->u.frame_list.next->u.frame_list.prev = sitd;
+ sitd->slot = frindex;
+ sitd->u.frame_list.prev = NULL;
+
+ frindex += i;
+ if (frindex >= sc->sc_flsize)
+ frindex -= sc->sc_flsize;
+
+ sitd = sitd->xfer_next;
+ }
+
+ epipe->u.isoc.cur_xfers++;
+ epipe->u.isoc.next_frame = frindex;
+
+ exfer->sitdstart = start;
+ exfer->sitdend = stop;
+ exfer->sqtdstart = NULL;
+ exfer->sqtdstart = NULL;
+
+ mutex_enter(&sc->sc_intrhead_lock);
+ ehci_add_intr_list(sc, exfer);
+ mutex_exit(&sc->sc_intrhead_lock);
+ xfer->status = USBD_IN_PROGRESS;
+ xfer->done = 0;
+ splx(s);
+
+ if (sc->sc_bus.use_polling) {
+ printf("Starting ehci isoc xfer with polling. Bad idea?\n");
+ ehci_waitintr(sc, xfer);
+ }
+
+ return USBD_IN_PROGRESS;
+}
+
+Static void
+ehci_device_fs_isoc_abort(usbd_xfer_handle xfer)
+{
+ DPRINTFN(1, ("ehci_device_fs_isoc_abort: xfer = %p\n", xfer));
+ ehci_abort_isoc_xfer(xfer, USBD_CANCELLED);
+}
+
+Static void
+ehci_device_fs_isoc_close(usbd_pipe_handle pipe)
+{
+ DPRINTFN(1, ("ehci_device_fs_isoc_close: nothing in the pipe to
free?\n"));
+}
+
+Static void
+ehci_device_fs_isoc_done(usbd_xfer_handle xfer)
+{
+ struct ehci_xfer *exfer;
+ ehci_softc_t *sc;
+ struct ehci_pipe *epipe;
+ int s;
+
+ exfer = EXFER(xfer);
+ sc = xfer->pipe->device->bus->hci_private;
+ epipe = (struct ehci_pipe *) xfer->pipe;
+
+ s = splusb();
+ epipe->u.isoc.cur_xfers--;
+ mutex_enter(&sc->sc_intrhead_lock);
+ if (xfer->status != USBD_NOMEM && ehci_active_intr_list(exfer)) {
+ ehci_del_intr_list(sc, exfer);
+ ehci_rem_free_sitd_chain(sc, exfer);
+ }
+ mutex_exit(&sc->sc_intrhead_lock);
+ splx(s);
+
+ usb_syncmem(&xfer->dmabuf, 0, xfer->length, BUS_DMASYNC_POSTWRITE |
+ BUS_DMASYNC_POSTREAD);
+
+}
+
Index: ehcireg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehcireg.h,v
retrieving revision 1.33
diff -u -r1.33 ehcireg.h
--- ehcireg.h 17 Oct 2011 16:44:02 -0000 1.33
+++ ehcireg.h 24 Mar 2013 18:04:25 -0000
@@ -245,12 +245,41 @@
#define EHCI_ITD_ALIGN 32
/* Split Transaction Isochronous Transfer Descriptor */
-typedef struct {
- volatile ehci_link_t sitd_next;
+ typedef struct {
/* XXX many more */
-} ehci_sitd_t;
-#define EHCI_SITD_ALIGN 32
+ volatile u_int32_t sitd_next;
+ volatile u_int32_t sitd_endp;
+#define EHCI_SITD_SET_DIR(x) (((x) & 0x01) << 31)
+#define EHCI_SITD_SET_PORT(x) (((x) & 0x7f) << 24)
+#define EHCI_SITD_SET_HUBA(x) (((x) & 0x7f) << 16)
+#define EHCI_SITD_SET_ENDPT(x) (((x) & 0x0f) << 8)
+#define EHCI_SITD_SET_DADDR(x) ((x) & 0x7f)
+
+ volatile u_int32_t sitd_sched;
+#define EHCI_SITD_SET_SMASK(x) ((x) & 0xff)
+#define EHCI_SITD_SET_CMASK(x) (((x) & 0xff) << 8)
+
+ volatile u_int32_t sitd_trans;
+#define EHCI_SITD_IOC 0x80000000
+#define EHCI_SITD_P 0x40000000
+#define EHCI_SITD_GET_LEN(x) (((x) & 0x03ff0000) >> 16)
+#define EHCI_SITD_SET_LEN(x) (((x) & 0x3ff) << 16)
+#define EHCI_SITD_ACTIVE 0x00000080
+#define EHCI_SITD_ERR 0x00000040
+#define EHCI_SITD_BUFERR 0x00000020
+#define EHCI_SITD_BABBLE 0x00000010
+#define EHCI_SITD_XACTERR 0x00000008
+#define EHCI_SITD_MISS 0x00000004
+#define EHCI_SITD_SPLITXSTATE 0x00000002
+
+ volatile u_int32_t sitd_buffer[2];
+#define EHCI_SITD_SET_BPTR(x) ((x) & 0xfffff000)
+#define EHCI_SITD_SET_OFFS(x) ((x) & 0xfff)
+ volatile u_int32_t sitd_back;
+ } ehci_sitd_t;
+ #define EHCI_SITD_ALIGN 32
+
/* Queue Element Transfer Descriptor */
#define EHCI_QTD_NBUFFERS 5
typedef struct {
Index: ehcivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.38
diff -u -r1.38 ehcivar.h
--- ehcivar.h 18 Jan 2011 08:29:24 -0000 1.38
+++ ehcivar.h 24 Mar 2013 18:04:25 -0000
@@ -55,7 +55,10 @@
#define EHCI_SQH_CHUNK (EHCI_PAGE_SIZE / EHCI_SQH_SIZE)
typedef struct ehci_soft_itd {
- ehci_itd_t itd;
+ union {
+ ehci_itd_t itd;
+ ehci_sitd_t sitd;
+ };
union {
struct {
/* soft_itds links in a periodic frame*/
@@ -75,6 +78,12 @@
#define EHCI_ITD_SIZE ((sizeof(struct ehci_soft_itd) + EHCI_QH_ALIGN - 1) /
EHCI_ITD_ALIGN * EHCI_ITD_ALIGN)
#define EHCI_ITD_CHUNK (EHCI_PAGE_SIZE / EHCI_ITD_SIZE)
+#define ehci_soft_sitd_t ehci_soft_itd_t
+#define ehci_soft_sitd ehci_soft_itd
+#define sc_softsitds sc_softitds
+#define EHCI_SITD_SIZE ((sizeof(struct ehci_soft_sitd) + EHCI_QH_ALIGN - 1) /
EHCI_SITD_ALIGN * EHCI_SITD_ALIGN)
+#define EHCI_SITD_CHUNK (EHCI_PAGE_SIZE / EHCI_SITD_SIZE)
+
struct ehci_xfer {
struct usbd_xfer xfer;
struct usb_task abort_task;
@@ -83,6 +92,8 @@
ehci_soft_qtd_t *sqtdend;
ehci_soft_itd_t *itdstart;
ehci_soft_itd_t *itdend;
+ ehci_soft_sitd_t *sitdstart;
+ ehci_soft_sitd_t *sitdend;
u_int isoc_len;
int isdone; /* used only when DIAGNOSTIC is defined */
};
@@ -145,6 +156,7 @@
ehci_soft_qh_t *sc_freeqhs;
ehci_soft_qtd_t *sc_freeqtds;
LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds;
+ LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds;
int sc_noport;
u_int8_t sc_hasppc; /* has Port Power Control */
Home |
Main Index |
Thread Index |
Old Index