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:
parent
91a35e7870
commit
43b1161d4d
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user