if (is_in) {
                                        csr = musb_readw(regs,
                                                        MGC_O_HDRC_TXCSR);
+                                       if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                                               csr |= MGC_M_TXCSR_FLUSHFIFO;
                                        csr |= MGC_M_TXCSR_P_SENDSTALL
                                                | MGC_M_TXCSR_CLRDATATOG
-                                               | MGC_M_TXCSR_FLUSHFIFO
                                                | MGC_M_TXCSR_P_WZC_BITS;
                                        musb_writew(regs, MGC_O_HDRC_TXCSR,
                                                        csr);
 
                                        pRequest->dma, request_size);
                        if (use_dma) {
                                if (pEnd->dma->bDesiredMode == 0) {
+                                       /* ASSERT: DMAENAB is clear */
                                        wCsrVal &= ~(MGC_M_TXCSR_AUTOSET |
                                                        MGC_M_TXCSR_DMAMODE);
                                        wCsrVal |= (MGC_M_TXCSR_DMAENAB |
                                                        MGC_M_TXCSR_MODE);
-                                               // against programming guide
+                                       // against programming guide
                                }
                                else
                                        wCsrVal |= (MGC_M_TXCSR_AUTOSET
                if (!use_dma) {
                        c->channel_release(pEnd->dma);
                        pEnd->dma = NULL;
+                       /* ASSERT: DMAENAB clear */
                        wCsrVal &= ~(MGC_M_TXCSR_DMAMODE | MGC_M_TXCSR_MODE);
                        /* invariant: prequest->buf is non-null */
                }
 static int musb_gadget_enable(struct usb_ep *ep,
                        const struct usb_endpoint_descriptor *desc)
 {
-       unsigned long flags;
-       struct musb_ep  *pEnd;
+       unsigned long           flags;
+       struct musb_ep          *pEnd;
+       struct musb_hw_ep       *hw_ep;
+       void __iomem            *regs;
        struct musb     *pThis;
        void __iomem    *pBase;
        u8              bEnd;
                return -EINVAL;
 
        pEnd = to_musb_ep(ep);
+       hw_ep = pEnd->hw_ep;
+       regs = hw_ep->regs;
        pThis = pEnd->pThis;
        pBase = pThis->pRegs;
        bEnd = pEnd->bEndNumber;
        if (desc->bEndpointAddress & USB_DIR_IN) {
                u16 wIntrTxE = musb_readw(pBase, MGC_O_HDRC_INTRTXE);
 
-               if (pEnd->hw_ep->bIsSharedFifo)
+               if (hw_ep->bIsSharedFifo)
                        pEnd->is_in = 1;
                if (!pEnd->is_in)
                        goto fail;
-               if (tmp > pEnd->hw_ep->wMaxPacketSizeTx)
+               if (tmp > hw_ep->wMaxPacketSizeTx)
                        goto fail;
 
                wIntrTxE |= (1 << bEnd);
                /* REVISIT if can_bulk_split(), use by updating "tmp";
                 * likewise high bandwidth periodic tx
                 */
-               MGC_WriteCsr16(pBase, MGC_O_HDRC_TXMAXP, bEnd, tmp);
+               musb_writew(regs, MGC_O_HDRC_TXMAXP, tmp);
 
-               csr = MGC_M_TXCSR_MODE | MGC_M_TXCSR_CLRDATATOG
-                               | MGC_M_TXCSR_FLUSHFIFO;
+               csr = MGC_M_TXCSR_MODE | MGC_M_TXCSR_CLRDATATOG;
+               if (musb_readw(regs, MGC_O_HDRC_TXCSR)
+                               & MGC_M_TXCSR_FIFONOTEMPTY)
+                       csr |= MGC_M_TXCSR_FLUSHFIFO;
                if (pEnd->type == USB_ENDPOINT_XFER_ISOC)
                        csr |= MGC_M_TXCSR_P_ISO;
 
                /* set twice in case of double buffering */
-               MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, csr);
-               MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, csr);
+               musb_writew(regs, MGC_O_HDRC_TXCSR, csr);
+               /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+               musb_writew(regs, MGC_O_HDRC_TXCSR, csr);
 
        } else {
                u16 wIntrRxE = musb_readw(pBase, MGC_O_HDRC_INTRRXE);
 
-               if (pEnd->hw_ep->bIsSharedFifo)
+               if (hw_ep->bIsSharedFifo)
                        pEnd->is_in = 0;
                if (pEnd->is_in)
                        goto fail;
-               if (tmp > pEnd->hw_ep->wMaxPacketSizeRx)
+               if (tmp > hw_ep->wMaxPacketSizeRx)
                        goto fail;
 
                wIntrRxE |= (1 << bEnd);
                MGC_WriteCsr16(pBase, MGC_O_HDRC_RXMAXP, bEnd, tmp);
 
                /* force shared fifo to OUT-only mode */
-               if (pEnd->hw_ep->bIsSharedFifo) {
+               if (hw_ep->bIsSharedFifo) {
                        csr = musb_readw(pBase, MGC_O_HDRC_TXCSR);
                        csr &= ~(MGC_M_TXCSR_MODE | MGC_M_TXCSR_TXPKTRDY);
                        MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, csr);
        if (is_dma_capable() && pThis->pDmaController) {
                struct dma_controller   *c = pThis->pDmaController;
 
-               pEnd->dma = c->channel_alloc(c, pEnd->hw_ep,
+               pEnd->dma = c->channel_alloc(c, hw_ep,
                                (desc->bEndpointAddress & USB_DIR_IN));
        } else
                pEnd->dma = NULL;
        DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear");
        if (pEnd->is_in) {
                wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd);
+               if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY)
+                       wCsr |= MGC_M_TXCSR_FLUSHFIFO;
                wCsr |= MGC_M_TXCSR_P_WZC_BITS
-                       | MGC_M_TXCSR_CLRDATATOG
-                       | MGC_M_TXCSR_FLUSHFIFO;
+                       | MGC_M_TXCSR_CLRDATATOG;
                if (value)
                        wCsr |= MGC_M_TXCSR_P_SENDSTALL;
                else
 
        if (musb_ep->is_in) {
                wCsr = MGC_ReadCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd);
-               wCsr |= MGC_M_TXCSR_FLUSHFIFO | MGC_M_TXCSR_P_WZC_BITS;
-               MGC_WriteCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd, wCsr);
-               MGC_WriteCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd, wCsr);
+               if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY) {
+                       wCsr |= MGC_M_TXCSR_FLUSHFIFO | MGC_M_TXCSR_P_WZC_BITS;
+                       MGC_WriteCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd, wCsr);
+                       /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+                       MGC_WriteCsr16(mbase, MGC_O_HDRC_TXCSR, nEnd, wCsr);
+               }
        } else {
                wCsr = MGC_ReadCsr16(mbase, MGC_O_HDRC_RXCSR, nEnd);
                wCsr |= MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_P_WZC_BITS;
 {
        struct musb     *musb = gadget_to_musb(gadget);
        unsigned long   flags;
-       int             status = 0;
+       int             status = -EINVAL;
        u8              power;
 
        spin_lock_irqsave(&musb->Lock, flags);
 
+       /* fail if we're not suspended */
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+       if (!(power & MGC_M_POWER_SUSPENDM))
+               goto done;
+
        switch (musb->xceiv.state) {
        case OTG_STATE_B_PERIPHERAL:
-               /* FIXME if not suspended, fail */
                if (musb->bMayWakeup)
                        break;
-               goto fail;
+               goto done;
        case OTG_STATE_B_IDLE:
                /* REVISIT we might be able to do SRP even without OTG,
                 * though Linux doesn't yet expose that capability
                }
                /* FALLTHROUGH */
        default:
-fail:
-               status = -EINVAL;
                goto done;
        }
 
-       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+       status = 0;
        power |= MGC_M_POWER_RESUME;
        musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
 
 
                if (bEnd) {
                        u16     csr = wCsr;
 
+                       /* ASSERT:  TXCSR_DMAENAB was already cleared */
+
                        /* flush all old state, set default */
+                       if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                               csr |= MGC_M_TXCSR_FLUSHFIFO;
                        csr &= ~(MGC_M_TXCSR_H_NAKTIMEOUT
                                        | MGC_M_TXCSR_DMAMODE
                                        | MGC_M_TXCSR_FRCDATATOG
                                        | MGC_M_TXCSR_FIFONOTEMPTY
                                        | MGC_M_TXCSR_TXPKTRDY
                                        );
-                       csr |= MGC_M_TXCSR_FLUSHFIFO
-                                       | MGC_M_TXCSR_MODE;
+                       csr |= MGC_M_TXCSR_MODE;
 
                        if (qh->type == USB_ENDPOINT_XFER_ISOC)
                                csr |= MGC_M_TXCSR_ISO;
                        /* twice in case of double packet buffering */
                        MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd,
                                        csr);
+                       /* REVISIT may need to clear FLUSHFIFO ... */
                        MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd,
                                        csr);
                        wCsr = MGC_ReadCsr16(pBase, MGC_O_HDRC_TXCSR,
                        musb_writeb(pBase,
                                MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXHUBPORT),
                                qh->h_port_reg);
+/* FIXME if !bEnd, do the same for RX ... */
                } else
                        musb_writeb(pBase, MGC_O_HDRC_FADDR, qh->addr_reg);
 
                }
 #endif
                if (wLoadCount) {
+                       /* ASSERT:  TXCSR_DMAENAB was already cleared */
+
                        /* PIO to load FIFO */
                        qh->segsize = wLoadCount;
                        musb_write_fifo(pEnd, wLoadCount, pBuffer);
 
        /* check for errors */
        if (wTxCsrVal & MGC_M_TXCSR_H_RXSTALL) {
+               /* dma was disabled, fifo flushed */
                DBG(3, "TX end %d stall\n", bEnd);
 
                /* stall; record URB status */
                status = -EPIPE;
 
        } else if (wTxCsrVal & MGC_M_TXCSR_H_ERROR) {
-               DBG(3, "TX data error on ep=%d\n", bEnd);
+               /* (NON-ISO) dma was disabled, fifo flushed */
+               DBG(3, "TX 3strikes on ep=%d\n", bEnd);
 
                status = -ETIMEDOUT;
 
                 * usb core; the dma engine should already be stopped.
                 */
 // SCRUB (TX)
+               if (wTxCsrVal & MGC_M_TXCSR_FIFONOTEMPTY)
+                       wTxCsrVal |= MGC_M_TXCSR_FLUSHFIFO;
                wTxCsrVal &= ~(MGC_M_TXCSR_FIFONOTEMPTY
                                | MGC_M_TXCSR_AUTOSET
                                | MGC_M_TXCSR_DMAENAB
                                | MGC_M_TXCSR_H_RXSTALL
                                | MGC_M_TXCSR_H_NAKTIMEOUT
                                );
-               wTxCsrVal |= MGC_M_TXCSR_FLUSHFIFO;
 
                MGC_SelectEnd(pBase, bEnd);
                MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, wTxCsrVal);
+               /* REVISIT may need to clear FLUSHFIFO ... */
                MGC_WriteCsr16(pBase, MGC_O_HDRC_TXCSR, bEnd, wTxCsrVal);
                MGC_WriteCsr8(pBase, MGC_O_HDRC_TXINTERVAL, bEnd, 0);
 
        } else {
 // SCRUB (TX)
                csr = MGC_ReadCsr16(regs, MGC_O_HDRC_TXCSR, hw_end);
+               if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                       csr |= MGC_M_TXCSR_FLUSHFIFO;
                csr &= ~( MGC_M_TXCSR_AUTOSET
                        | MGC_M_TXCSR_DMAENAB
                        | MGC_M_TXCSR_H_RXSTALL
                        | MGC_M_TXCSR_H_ERROR
                        | MGC_M_TXCSR_FIFONOTEMPTY
                        );
-               csr |= MGC_M_TXCSR_FLUSHFIFO;
                MGC_WriteCsr16(regs, MGC_O_HDRC_TXCSR, 0, csr);
+               /* REVISIT may need to clear FLUSHFIFO ... */
                MGC_WriteCsr16(regs, MGC_O_HDRC_TXCSR, 0, csr);
                /* flush cpu writebuffer */
                csr = MGC_ReadCsr16(regs, MGC_O_HDRC_TXCSR, hw_end);
 
 /* Additional Control Registers */
 
 #define MGC_O_HDRC_DEVCTL      0x60    /* 8 bit */
-// vctrl/vstatus:  optional vendor utmi+phy register at 0x68
-#define MGC_O_HDRC_HWVERS      0x6C    /* 8 bit */
 
 /* These are always controlled through the INDEX register */
 #define MGC_O_HDRC_TXFIFOSZ    0x62    /* 8-bit (see masks) */
 #define MGC_O_HDRC_TXFIFOADD   0x64    /* 16-bit offset shifted right 3 */
 #define MGC_O_HDRC_RXFIFOADD   0x66    /* 16-bit offset shifted right 3 */
 
+// vctrl/vstatus:  optional vendor utmi+phy register at 0x68
+#define MGC_O_HDRC_HWVERS      0x6C    /* 8 bit */
+
+#define MGC_O_HDRC_EPINFO      0x78    /* 8 bit */
+#define MGC_O_HDRC_RAMINFO     0x79    /* 8 bit */
+#define MGC_O_HDRC_LINKINFO    0x7a    /* 8 bit */
+#define MGC_O_HDRC_VPLEN       0x7b    /* 8 bit */
+#define MGC_O_HDRC_HS_EOF1     0x7c    /* 8 bit */
+#define MGC_O_HDRC_FS_EOF1     0x7d    /* 8 bit */
+#define MGC_O_HDRC_LS_EOF1     0x7e    /* 8 bit */
+
 /* offsets to endpoint registers */
 #define MGC_O_HDRC_TXMAXP      0x00
 #define MGC_O_HDRC_TXCSR       0x02
 #include "tusb6010.h"          /* needed "only" for TUSB_EP0_CONF */
 #endif
 
-/* "bus control" registers */
+/* "bus control"/target registers, for host side multipoint (external hubs) */
 #define MGC_O_HDRC_TXFUNCADDR  0x00
 #define MGC_O_HDRC_TXHUBADDR   0x02
 #define MGC_O_HDRC_TXHUBPORT   0x03
 #define MGC_M_INTR_DISCONNECT 0x20
 #define MGC_M_INTR_SESSREQ    0x40
 #define MGC_M_INTR_VBUSERROR  0x80     /* FOR SESSION END */
-#define MGC_M_INTR_EP0      0x01       /* FOR EP0 INTERRUPT */
 
 /* DEVCTL */
 #define MGC_M_DEVCTL_BDEVICE    0x80
 #define MGC_M_CSR0_P_SENTSTALL    0x0004
 
 /* CSR0 in Host mode */
+#define MGC_M_CSR0_H_DIS_PING  0x0800
 #define MGC_M_CSR0_H_WR_DATATOGGLE   0x0400    /* set to allow setting: */
 #define MGC_M_CSR0_H_DATATOGGLE            0x0200      /* data toggle control */
 #define MGC_M_CSR0_H_NAKTIMEOUT   0x0080
 #define MGC_TYPE_SPEED_HIGH    1
 #define MGC_TYPE_SPEED_FULL    2
 #define MGC_TYPE_SPEED_LOW     3
-#define MGC_M_TYPE_PROTO       0x30
+#define MGC_M_TYPE_PROTO       0x30    /* implicitly zero for ep0 */
 #define MGC_S_TYPE_PROTO       4
-#define MGC_M_TYPE_REMOTE_END  0xf
+#define MGC_M_TYPE_REMOTE_END  0xf     /* implicitly zero for ep0 */
 
 /* CONFIGDATA */
 
 #define MGC_M_RXCSR_AUTOCLEAR     0x8000
 #define MGC_M_RXCSR_DMAENAB       0x2000
 #define MGC_M_RXCSR_DISNYET       0x1000
+#define MGC_M_RXCSR_PID_ERR       0x1000
 #define MGC_M_RXCSR_DMAMODE       0x0800
 #define MGC_M_RXCSR_INCOMPRX      0x0100
 #define MGC_M_RXCSR_CLRDATATOG    0x0080
 
 
                if (devctl & MGC_M_DEVCTL_HM) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
-                       /* REVISIT:  this is where SRP kicks in, yes? */
+                       /* REVISIT:  this is where SRP kicks in, yes?
+                        * host responsibility should be to CLEAR the
+                        * resume signaling after 50 msec ...
+                        */
                        MUSB_HST_MODE(pThis);   /* unnecessary */
                        power &= ~MGC_M_POWER_SUSPENDM;
                        musb_writeb(pBase, MGC_O_HDRC_POWER,
 
                musb->port1_status |= USB_PORT_STAT_SUSPEND;
        } else if (power & MGC_M_POWER_SUSPENDM) {
                DBG(3, "Root port resumed\n");
-               power &= ~(MGC_M_POWER_SUSPENDM | MGC_M_POWER_RESUME);
                musb_writeb(pBase, MGC_O_HDRC_POWER,
                                power | MGC_M_POWER_RESUME);