On Fri, 12 Mar 2010, Alan Stern wrote: > Maybe we could have the scatter-gather library put pointers to the > scatterlist elements in the URBs, and then for each URB have usbmon > call dma_sync_sg() with nelems set to 1 (see > Documentation/DMA-API.txt). I'm not sure whether this will work > properly if the original scatter-gather list contained more than one > element, but it probably will. I can ask. Here's a patch. Oliver, does it fix your problem? Alan Stern Index: usb-2.6/drivers/usb/mon/usb_mon.h =================================================================== --- usb-2.6.orig/drivers/usb/mon/usb_mon.h +++ usb-2.6/drivers/usb/mon/usb_mon.h @@ -72,4 +72,6 @@ extern const struct file_operations mon_ extern struct mon_bus mon_bus0; /* Only for redundant checks */ +extern void usb_sg_sync_for_cpu(struct urb *urb, int nelems); + #endif /* __USB_MON_H */ Index: usb-2.6/drivers/usb/mon/mon_bin.c =================================================================== --- usb-2.6.orig/drivers/usb/mon/mon_bin.c +++ usb-2.6/drivers/usb/mon/mon_bin.c @@ -410,6 +410,7 @@ static unsigned int mon_bin_get_data(con *flag = 'Z'; return length; } + usb_sg_sync_for_cpu(urb, 1); mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); length = 0; @@ -421,6 +422,7 @@ static unsigned int mon_bin_get_data(con } /* Copy up to the first non-addressable segment */ + usb_sg_sync_for_cpu(urb, urb->num_sgs); for_each_sg(urb->sg->sg, sg, urb->num_sgs, i) { if (length == 0 || PageHighMem(sg_page(sg))) break; Index: usb-2.6/drivers/usb/mon/mon_text.c =================================================================== --- usb-2.6.orig/drivers/usb/mon/mon_text.c +++ usb-2.6/drivers/usb/mon/mon_text.c @@ -170,6 +170,7 @@ static inline char mon_text_get_data(str src = sg_virt(sg); } + usb_sg_sync_for_cpu(urb, 1); memcpy(ep->data, src, len); return 0; } Index: usb-2.6/drivers/usb/core/message.c =================================================================== --- usb-2.6.orig/drivers/usb/core/message.c +++ usb-2.6/drivers/usb/core/message.c @@ -467,6 +467,7 @@ int usb_sg_init(struct usb_sg_request *i io->urbs[i]->transfer_buffer = NULL; if (dma) { + io->urbs[i]->sg = (struct usb_sg_request *) sg; io->urbs[i]->transfer_dma = sg_dma_address(sg); len = sg_dma_len(sg); } else { @@ -643,6 +644,35 @@ void usb_sg_cancel(struct usb_sg_request } EXPORT_SYMBOL_GPL(usb_sg_cancel); +/** + * usb_sg_sync_for_cpu -- give ownership of DMA buffers to the CPU + * @urb: URB whose buffers should be affected + * @nelems: number of sg elements to affect + * + * This allows the CPU to access @urb's sg transfer buffers after @urb + * has completed but before sg_clean() has unmapped the buffers for DMA. + * This is intended solely for use by usbmon. + */ +void usb_sg_sync_for_cpu(struct urb *urb, int nelems) +{ + enum dma_data_direction dir; + struct scatterlist *sg; + + if (!(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + return; /* Either not sg or not DMA */ + + if (urb->num_sgs == 0) { /* HCD has no native sg support */ + sg = (struct scatterlist *) urb->sg; + if (!sg) + return; /* Coherent mapping, not sg-mapped */ + } else { /* HCD has native sg support */ + sg = urb->sg->sg; + } + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + dma_sync_sg_for_cpu(urb->dev->bus->controller, sg, nelems, dir); +} +EXPORT_SYMBOL_GPL(usb_sg_sync_for_cpu); + /*-------------------------------------------------------------------*/ /** -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html