Workaround design botch in usb: blindly mixing bus_dma with PIO does not

work on architectures with a write-back cache as the PIO writes end up
in the cache which the sync(BUS_DMASYNC_POSTREAD) in usb_transfer_complete
then discards; compensate in the xfer methods that do PIO by pushing the
writes out of the cache before usb_transfer_complete is called.

This fixes USB on xscale and likely other places.

Sponsored by:	hobnob
Reviewed by:	cognet, imp
MFC after:	1 month
This commit is contained in:
Sam Leffler 2008-03-20 16:19:25 +00:00
parent 91a35e7870
commit 43b1161d4d
2 changed files with 32 additions and 0 deletions

View File

@ -653,6 +653,20 @@ ehci_pcd_enable(void *v_sc)
ehci_pcd_able(sc, 1);
}
/*
* XXX write back xfer data for architectures with a write-back
* data cache; this is a hack because usb is mis-architected
* in blindly mixing bus_dma w/ PIO.
*/
static __inline void
hacksync(usbd_xfer_handle xfer)
{
usbd_pipe_handle pipe = xfer->pipe;
bus_dma_tag_t tag = pipe->device->bus->buffer_dmatag;
struct usb_dma_mapping *dmap = &xfer->dmamap;
bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE);
}
void
ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
{
@ -679,6 +693,7 @@ ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
xfer->actlen = xfer->length;
xfer->status = USBD_NORMAL_COMPLETION;
hacksync(xfer); /* XXX to compensate for usb_transfer_complete */
usb_transfer_complete(xfer);
}
@ -2072,6 +2087,7 @@ ehci_root_ctrl_start(usbd_xfer_handle xfer)
ret:
xfer->status = err;
s = splusb();
hacksync(xfer); /* XXX to compensate for usb_transfer_complete */
usb_transfer_complete(xfer);
splx(s);
return (USBD_IN_PROGRESS);

View File

@ -1560,6 +1560,20 @@ ohci_device_bulk_done(usbd_xfer_handle xfer)
xfer->hcpriv = NULL;
}
/*
* XXX write back xfer data for architectures with a write-back
* data cache; this is a hack because usb is mis-architected
* in blindly mixing bus_dma w/ PIO.
*/
static __inline void
hacksync(usbd_xfer_handle xfer)
{
usbd_pipe_handle pipe = xfer->pipe;
bus_dma_tag_t tag = pipe->device->bus->buffer_dmatag;
struct usb_dma_mapping *dmap = &xfer->dmamap;
bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE);
}
void
ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer)
{
@ -1591,6 +1605,7 @@ ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer)
xfer->actlen = xfer->length;
xfer->status = USBD_NORMAL_COMPLETION;
hacksync(xfer); /* XXX to compensate for usb_transfer_complete */
usb_transfer_complete(xfer);
}
@ -2722,6 +2737,7 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
ret:
xfer->status = err;
s = splusb();
hacksync(xfer); /* XXX to compensate for usb_transfer_complete */
usb_transfer_complete(xfer);
splx(s);
return (USBD_IN_PROGRESS);