From 33f38636865a31b597003c87e2d2bff06f57a3a9 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Sat, 6 Jun 2009 20:31:49 +0800 Subject: USB: ehci-dbg.c: no need for checking it before call vfree vfree() does it's own NULL checking,so no need for check before calling it. Signed-off-by: Figo.zhang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 7f4ace73d44a..1104caa0803b 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -879,8 +879,7 @@ static int debug_close(struct inode *inode, struct file *file) struct debug_buffer *buf = file->private_data; if (buf) { - if (buf->output_buf) - vfree(buf->output_buf); + vfree(buf->output_buf); kfree(buf); } -- cgit v1.2.3 From 5623c1743840b36e3f41c3a392f255ab6c276b15 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Wed, 10 Jun 2009 14:15:52 -0600 Subject: USB: sisusbvga: drop usb_buffer_alloc This patch falls out of my work to fix usbmon so it uses virtual addresses. It is not necessary, the "new" usbmon should work just fine with sisusbvga. However, it seems ridiculous that anyone would use uncached memory to transfer bulk data. Dropping the unnecessary use of usb_buffer_alloc should be beneficial here, in case anyone ever uses the dongle on anything beyond x86. I had no success in raising the author of the driver by e-mail, so the patch is not actually tested. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 53 +++++++++---------------------------- drivers/usb/misc/sisusbvga/sisusb.h | 2 -- 2 files changed, 13 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index b4ec716de7da..0025847743f3 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -79,14 +79,12 @@ sisusb_free_buffers(struct sisusb_usb_data *sisusb) for (i = 0; i < NUMOBUFS; i++) { if (sisusb->obuf[i]) { - usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize, - sisusb->obuf[i], sisusb->transfer_dma_out[i]); + kfree(sisusb->obuf[i]); sisusb->obuf[i] = NULL; } } if (sisusb->ibuf) { - usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize, - sisusb->ibuf, sisusb->transfer_dma_in); + kfree(sisusb->ibuf); sisusb->ibuf = NULL; } } @@ -230,8 +228,7 @@ sisusb_bulk_completeout(struct urb *urb) static int sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data, - int len, int *actual_length, int timeout, unsigned int tflags, - dma_addr_t transfer_dma) + int len, int *actual_length, int timeout, unsigned int tflags) { struct urb *urb = sisusb->sisurbout[index]; int retval, byteswritten = 0; @@ -245,9 +242,6 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, urb->transfer_flags |= tflags; urb->actual_length = 0; - if ((urb->transfer_dma = transfer_dma)) - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - /* Set up context */ sisusb->urbout_context[index].actual_length = (timeout) ? NULL : actual_length; @@ -297,8 +291,8 @@ sisusb_bulk_completein(struct urb *urb) } static int -sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len, - int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma) +sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, + int len, int *actual_length, int timeout, unsigned int tflags) { struct urb *urb = sisusb->sisurbin; int retval, readbytes = 0; @@ -311,9 +305,6 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, urb->transfer_flags |= tflags; urb->actual_length = 0; - if ((urb->transfer_dma = transfer_dma)) - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - sisusb->completein = 0; retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval == 0) { @@ -422,8 +413,7 @@ static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len, thispass, &transferred_len, async ? 0 : 5 * HZ, - tflags, - sisusb->transfer_dma_out[index]); + tflags); if (result == -ETIMEDOUT) { @@ -432,29 +422,16 @@ static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len, return -ETIME; continue; + } - } else if ((result == 0) && !async && transferred_len) { + if ((result == 0) && !async && transferred_len) { thispass -= transferred_len; - if (thispass) { - if (sisusb->transfer_dma_out) { - /* If DMA, copy remaining - * to beginning of buffer - */ - memcpy(buffer, - buffer + transferred_len, - thispass); - } else { - /* If not DMA, simply increase - * the pointer - */ - buffer += transferred_len; - } - } + buffer += transferred_len; } else break; - }; + } if (result) return result; @@ -530,8 +507,7 @@ static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len, thispass, &transferred_len, 5 * HZ, - tflags, - sisusb->transfer_dma_in); + tflags); if (transferred_len) thispass = transferred_len; @@ -3132,8 +3108,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate buffers */ sisusb->ibufsize = SISUSB_IBUF_SIZE; - if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE, - GFP_KERNEL, &sisusb->transfer_dma_in))) { + if (!(sisusb->ibuf = kmalloc(SISUSB_IBUF_SIZE, GFP_KERNEL))) { dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer"); retval = -ENOMEM; goto error_2; @@ -3142,9 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->numobufs = 0; sisusb->obufsize = SISUSB_OBUF_SIZE; for (i = 0; i < NUMOBUFS; i++) { - if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE, - GFP_KERNEL, - &sisusb->transfer_dma_out[i]))) { + if (!(sisusb->obuf[i] = kmalloc(SISUSB_OBUF_SIZE, GFP_KERNEL))) { if (i == 0) { dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n"); retval = -ENOMEM; diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index cf0b4a5883f6..55492a5930bd 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -123,8 +123,6 @@ struct sisusb_usb_data { int numobufs; /* number of obufs = number of out urbs */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ int obufsize, ibufsize; - dma_addr_t transfer_dma_out[NUMOBUFS]; - dma_addr_t transfer_dma_in; struct urb *sisurbout[NUMOBUFS]; struct urb *sisurbin; unsigned char urbstatus[NUMOBUFS]; -- cgit v1.2.3 From 78bf02a8cc79773ca7145d8593564a08705da985 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Wed, 10 Jun 2009 15:21:24 -0600 Subject: USB: usbmon: drop Kconfig defaults These statements seem to be unnecessary. No idea why, but I built all possible configurations and everything gets built just as before. It's an old patch that popped from discussion with Paul in November 2008. Obviously not a very high priority but better late than never. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index f28f350cd96a..635745f57fbd 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -5,11 +5,9 @@ config USB_MON tristate "USB Monitor" depends on USB - default y if USB=y - default m if USB=m help If you select this option, a component which captures the USB traffic between peripheral-specific drivers and HC drivers will be built. For more information, see . - If unsure, say Y (if allowed), otherwise M. + If unsure, say Y, if allowed, otherwise M. -- cgit v1.2.3 From b6a094e3c59e1a00d395430359f07cd0ea9ee2de Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Thu, 11 Jun 2009 08:53:20 -0600 Subject: USB: usbmon: end ugly tricks with DMA peeking This patch fixes crashes when usbmon attempts to access GART aperture. The old code attempted to take a bus address and convert it into a virtual address, which clearly was impossible on systems with actual IOMMUs. Let us not persist in this foolishness, and use transfer_buffer in all cases instead. I think downsides are negligible. The ones I see are: - A driver may pass an address of one buffer down as transfer_buffer, and entirely different entity mapped for DMA, resulting in misleading output of usbmon. Note, however, that PIO based controllers would do transfer the same data that usbmon sees here. - Out of tree drivers may crash usbmon if they store garbage in transfer_buffer. I inspected the in-tree drivers, and clarified the documentation in comments. - Drivers that use get_user_pages will not be possible to monitor. I only found one driver with this problem (drivers/staging/rspiusb). - Same happens with with usb_storage transferring from highmem, but it works fine on 64-bit systems, so I think it's not a concern. At least we don't crash anymore. Why didn't we do this in 2.6.10? That's because back in those days it was popular not to fill in transfer_buffer, so almost all traffic would be invisible (e.g. all of HID was like that). But now, the tree is almost 100% PIO friendly, so we can do the right thing at last. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/Makefile | 2 +- drivers/usb/mon/mon_bin.c | 12 +----- drivers/usb/mon/mon_dma.c | 95 ---------------------------------------------- drivers/usb/mon/mon_main.c | 1 - drivers/usb/mon/mon_text.c | 14 ------- drivers/usb/mon/usb_mon.h | 14 ------- include/linux/usb.h | 19 +++++++--- 7 files changed, 15 insertions(+), 142 deletions(-) delete mode 100644 drivers/usb/mon/mon_dma.c (limited to 'drivers') diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile index c6516b566731..384b198faa7c 100644 --- a/drivers/usb/mon/Makefile +++ b/drivers/usb/mon/Makefile @@ -2,6 +2,6 @@ # Makefile for USB monitor # -usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o +usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o obj-$(CONFIG_USB_MON) += usbmon.o diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index f8d9045d668a..ef4b3223a4d5 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -220,9 +220,8 @@ static void mon_free_buff(struct mon_pgmap *map, int npages); /* * This is a "chunked memcpy". It does not manipulate any counters. - * But it returns the new offset for repeated application. */ -unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, +static void mon_copy_to_buff(const struct mon_reader_bin *this, unsigned int off, const unsigned char *from, unsigned int length) { unsigned int step_len; @@ -247,7 +246,6 @@ unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, from += step_len; length -= step_len; } - return off; } /* @@ -400,15 +398,8 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, unsigned int offset, struct urb *urb, unsigned int length) { - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { - mon_dmapeek_vec(rp, offset, urb->transfer_dma, length); - return 0; - } - if (urb->transfer_buffer == NULL) return 'Z'; - mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); return 0; } @@ -635,7 +626,6 @@ static int mon_bin_open(struct inode *inode, struct file *file) spin_lock_init(&rp->b_lock); init_waitqueue_head(&rp->b_wait); mutex_init(&rp->fetch_lock); - rp->b_size = BUFF_DFL; size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE); diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c deleted file mode 100644 index 140cc80bd2b1..000000000000 --- a/drivers/usb/mon/mon_dma.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * The USB Monitor, inspired by Dave Harding's USBMon. - * - * mon_dma.c: Library which snoops on DMA areas. - * - * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com) - */ -#include -#include -#include -#include - -#include /* Only needed for declarations in usb_mon.h */ -#include "usb_mon.h" - -/* - * PC-compatibles, are, fortunately, sufficiently cache-coherent for this. - */ -#if defined(__i386__) || defined(__x86_64__) /* CONFIG_ARCH_I386 doesn't exit */ -#define MON_HAS_UNMAP 1 - -#define phys_to_page(phys) pfn_to_page((phys) >> PAGE_SHIFT) - -char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len) -{ - struct page *pg; - unsigned long flags; - unsigned char *map; - unsigned char *ptr; - - /* - * On i386, a DMA handle is the "physical" address of a page. - * In other words, the bus address is equal to physical address. - * There is no IOMMU. - */ - pg = phys_to_page(dma_addr); - - /* - * We are called from hardware IRQs in case of callbacks. - * But we can be called from softirq or process context in case - * of submissions. In such case, we need to protect KM_IRQ0. - */ - local_irq_save(flags); - map = kmap_atomic(pg, KM_IRQ0); - ptr = map + (dma_addr & (PAGE_SIZE-1)); - memcpy(dst, ptr, len); - kunmap_atomic(map, KM_IRQ0); - local_irq_restore(flags); - return 0; -} - -void mon_dmapeek_vec(const struct mon_reader_bin *rp, - unsigned int offset, dma_addr_t dma_addr, unsigned int length) -{ - unsigned long flags; - unsigned int step_len; - struct page *pg; - unsigned char *map; - unsigned long page_off, page_len; - - local_irq_save(flags); - while (length) { - /* compute number of bytes we are going to copy in this page */ - step_len = length; - page_off = dma_addr & (PAGE_SIZE-1); - page_len = PAGE_SIZE - page_off; - if (page_len < step_len) - step_len = page_len; - - /* copy data and advance pointers */ - pg = phys_to_page(dma_addr); - map = kmap_atomic(pg, KM_IRQ0); - offset = mon_copy_to_buff(rp, offset, map + page_off, step_len); - kunmap_atomic(map, KM_IRQ0); - dma_addr += step_len; - length -= step_len; - } - local_irq_restore(flags); -} - -#endif /* __i386__ */ - -#ifndef MON_HAS_UNMAP -char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len) -{ - return 'D'; -} - -void mon_dmapeek_vec(const struct mon_reader_bin *rp, - unsigned int offset, dma_addr_t dma_addr, unsigned int length) -{ - ; -} - -#endif /* MON_HAS_UNMAP */ diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 5e0ab4201c00..e0c2db3b767b 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -361,7 +361,6 @@ static int __init mon_init(void) } // MOD_INC_USE_COUNT(which_module?); - mutex_lock(&usb_bus_list_lock); list_for_each_entry (ubus, &usb_bus_list, bus_list) { mon_bus_init(ubus); diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index a7eb4c99342c..9f1a9227ebe6 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -150,20 +150,6 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, return '>'; } - /* - * The check to see if it's safe to poke at data has an enormous - * number of corner cases, but it seems that the following is - * more or less safe. - * - * We do not even try to look at transfer_buffer, because it can - * contain non-NULL garbage in case the upper level promised to - * set DMA for the HCD. - */ - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { - return mon_dmapeek(ep->data, urb->transfer_dma, len); - } - if (urb->transfer_buffer == NULL) return 'Z'; /* '0' would be not as pretty. */ diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index f5d84ff8c101..df9a4df342c7 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -64,20 +64,6 @@ void mon_text_exit(void); int __init mon_bin_init(void); void mon_bin_exit(void); -/* - * DMA interface. - * - * XXX The vectored side needs a serious re-thinking. Abstracting vectors, - * like in Paolo's original patch, produces a double pkmap. We need an idea. -*/ -extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len); - -struct mon_reader_bin; -extern void mon_dmapeek_vec(const struct mon_reader_bin *rp, - unsigned int offset, dma_addr_t dma_addr, unsigned int len); -extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp, - unsigned int offset, const unsigned char *from, unsigned int len); - /* */ extern struct mutex mon_lock; diff --git a/include/linux/usb.h b/include/linux/usb.h index 84929e914034..d930bbe3bfb2 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1036,9 +1036,10 @@ typedef void (*usb_complete_t)(struct urb *); * @transfer_flags: A variety of flags may be used to affect how URB * submission, unlinking, or operation are handled. Different * kinds of URB can use different flags. - * @transfer_buffer: This identifies the buffer to (or from) which - * the I/O request will be performed (unless URB_NO_TRANSFER_DMA_MAP - * is set). This buffer must be suitable for DMA; allocate it with + * @transfer_buffer: This identifies the buffer to (or from) which the I/O + * request will be performed unless URB_NO_TRANSFER_DMA_MAP is set + * (however, do not leave garbage in transfer_buffer even then). + * This buffer must be suitable for DMA; allocate it with * kmalloc() or equivalent. For transfers to "in" endpoints, contents * of this buffer will be modified. This buffer is used for the data * stage of control transfers. @@ -1102,9 +1103,15 @@ typedef void (*usb_complete_t)(struct urb *); * allocate a DMA buffer with usb_buffer_alloc() or call usb_buffer_map(). * When these transfer flags are provided, host controller drivers will * attempt to use the dma addresses found in the transfer_dma and/or - * setup_dma fields rather than determining a dma address themselves. (Note - * that transfer_buffer and setup_packet must still be set because not all - * host controllers use DMA, nor do virtual root hubs). + * setup_dma fields rather than determining a dma address themselves. + * + * Note that transfer_buffer must still be set if the controller + * does not support DMA (as indicated by bus.uses_dma) and when talking + * to root hub. If you have to trasfer between highmem zone and the device + * on such controller, create a bounce buffer or bail out with an error. + * If transfer_buffer cannot be set (is in highmem) and the controller is DMA + * capable, assign NULL to it, so that usbmon knows not to use the value. + * The setup_packet must always be set, so it cannot be located in highmem. * * Initialization: * -- cgit v1.2.3 From 5aaf2ee1f0f9a82d4aed13b5505774b88dfad7e5 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Thu, 11 Jun 2009 08:40:39 -0600 Subject: USB: Let usb_sg_init to set transfer_buffer more often This fix permits the "new" usbmon to access usb-storage's data buffer without DMA remapping tricks. It should be compatible with PIO controllers and not add any new crashes. Note that from now on PIO controllers and usbmon are uniform in their access pattern and if one crashes then the other will too. Hopefuly neither does. As a side effect, we get rid for #ifdefs, which were a little ugly. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 2bed83caacb1..df487425b7da 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -459,35 +459,23 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, io->urbs[i]->context = io; /* - * Some systems need to revert to PIO when DMA is - * temporarily unavailable. For their sakes, both - * transfer_buffer and transfer_dma are set when - * possible. However this can only work on systems - * without: + * Some systems need to revert to PIO when DMA is temporarily + * unavailable. For their sakes, both transfer_buffer and + * transfer_dma are set when possible. * - * - HIGHMEM, since DMA buffers located in high memory - * are not directly addressable by the CPU for PIO; - * - * - IOMMU, since dma_map_sg() is allowed to use an - * IOMMU to make virtually discontiguous buffers be - * "dma-contiguous" so that PIO and DMA need diferent - * numbers of URBs. - * - * So when HIGHMEM or IOMMU are in use, transfer_buffer - * is NULL to prevent stale pointers and to help spot - * bugs. + * Note that if IOMMU coalescing occurred, we cannot + * trust sg_page anymore, so check if S/G list shrunk. */ + if (io->nents == io->entries && !PageHighMem(sg_page(sg))) + io->urbs[i]->transfer_buffer = sg_virt(sg); + else + io->urbs[i]->transfer_buffer = NULL; + if (dma) { io->urbs[i]->transfer_dma = sg_dma_address(sg); len = sg_dma_len(sg); -#if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU) - io->urbs[i]->transfer_buffer = NULL; -#else - io->urbs[i]->transfer_buffer = sg_virt(sg); -#endif } else { /* hc may use _only_ transfer_buffer */ - io->urbs[i]->transfer_buffer = sg_virt(sg); len = sg->length; } -- cgit v1.2.3