summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorraj <raj@FreeBSD.org>2008-02-12 11:03:29 +0000
committerraj <raj@FreeBSD.org>2008-02-12 11:03:29 +0000
commit155d019a02a65209a252a9679ccb33ea18569cca (patch)
tree270bd62b203de76f928b9d973ef7b72b220caed6
parentbd45971fbf8d160b37792d6540909ae5fa44d4ec (diff)
downloadFreeBSD-src-155d019a02a65209a252a9679ccb33ea18569cca.zip
FreeBSD-src-155d019a02a65209a252a9679ccb33ea18569cca.tar.gz
Eliminate BUS_DMA <-> cache incoherencies in USB transfers.
With write-allocate cache we get into the following scenario: 1. data has been updated in the memory by the USB HC, but 2. D-cache holds an un-flushed value of it 3. when affected cache line is being replaced, the old (un-flushed) value is flushed and overwrites the newly arrived This is possible due to how write-allocate works with virtual caches (ARM for example). In case of USB transfers it leads to fatal tags discrepancies in umass(4) operation, which look like the following: umass0: Invalid CSW: tag 1 should be 2 (probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR (probe0:umass-sim0:0:0:0): Retrying Command umass0: Invalid CSW: tag 1 should be 3 (probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR (probe0:umass-sim0:0:0:0): Retrying Command umass0: Invalid CSW: tag 1 should be 4 (probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR (probe0:umass-sim0:0:0:0): Retrying Command umass0: Invalid CSW: tag 1 should be 5 (probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR (probe0:umass-sim0:0:0:0): Retrying Command umass0: Invalid CSW: tag 1 should be 6 (probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR (probe0:umass-sim0:0:0:0): error 5 (probe0:umass-sim0:0:0:0): Retries Exausted To eliminate this, a BUS_DMASYNC_PREREAD sync operation is required in usbd_start_transfer(). Credits for nailing this down go to Grzegorz Bernacki gjb AT semihalf DOT com. Reviewed by: imp Approved by: cognet (mentor)
-rw-r--r--sys/dev/usb/usbdi.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 35c201c..bfc0dd9 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -383,7 +383,8 @@ usbd_start_transfer(void *arg, bus_dma_segment_t *segs, int nseg, int error)
* packet.
*/
bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE);
- }
+ } else
+ bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREREAD);
}
err = pipe->methods->transfer(xfer);
if (err != USBD_IN_PROGRESS && err) {
OpenPOWER on IntegriCloud