diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 11:10:12 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 11:10:12 -0700 |
| commit | 19f23bdac78b23931f45121dd246fedad57597b1 (patch) | |
| tree | ef45709a56cdf47165ec0acb1eb0377bb2dd9411 /usb | |
| parent | 3dc984e689eddab9a8624360e8c8eccfc14104bd (diff) | |
| download | patches-19f23bdac78b23931f45121dd246fedad57597b1.tar.gz | |
kobject network namespace patches and some usb serial fixes
Diffstat (limited to 'usb')
24 files changed, 2169 insertions, 57 deletions
diff --git a/usb/usb-aircable-fix-incorrect-write-buffer-length.patch b/usb/usb-aircable-fix-incorrect-write-buffer-length.patch new file mode 100644 index 00000000000000..c68e04ff1c87a5 --- /dev/null +++ b/usb/usb-aircable-fix-incorrect-write-buffer-length.patch @@ -0,0 +1,28 @@ +From jhovold@gmail.com Thu May 20 10:57:22 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:33 +0200 +Subject: USB: aircable: fix incorrect write-buffer length +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-5-git-send-email-jhovold@gmail.com> + + +Returned length should include header length. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/aircable.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/serial/aircable.c ++++ b/drivers/usb/serial/aircable.c +@@ -95,7 +95,7 @@ static int aircable_prepare_write_buffer + buf[1] = TX_HEADER_1; + put_unaligned_le16(count, &buf[2]); + +- return count; ++ return count + HCI_HEADER_LENGTH; + } + + static int aircable_probe(struct usb_serial *serial, diff --git a/usb/usb-change-the-scatterlist-type-in-struct-urb.patch b/usb/usb-change-the-scatterlist-type-in-struct-urb.patch index 5a9fc08f9c2922..6c824eff32c6f5 100644 --- a/usb/usb-change-the-scatterlist-type-in-struct-urb.patch +++ b/usb/usb-change-the-scatterlist-type-in-struct-urb.patch @@ -114,7 +114,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> void *orig; --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -1771,7 +1771,7 @@ static unsigned int count_sg_trbs_needed +@@ -1788,7 +1788,7 @@ static unsigned int count_sg_trbs_needed xhci_dbg(xhci, "count sg list trbs: \n"); num_trbs = 0; @@ -123,7 +123,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> unsigned int previous_total_trbs = num_trbs; unsigned int len = sg_dma_len(sg); -@@ -1934,7 +1934,7 @@ static int queue_bulk_sg_tx(struct xhci_ +@@ -1951,7 +1951,7 @@ static int queue_bulk_sg_tx(struct xhci_ * the amount of memory allocated for this scatter-gather list. * 3. TRBs buffers can't cross 64KB boundaries. */ diff --git a/usb/usb-clean-up-some-host-controller-sparse-warnings.patch b/usb/usb-clean-up-some-host-controller-sparse-warnings.patch index 132befa10a999c..fef5aec9c95f8e 100644 --- a/usb/usb-clean-up-some-host-controller-sparse-warnings.patch +++ b/usb/usb-clean-up-some-host-controller-sparse-warnings.patch @@ -143,7 +143,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -371,7 +371,7 @@ static struct xhci_segment *find_trb_seg +@@ -388,7 +388,7 @@ static struct xhci_segment *find_trb_seg cur_seg = cur_seg->next; if (cur_seg == start_seg) /* Looped over the entire list. Oops! */ @@ -152,7 +152,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } return cur_seg; } -@@ -565,7 +565,7 @@ static void handle_stopped_endpoint(stru +@@ -582,7 +582,7 @@ static void handle_stopped_endpoint(stru struct xhci_ring *ep_ring; struct xhci_virt_ep *ep; struct list_head *entry; @@ -161,7 +161,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> struct xhci_td *last_unlinked_td; struct xhci_dequeue_state deq_state; -@@ -1098,7 +1098,7 @@ struct xhci_segment *trb_in_td(struct xh +@@ -1115,7 +1115,7 @@ struct xhci_segment *trb_in_td(struct xh do { if (start_dma == 0) @@ -170,7 +170,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* We may get an event for a Link TRB in the middle of a TD */ end_seg_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[TRBS_PER_SEGMENT - 1]); -@@ -1120,7 +1120,7 @@ struct xhci_segment *trb_in_td(struct xh +@@ -1137,7 +1137,7 @@ struct xhci_segment *trb_in_td(struct xh suspect_dma <= end_trb_dma)) return cur_seg; } @@ -179,7 +179,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } else { /* Might still be somewhere in this segment */ if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma) -@@ -1130,7 +1130,7 @@ struct xhci_segment *trb_in_td(struct xh +@@ -1147,7 +1147,7 @@ struct xhci_segment *trb_in_td(struct xh start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]); } while (cur_seg != start_seg); @@ -188,7 +188,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, -@@ -1206,11 +1206,11 @@ static int handle_tx_event(struct xhci_h +@@ -1223,11 +1223,11 @@ static int handle_tx_event(struct xhci_h struct xhci_ring *ep_ring; unsigned int slot_id; int ep_index; diff --git a/usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch b/usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch index 7500c711d8dde2..b48f6b4a6d3865 100644 --- a/usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch +++ b/usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch @@ -451,7 +451,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> qset_free_stds(qset, urb); --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -1945,7 +1945,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd * +@@ -1962,7 +1962,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd * int running_total, trb_buff_len, ret; u64 addr; diff --git a/usb/usb-ftdi_sio-fix-legacy-sio-device-header.patch b/usb/usb-ftdi_sio-fix-legacy-sio-device-header.patch new file mode 100644 index 00000000000000..b7ea1678730034 --- /dev/null +++ b/usb/usb-ftdi_sio-fix-legacy-sio-device-header.patch @@ -0,0 +1,32 @@ +From jhovold@gmail.com Thu May 20 10:58:53 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:41 +0200 +Subject: USB: ftdi_sio: fix legacy SIO-device header +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-13-git-send-email-jhovold@gmail.com> + + +Length field of header was incorrectly set to available payload space +rather than the actual payload size. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/ftdi_sio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -1752,10 +1752,10 @@ static int ftdi_prepare_write_buffer(str + spin_lock_irqsave(&port->lock, flags); + for (i = 0; i < size - 1; i += priv->max_packet_size) { + len = min_t(int, size - i, priv->max_packet_size) - 1; +- buffer[i] = (len << 2) + 1; + c = kfifo_out(&port->write_fifo, &buffer[i + 1], len); + if (!c) + break; ++ buffer[i] = (c << 2) + 1; + count += c + 1; + } + spin_unlock_irqrestore(&port->lock, flags); diff --git a/usb/usb-io_ti-remove-unsused-private-counter.patch b/usb/usb-io_ti-remove-unsused-private-counter.patch new file mode 100644 index 00000000000000..5475aa864c7182 --- /dev/null +++ b/usb/usb-io_ti-remove-unsused-private-counter.patch @@ -0,0 +1,37 @@ +From jhovold@gmail.com Thu May 20 10:58:03 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:36 +0200 +Subject: USB: io_ti: remove unsused private counter +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-8-git-send-email-jhovold@gmail.com> + + + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/io_ti.c | 5 ----- + 1 file changed, 5 deletions(-) + +--- a/drivers/usb/serial/io_ti.c ++++ b/drivers/usb/serial/io_ti.c +@@ -56,10 +56,6 @@ + #define EPROM_PAGE_SIZE 64 + + +-struct edgeport_uart_buf_desc { +- __u32 count; /* Number of bytes currently in buffer */ +-}; +- + /* different hardware types */ + #define HARDWARE_TYPE_930 0 + #define HARDWARE_TYPE_TIUMP 1 +@@ -108,7 +104,6 @@ struct edgeport_port { + int baud_rate; + int close_pending; + int lsr_event; +- struct edgeport_uart_buf_desc tx; + struct async_icount icount; + wait_queue_head_t delta_msr_wait; /* for handling sleeping while + waiting for msr change to diff --git a/usb/usb-io_ti-use-kfifo-to-implement-write-buffering.patch b/usb/usb-io_ti-use-kfifo-to-implement-write-buffering.patch new file mode 100644 index 00000000000000..a53a6423df2574 --- /dev/null +++ b/usb/usb-io_ti-use-kfifo-to-implement-write-buffering.patch @@ -0,0 +1,349 @@ +From jhovold@gmail.com Thu May 20 10:58:11 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:37 +0200 +Subject: USB: io_ti: use kfifo to implement write buffering +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-9-git-send-email-jhovold@gmail.com> + + +Kill custom fifo implementation. + +Compile-only tested. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/io_ti.c | 223 ++------------------------------------------- + 1 file changed, 13 insertions(+), 210 deletions(-) + +--- a/drivers/usb/serial/io_ti.c ++++ b/drivers/usb/serial/io_ti.c +@@ -36,6 +36,7 @@ + #include <linux/spinlock.h> + #include <linux/mutex.h> + #include <linux/serial.h> ++#include <linux/kfifo.h> + #include <linux/ioctl.h> + #include <linux/firmware.h> + #include <linux/uaccess.h> +@@ -83,14 +84,6 @@ struct product_info { + __u8 hardware_type; /* Type of hardware */ + } __attribute__((packed)); + +-/* circular buffer */ +-struct edge_buf { +- unsigned int buf_size; +- char *buf_buf; +- char *buf_get; +- char *buf_put; +-}; +- + struct edgeport_port { + __u16 uart_base; + __u16 dma_address; +@@ -114,7 +107,7 @@ struct edgeport_port { + spinlock_t ep_lock; + int ep_read_urb_state; + int ep_write_urb_in_use; +- struct edge_buf *ep_out_buf; ++ struct kfifo write_fifo; + }; + + struct edgeport_serial { +@@ -244,17 +237,6 @@ static void edge_send(struct tty_struct + static int edge_create_sysfs_attrs(struct usb_serial_port *port); + static int edge_remove_sysfs_attrs(struct usb_serial_port *port); + +-/* circular buffer */ +-static struct edge_buf *edge_buf_alloc(unsigned int size); +-static void edge_buf_free(struct edge_buf *eb); +-static void edge_buf_clear(struct edge_buf *eb); +-static unsigned int edge_buf_data_avail(struct edge_buf *eb); +-static unsigned int edge_buf_space_avail(struct edge_buf *eb); +-static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf, +- unsigned int count); +-static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, +- unsigned int count); +- + + static int ti_vread_sync(struct usb_device *dev, __u8 request, + __u16 value, __u16 index, u8 *data, int size) +@@ -585,7 +567,7 @@ static void chase_port(struct edgeport_p + add_wait_queue(&tty->write_wait, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); +- if (edge_buf_data_avail(port->ep_out_buf) == 0 ++ if (kfifo_len(&port->write_fifo) == 0 + || timeout == 0 || signal_pending(current) + || !usb_get_intfdata(port->port->serial->interface)) + /* disconnect */ +@@ -597,7 +579,7 @@ static void chase_port(struct edgeport_p + set_current_state(TASK_RUNNING); + remove_wait_queue(&tty->write_wait, &wait); + if (flush) +- edge_buf_clear(port->ep_out_buf); ++ kfifo_reset_out(&port->write_fifo); + spin_unlock_irqrestore(&port->ep_lock, flags); + tty_kref_put(tty); + +@@ -2084,7 +2066,6 @@ static int edge_write(struct tty_struct + const unsigned char *data, int count) + { + struct edgeport_port *edge_port = usb_get_serial_port_data(port); +- unsigned long flags; + + dbg("%s - port %d", __func__, port->number); + +@@ -2098,10 +2079,8 @@ static int edge_write(struct tty_struct + if (edge_port->close_pending == 1) + return -ENODEV; + +- spin_lock_irqsave(&edge_port->ep_lock, flags); +- count = edge_buf_put(edge_port->ep_out_buf, data, count); +- spin_unlock_irqrestore(&edge_port->ep_lock, flags); +- ++ count = kfifo_in_locked(&edge_port->write_fifo, data, count, ++ &edge_port->ep_lock); + edge_send(tty); + + return count; +@@ -2124,7 +2103,7 @@ static void edge_send(struct tty_struct + return; + } + +- count = edge_buf_get(edge_port->ep_out_buf, ++ count = kfifo_out(&edge_port->write_fifo, + port->write_urb->transfer_buffer, + port->bulk_out_size); + +@@ -2180,7 +2159,7 @@ static int edge_write_room(struct tty_st + return 0; + + spin_lock_irqsave(&edge_port->ep_lock, flags); +- room = edge_buf_space_avail(edge_port->ep_out_buf); ++ room = kfifo_avail(&edge_port->write_fifo); + spin_unlock_irqrestore(&edge_port->ep_lock, flags); + + dbg("%s - returns %d", __func__, room); +@@ -2202,7 +2181,7 @@ static int edge_chars_in_buffer(struct t + return 0; + + spin_lock_irqsave(&edge_port->ep_lock, flags); +- chars = edge_buf_data_avail(edge_port->ep_out_buf); ++ chars = kfifo_len(&edge_port->write_fifo); + spin_unlock_irqrestore(&edge_port->ep_lock, flags); + + dbg("%s - returns %d", __func__, chars); +@@ -2659,8 +2638,8 @@ static int edge_startup(struct usb_seria + goto cleanup; + } + spin_lock_init(&edge_port->ep_lock); +- edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE); +- if (edge_port->ep_out_buf == NULL) { ++ if (kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE, ++ GFP_KERNEL)) { + dev_err(&serial->dev->dev, "%s - Out of memory\n", + __func__); + kfree(edge_port); +@@ -2677,7 +2656,7 @@ static int edge_startup(struct usb_seria + cleanup: + for (--i; i >= 0; --i) { + edge_port = usb_get_serial_port_data(serial->port[i]); +- edge_buf_free(edge_port->ep_out_buf); ++ kfifo_free(&edge_port->write_fifo); + kfree(edge_port); + usb_set_serial_port_data(serial->port[i], NULL); + } +@@ -2708,7 +2687,7 @@ static void edge_release(struct usb_seri + + for (i = 0; i < serial->num_ports; ++i) { + edge_port = usb_get_serial_port_data(serial->port[i]); +- edge_buf_free(edge_port->ep_out_buf); ++ kfifo_free(&edge_port->write_fifo); + kfree(edge_port); + } + kfree(usb_get_serial_data(serial)); +@@ -2758,182 +2737,6 @@ static int edge_remove_sysfs_attrs(struc + } + + +-/* Circular Buffer */ +- +-/* +- * edge_buf_alloc +- * +- * Allocate a circular buffer and all associated memory. +- */ +- +-static struct edge_buf *edge_buf_alloc(unsigned int size) +-{ +- struct edge_buf *eb; +- +- +- if (size == 0) +- return NULL; +- +- eb = kmalloc(sizeof(struct edge_buf), GFP_KERNEL); +- if (eb == NULL) +- return NULL; +- +- eb->buf_buf = kmalloc(size, GFP_KERNEL); +- if (eb->buf_buf == NULL) { +- kfree(eb); +- return NULL; +- } +- +- eb->buf_size = size; +- eb->buf_get = eb->buf_put = eb->buf_buf; +- +- return eb; +-} +- +- +-/* +- * edge_buf_free +- * +- * Free the buffer and all associated memory. +- */ +- +-static void edge_buf_free(struct edge_buf *eb) +-{ +- if (eb) { +- kfree(eb->buf_buf); +- kfree(eb); +- } +-} +- +- +-/* +- * edge_buf_clear +- * +- * Clear out all data in the circular buffer. +- */ +- +-static void edge_buf_clear(struct edge_buf *eb) +-{ +- if (eb != NULL) +- eb->buf_get = eb->buf_put; +- /* equivalent to a get of all data available */ +-} +- +- +-/* +- * edge_buf_data_avail +- * +- * Return the number of bytes of data available in the circular +- * buffer. +- */ +- +-static unsigned int edge_buf_data_avail(struct edge_buf *eb) +-{ +- if (eb == NULL) +- return 0; +- return ((eb->buf_size + eb->buf_put - eb->buf_get) % eb->buf_size); +-} +- +- +-/* +- * edge_buf_space_avail +- * +- * Return the number of bytes of space available in the circular +- * buffer. +- */ +- +-static unsigned int edge_buf_space_avail(struct edge_buf *eb) +-{ +- if (eb == NULL) +- return 0; +- return ((eb->buf_size + eb->buf_get - eb->buf_put - 1) % eb->buf_size); +-} +- +- +-/* +- * edge_buf_put +- * +- * Copy data data from a user buffer and put it into the circular buffer. +- * Restrict to the amount of space available. +- * +- * Return the number of bytes copied. +- */ +- +-static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf, +- unsigned int count) +-{ +- unsigned int len; +- +- +- if (eb == NULL) +- return 0; +- +- len = edge_buf_space_avail(eb); +- if (count > len) +- count = len; +- +- if (count == 0) +- return 0; +- +- len = eb->buf_buf + eb->buf_size - eb->buf_put; +- if (count > len) { +- memcpy(eb->buf_put, buf, len); +- memcpy(eb->buf_buf, buf+len, count - len); +- eb->buf_put = eb->buf_buf + count - len; +- } else { +- memcpy(eb->buf_put, buf, count); +- if (count < len) +- eb->buf_put += count; +- else /* count == len */ +- eb->buf_put = eb->buf_buf; +- } +- +- return count; +-} +- +- +-/* +- * edge_buf_get +- * +- * Get data from the circular buffer and copy to the given buffer. +- * Restrict to the amount of data available. +- * +- * Return the number of bytes copied. +- */ +- +-static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, +- unsigned int count) +-{ +- unsigned int len; +- +- +- if (eb == NULL) +- return 0; +- +- len = edge_buf_data_avail(eb); +- if (count > len) +- count = len; +- +- if (count == 0) +- return 0; +- +- len = eb->buf_buf + eb->buf_size - eb->buf_get; +- if (count > len) { +- memcpy(buf, eb->buf_get, len); +- memcpy(buf+len, eb->buf_buf, count - len); +- eb->buf_get = eb->buf_buf + count - len; +- } else { +- memcpy(buf, eb->buf_get, count); +- if (count < len) +- eb->buf_get += count; +- else /* count == len */ +- eb->buf_get = eb->buf_buf; +- } +- +- return count; +-} +- +- + static struct usb_serial_driver edgeport_1port_device = { + .driver = { + .owner = THIS_MODULE, diff --git a/usb/usb-ir-usb-fix-incorrect-write-buffer-length.patch b/usb/usb-ir-usb-fix-incorrect-write-buffer-length.patch new file mode 100644 index 00000000000000..b19d435047cffb --- /dev/null +++ b/usb/usb-ir-usb-fix-incorrect-write-buffer-length.patch @@ -0,0 +1,38 @@ +From jhovold@gmail.com Thu May 20 10:57:39 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:34 +0200 +Subject: USB: ir-usb: fix incorrect write-buffer length +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-6-git-send-email-jhovold@gmail.com> + + +Returned length should include header length. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/ir-usb.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/serial/ir-usb.c ++++ b/drivers/usb/serial/ir-usb.c +@@ -307,6 +307,7 @@ static int ir_prepare_write_buffer(struc + void *dest, size_t size) + { + unsigned char *buf = dest; ++ int count; + + /* + * The first byte of the packet we send to the device contains an +@@ -317,8 +318,9 @@ static int ir_prepare_write_buffer(struc + */ + *buf = ir_xbof | ir_baud; + +- return kfifo_out_locked(&port->write_fifo, buf + 1, size - 1, ++ count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1, + &port->lock); ++ return count + 1; + } + + static void ir_process_read_urb(struct urb *urb) diff --git a/usb/usb-kl5usb105-fix-memory-leak.patch b/usb/usb-kl5usb105-fix-memory-leak.patch new file mode 100644 index 00000000000000..8611cdcdf38bda --- /dev/null +++ b/usb/usb-kl5usb105-fix-memory-leak.patch @@ -0,0 +1,28 @@ +From jhovold@gmail.com Thu May 20 10:58:20 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:38 +0200 +Subject: USB: kl5usb105: fix memory leak +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>, stable <stable@kernel.org> +Message-ID: <1274220101-13873-10-git-send-email-jhovold@gmail.com> + + +Private data was not freed on error path in startup. + +Cc: stable <stable@kernel.org> +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/kl5kusb105.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/serial/kl5kusb105.c ++++ b/drivers/usb/serial/kl5kusb105.c +@@ -321,6 +321,7 @@ err_cleanup: + usb_free_urb(priv->write_urb_pool[j]); + } + } ++ kfree(priv); + usb_set_serial_port_data(serial->port[i], NULL); + } + return -ENOMEM; diff --git a/usb/usb-kl5usb105-minor-clean-ups.patch b/usb/usb-kl5usb105-minor-clean-ups.patch new file mode 100644 index 00000000000000..51e876e7c0202d --- /dev/null +++ b/usb/usb-kl5usb105-minor-clean-ups.patch @@ -0,0 +1,228 @@ +From jhovold@gmail.com Thu May 20 10:58:29 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:39 +0200 +Subject: USB: kl5usb105: minor clean ups +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-11-git-send-email-jhovold@gmail.com> + + +Whitespace changes and some removed comments. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/kl5kusb105.c | 79 ++++++++++++++++------------------------ + 1 file changed, 33 insertions(+), 46 deletions(-) + +--- a/drivers/usb/serial/kl5kusb105.c ++++ b/drivers/usb/serial/kl5kusb105.c +@@ -107,7 +107,7 @@ static struct usb_driver kl5kusb105d_dri + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, +- .no_dynamic_id = 1, ++ .no_dynamic_id = 1, + }; + + static struct usb_serial_driver kl5kusb105d_device = { +@@ -115,26 +115,26 @@ static struct usb_serial_driver kl5kusb1 + .owner = THIS_MODULE, + .name = "kl5kusb105d", + }, +- .description = "KL5KUSB105D / PalmConnect", +- .usb_driver = &kl5kusb105d_driver, +- .id_table = id_table, +- .num_ports = 1, +- .open = klsi_105_open, +- .close = klsi_105_close, +- .write = klsi_105_write, +- .write_bulk_callback = klsi_105_write_bulk_callback, +- .chars_in_buffer = klsi_105_chars_in_buffer, +- .write_room = klsi_105_write_room, +- .read_bulk_callback = klsi_105_read_bulk_callback, +- .set_termios = klsi_105_set_termios, +- /*.break_ctl = klsi_105_break_ctl,*/ +- .tiocmget = klsi_105_tiocmget, +- .tiocmset = klsi_105_tiocmset, +- .attach = klsi_105_startup, +- .disconnect = klsi_105_disconnect, +- .release = klsi_105_release, +- .throttle = klsi_105_throttle, +- .unthrottle = klsi_105_unthrottle, ++ .description = "KL5KUSB105D / PalmConnect", ++ .usb_driver = &kl5kusb105d_driver, ++ .id_table = id_table, ++ .num_ports = 1, ++ .open = klsi_105_open, ++ .close = klsi_105_close, ++ .write = klsi_105_write, ++ .write_bulk_callback = klsi_105_write_bulk_callback, ++ .chars_in_buffer = klsi_105_chars_in_buffer, ++ .write_room = klsi_105_write_room, ++ .read_bulk_callback = klsi_105_read_bulk_callback, ++ .set_termios = klsi_105_set_termios, ++ /*.break_ctl = klsi_105_break_ctl,*/ ++ .tiocmget = klsi_105_tiocmget, ++ .tiocmset = klsi_105_tiocmset, ++ .attach = klsi_105_startup, ++ .disconnect = klsi_105_disconnect, ++ .release = klsi_105_release, ++ .throttle = klsi_105_throttle, ++ .unthrottle = klsi_105_unthrottle, + }; + + struct klsi_105_port_settings { +@@ -189,7 +189,7 @@ static int klsi_105_chg_port_settings(st + settings->pktlen, settings->baudrate, settings->databits, + settings->unknown1, settings->unknown2); + return rc; +-} /* klsi_105_chg_port_settings */ ++} + + /* translate a 16-bit status value from the device to linux's TIO bits */ + static unsigned long klsi_105_status2linestate(const __u16 status) +@@ -202,6 +202,7 @@ static unsigned long klsi_105_status2lin + + return res; + } ++ + /* + * Read line control via vendor command and return result through + * *line_state_p +@@ -325,8 +326,7 @@ err_cleanup: + usb_set_serial_port_data(serial->port[i], NULL); + } + return -ENOMEM; +-} /* klsi_105_startup */ +- ++} + + static void klsi_105_disconnect(struct usb_serial *serial) + { +@@ -352,8 +352,7 @@ static void klsi_105_disconnect(struct u + } + } + } +-} /* klsi_105_disconnect */ +- ++} + + static void klsi_105_release(struct usb_serial *serial) + { +@@ -367,7 +366,7 @@ static void klsi_105_release(struct usb_ + + kfree(priv); + } +-} /* klsi_105_release */ ++} + + static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) + { +@@ -461,8 +460,7 @@ static int klsi_105_open(struct tty_str + exit: + kfree(cfg); + return retval; +-} /* klsi_105_open */ +- ++} + + static void klsi_105_close(struct usb_serial_port *port) + { +@@ -498,8 +496,7 @@ static void klsi_105_close(struct usb_se + dev_info(&port->serial->dev->dev, + "port stats: %ld bytes in, %ld bytes out\n", + priv->bytes_in, priv->bytes_out); +-} /* klsi_105_close */ +- ++} + + /* We need to write a complete 64-byte data block and encode the + * number actually sent in the first double-byte, LSB-order. That +@@ -507,7 +504,6 @@ static void klsi_105_close(struct usb_se + */ + #define KLSI_105_DATA_OFFSET 2 /* in the bulk urb data block */ + +- + static int klsi_105_write(struct tty_struct *tty, + struct usb_serial_port *port, const unsigned char *buf, int count) + { +@@ -586,7 +582,7 @@ exit: + priv->bytes_out += bytes_sent; + + return bytes_sent; /* that's how much we wrote */ +-} /* klsi_105_write */ ++} + + static void klsi_105_write_bulk_callback(struct urb *urb) + { +@@ -602,8 +598,7 @@ static void klsi_105_write_bulk_callback + } + + usb_serial_port_softint(port); +-} /* klsi_105_write_bulk_completion_callback */ +- ++} + + /* return number of characters currently in the writing process */ + static int klsi_105_chars_in_buffer(struct tty_struct *tty) +@@ -647,8 +642,6 @@ static int klsi_105_write_room(struct tt + return room; + } + +- +- + static void klsi_105_read_bulk_callback(struct urb *urb) + { + struct usb_serial_port *port = urb->context; +@@ -720,8 +713,7 @@ static void klsi_105_read_bulk_callback( + dev_err(&port->dev, + "%s - failed resubmitting read urb, error %d\n", + __func__, rc); +-} /* klsi_105_read_bulk_callback */ +- ++} + + static void klsi_105_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, +@@ -888,8 +880,7 @@ static void klsi_105_set_termios(struct + klsi_105_chg_port_settings(port, cfg); + err: + kfree(cfg); +-} /* klsi_105_set_termios */ +- ++} + + #if 0 + static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) +@@ -907,7 +898,7 @@ static void mct_u232_break_ctl(struct tt + lcr |= MCT_U232_SET_BREAK; + + mct_u232_set_line_ctrl(serial, lcr); +-} /* mct_u232_break_ctl */ ++} + #endif + + static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file) +@@ -986,7 +977,6 @@ static void klsi_105_unthrottle(struct t + } + + +- + static int __init klsi_105_init(void) + { + int retval; +@@ -1006,7 +996,6 @@ failed_usb_serial_register: + return retval; + } + +- + static void __exit klsi_105_exit(void) + { + usb_deregister(&kl5kusb105d_driver); +@@ -1024,5 +1013,3 @@ MODULE_LICENSE("GPL"); + + module_param(debug, bool, S_IRUGO | S_IWUSR); + MODULE_PARM_DESC(debug, "enable extensive debugging messages"); +- +-/* vim: set sts=8 ts=8 sw=8: */ diff --git a/usb/usb-kl5usb105-reimplement-using-generic-framework.patch b/usb/usb-kl5usb105-reimplement-using-generic-framework.patch new file mode 100644 index 00000000000000..ff3f9bc4a9a615 --- /dev/null +++ b/usb/usb-kl5usb105-reimplement-using-generic-framework.patch @@ -0,0 +1,556 @@ +From jhovold@gmail.com Thu May 20 10:58:37 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:40 +0200 +Subject: USB: kl5usb105: reimplement using generic framework +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-12-git-send-email-jhovold@gmail.com> + + +Kill custom read and write implementations (static per-port, +singleton(!) urb pool). + +Also remove changelog header (can be retrieved through git). + +Read processing and write-buffer handling tested using a cp210x device +in a loopback setup. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/kl5kusb105.c | 380 ++++------------------------------------ + 1 file changed, 47 insertions(+), 333 deletions(-) + +--- a/drivers/usb/serial/kl5kusb105.c ++++ b/drivers/usb/serial/kl5kusb105.c +@@ -1,6 +1,7 @@ + /* + * KLSI KL5KUSB105 chip RS232 converter driver + * ++ * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> + * Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de> + * + * This program is free software; you can redistribute it and/or modify +@@ -34,17 +35,6 @@ + * implement handshaking or decide that we do not support it + */ + +-/* History: +- * 0.3a - implemented pools of write URBs +- * 0.3 - alpha version for public testing +- * 0.2 - TIOCMGET works, so autopilot(1) can be used! +- * 0.1 - can be used to do pilot-xfer -p /dev/ttyUSB0 -l +- * +- * The driver skeleton is mainly based on mct_u232.c and various other +- * pieces of code shamelessly copied from the drivers/usb/serial/ directory. +- */ +- +- + #include <linux/kernel.h> + #include <linux/errno.h> + #include <linux/init.h> +@@ -64,8 +54,8 @@ static int debug; + /* + * Version Information + */ +-#define DRIVER_VERSION "v0.3a" +-#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>" ++#define DRIVER_VERSION "v0.4" ++#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>" + #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" + + +@@ -73,23 +63,17 @@ static int debug; + * Function prototypes + */ + static int klsi_105_startup(struct usb_serial *serial); +-static void klsi_105_disconnect(struct usb_serial *serial); + static void klsi_105_release(struct usb_serial *serial); + static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); + static void klsi_105_close(struct usb_serial_port *port); +-static int klsi_105_write(struct tty_struct *tty, +- struct usb_serial_port *port, const unsigned char *buf, int count); +-static void klsi_105_write_bulk_callback(struct urb *urb); +-static int klsi_105_chars_in_buffer(struct tty_struct *tty); +-static int klsi_105_write_room(struct tty_struct *tty); +-static void klsi_105_read_bulk_callback(struct urb *urb); + static void klsi_105_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old); +-static void klsi_105_throttle(struct tty_struct *tty); +-static void klsi_105_unthrottle(struct tty_struct *tty); + static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file); + static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); ++static void klsi_105_process_read_urb(struct urb *urb); ++static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, ++ void *dest, size_t size); + + /* + * All of the device info needed for the KLSI converters. +@@ -119,22 +103,19 @@ static struct usb_serial_driver kl5kusb1 + .usb_driver = &kl5kusb105d_driver, + .id_table = id_table, + .num_ports = 1, ++ .bulk_out_size = 64, + .open = klsi_105_open, + .close = klsi_105_close, +- .write = klsi_105_write, +- .write_bulk_callback = klsi_105_write_bulk_callback, +- .chars_in_buffer = klsi_105_chars_in_buffer, +- .write_room = klsi_105_write_room, +- .read_bulk_callback = klsi_105_read_bulk_callback, + .set_termios = klsi_105_set_termios, + /*.break_ctl = klsi_105_break_ctl,*/ + .tiocmget = klsi_105_tiocmget, + .tiocmset = klsi_105_tiocmset, + .attach = klsi_105_startup, +- .disconnect = klsi_105_disconnect, + .release = klsi_105_release, +- .throttle = klsi_105_throttle, +- .unthrottle = klsi_105_unthrottle, ++ .throttle = usb_serial_generic_throttle, ++ .unthrottle = usb_serial_generic_unthrottle, ++ .process_read_urb = klsi_105_process_read_urb, ++ .prepare_write_buffer = klsi_105_prepare_write_buffer, + }; + + struct klsi_105_port_settings { +@@ -145,18 +126,11 @@ struct klsi_105_port_settings { + __u8 unknown2; + } __attribute__ ((packed)); + +-/* we implement a pool of NUM_URBS urbs per usb_serial */ +-#define NUM_URBS 1 +-#define URB_TRANSFER_BUFFER_SIZE 64 + struct klsi_105_private { + struct klsi_105_port_settings cfg; + struct ktermios termios; + unsigned long line_state; /* modem line settings */ +- /* write pool */ +- struct urb *write_urb_pool[NUM_URBS]; + spinlock_t lock; +- unsigned long bytes_in; +- unsigned long bytes_out; + }; + + +@@ -259,7 +233,7 @@ static int klsi_105_get_line_state(struc + static int klsi_105_startup(struct usb_serial *serial) + { + struct klsi_105_private *priv; +- int i, j; ++ int i; + + /* check if we support the product id (see keyspan.c) + * FIXME +@@ -283,29 +257,9 @@ static int klsi_105_startup(struct usb_s + + priv->line_state = 0; + +- priv->bytes_in = 0; +- priv->bytes_out = 0; + usb_set_serial_port_data(serial->port[i], priv); + + spin_lock_init(&priv->lock); +- for (j = 0; j < NUM_URBS; j++) { +- struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); +- +- priv->write_urb_pool[j] = urb; +- if (urb == NULL) { +- dev_err(&serial->dev->dev, "No more urbs???\n"); +- goto err_cleanup; +- } +- +- urb->transfer_buffer = +- kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); +- if (!urb->transfer_buffer) { +- dev_err(&serial->dev->dev, +- "%s - out of memory for urb buffers.\n", +- __func__); +- goto err_cleanup; +- } +- } + + /* priv->termios is left uninitalized until port opening */ + init_waitqueue_head(&serial->port[i]->write_wait); +@@ -316,56 +270,20 @@ static int klsi_105_startup(struct usb_s + err_cleanup: + for (; i >= 0; i--) { + priv = usb_get_serial_port_data(serial->port[i]); +- for (j = 0; j < NUM_URBS; j++) { +- if (priv->write_urb_pool[j]) { +- kfree(priv->write_urb_pool[j]->transfer_buffer); +- usb_free_urb(priv->write_urb_pool[j]); +- } +- } + kfree(priv); + usb_set_serial_port_data(serial->port[i], NULL); + } + return -ENOMEM; + } + +-static void klsi_105_disconnect(struct usb_serial *serial) +-{ +- int i; +- +- dbg("%s", __func__); +- +- /* stop reads and writes on all ports */ +- for (i = 0; i < serial->num_ports; ++i) { +- struct klsi_105_private *priv = +- usb_get_serial_port_data(serial->port[i]); +- +- if (priv) { +- /* kill our write urb pool */ +- int j; +- struct urb **write_urbs = priv->write_urb_pool; +- +- for (j = 0; j < NUM_URBS; j++) { +- if (write_urbs[j]) { +- usb_kill_urb(write_urbs[j]); +- usb_free_urb(write_urbs[j]); +- } +- } +- } +- } +-} +- + static void klsi_105_release(struct usb_serial *serial) + { + int i; + + dbg("%s", __func__); + +- for (i = 0; i < serial->num_ports; ++i) { +- struct klsi_105_private *priv = +- usb_get_serial_port_data(serial->port[i]); +- +- kfree(priv); +- } ++ for (i = 0; i < serial->num_ports; ++i) ++ kfree(usb_get_serial_port_data(serial->port[i])); + } + + static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) +@@ -416,18 +334,8 @@ static int klsi_105_open(struct tty_str + spin_unlock_irqrestore(&priv->lock, flags); + + /* READ_ON and urb submission */ +- usb_fill_bulk_urb(port->read_urb, port->serial->dev, +- usb_rcvbulkpipe(port->serial->dev, +- port->bulk_in_endpointAddress), +- port->read_urb->transfer_buffer, +- port->read_urb->transfer_buffer_length, +- klsi_105_read_bulk_callback, +- port); +- +- rc = usb_submit_urb(port->read_urb, GFP_KERNEL); ++ rc = usb_serial_generic_open(tty, port); + if (rc) { +- dev_err(&port->dev, "%s - failed submitting read urb, " +- "error %d\n", __func__, rc); + retval = rc; + goto exit; + } +@@ -464,7 +372,6 @@ exit: + + static void klsi_105_close(struct usb_serial_port *port) + { +- struct klsi_105_private *priv = usb_get_serial_port_data(port); + int rc; + + dbg("%s port %d", __func__, port->number); +@@ -487,232 +394,61 @@ static void klsi_105_close(struct usb_se + mutex_unlock(&port->serial->disc_mutex); + + /* shutdown our bulk reads and writes */ +- usb_kill_urb(port->write_urb); +- usb_kill_urb(port->read_urb); +- /* unlink our write pool */ +- /* FIXME */ ++ usb_serial_generic_close(port); ++ + /* wgg - do I need this? I think so. */ + usb_kill_urb(port->interrupt_in_urb); +- dev_info(&port->serial->dev->dev, +- "port stats: %ld bytes in, %ld bytes out\n", +- priv->bytes_in, priv->bytes_out); + } + + /* We need to write a complete 64-byte data block and encode the + * number actually sent in the first double-byte, LSB-order. That + * leaves at most 62 bytes of payload. + */ +-#define KLSI_105_DATA_OFFSET 2 /* in the bulk urb data block */ +- +-static int klsi_105_write(struct tty_struct *tty, +- struct usb_serial_port *port, const unsigned char *buf, int count) +-{ +- struct klsi_105_private *priv = usb_get_serial_port_data(port); +- int result, size; +- int bytes_sent = 0; +- +- dbg("%s - port %d", __func__, port->number); +- +- while (count > 0) { +- /* try to find a free urb (write 0 bytes if none) */ +- struct urb *urb = NULL; +- unsigned long flags; +- int i; +- /* since the pool is per-port we might not need +- the spin lock !? */ +- spin_lock_irqsave(&priv->lock, flags); +- for (i = 0; i < NUM_URBS; i++) { +- if (priv->write_urb_pool[i]->status != -EINPROGRESS) { +- urb = priv->write_urb_pool[i]; +- dbg("%s - using pool URB %d", __func__, i); +- break; +- } +- } +- spin_unlock_irqrestore(&priv->lock, flags); +- +- if (urb == NULL) { +- dbg("%s - no more free urbs", __func__); +- goto exit; +- } +- +- if (urb->transfer_buffer == NULL) { +- urb->transfer_buffer = +- kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); +- if (urb->transfer_buffer == NULL) { +- dev_err(&port->dev, +- "%s - no more kernel memory...\n", +- __func__); +- goto exit; +- } +- } +- +- size = min(count, port->bulk_out_size - KLSI_105_DATA_OFFSET); +- size = min(size, URB_TRANSFER_BUFFER_SIZE - +- KLSI_105_DATA_OFFSET); +- +- memcpy(urb->transfer_buffer + KLSI_105_DATA_OFFSET, buf, size); +- +- /* write payload size into transfer buffer */ +- ((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF); +- ((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8); +- +- /* set up our urb */ +- usb_fill_bulk_urb(urb, port->serial->dev, +- usb_sndbulkpipe(port->serial->dev, +- port->bulk_out_endpointAddress), +- urb->transfer_buffer, +- URB_TRANSFER_BUFFER_SIZE, +- klsi_105_write_bulk_callback, +- port); +- +- /* send the data out the bulk port */ +- result = usb_submit_urb(urb, GFP_ATOMIC); +- if (result) { +- dev_err(&port->dev, +- "%s - failed submitting write urb, error %d\n", +- __func__, result); +- goto exit; +- } +- buf += size; +- bytes_sent += size; +- count -= size; +- } +-exit: +- /* lockless, but it's for debug info only... */ +- priv->bytes_out += bytes_sent; +- +- return bytes_sent; /* that's how much we wrote */ +-} +- +-static void klsi_105_write_bulk_callback(struct urb *urb) +-{ +- struct usb_serial_port *port = urb->context; +- int status = urb->status; +- +- dbg("%s - port %d", __func__, port->number); +- +- if (status) { +- dbg("%s - nonzero write bulk status received: %d", __func__, +- status); +- return; +- } +- +- usb_serial_port_softint(port); +-} +- +-/* return number of characters currently in the writing process */ +-static int klsi_105_chars_in_buffer(struct tty_struct *tty) ++#define KLSI_HDR_LEN 2 ++static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, ++ void *dest, size_t size) + { +- struct usb_serial_port *port = tty->driver_data; +- int chars = 0; +- int i; +- unsigned long flags; +- struct klsi_105_private *priv = usb_get_serial_port_data(port); +- +- spin_lock_irqsave(&priv->lock, flags); ++ unsigned char *buf = dest; ++ int count; + +- for (i = 0; i < NUM_URBS; ++i) { +- if (priv->write_urb_pool[i]->status == -EINPROGRESS) +- chars += URB_TRANSFER_BUFFER_SIZE; +- } +- +- spin_unlock_irqrestore(&priv->lock, flags); ++ count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size, ++ &port->lock); ++ put_unaligned_le16(count, buf); + +- dbg("%s - returns %d", __func__, chars); +- return chars; ++ return count + KLSI_HDR_LEN; + } + +-static int klsi_105_write_room(struct tty_struct *tty) +-{ +- struct usb_serial_port *port = tty->driver_data; +- unsigned long flags; +- int i; +- int room = 0; +- struct klsi_105_private *priv = usb_get_serial_port_data(port); +- +- spin_lock_irqsave(&priv->lock, flags); +- for (i = 0; i < NUM_URBS; ++i) { +- if (priv->write_urb_pool[i]->status != -EINPROGRESS) +- room += URB_TRANSFER_BUFFER_SIZE; +- } +- +- spin_unlock_irqrestore(&priv->lock, flags); +- +- dbg("%s - returns %d", __func__, room); +- return room; +-} +- +-static void klsi_105_read_bulk_callback(struct urb *urb) ++/* The data received is preceded by a length double-byte in LSB-first order. ++ */ ++static void klsi_105_process_read_urb(struct urb *urb) + { + struct usb_serial_port *port = urb->context; +- struct klsi_105_private *priv = usb_get_serial_port_data(port); +- struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; +- int rc; +- int status = urb->status; ++ struct tty_struct *tty; ++ unsigned len; + +- dbg("%s - port %d", __func__, port->number); ++ /* empty urbs seem to happen, we ignore them */ ++ if (!urb->actual_length) ++ return; + +- /* The urb might have been killed. */ +- if (status) { +- dbg("%s - nonzero read bulk status received: %d", __func__, +- status); ++ if (urb->actual_length <= KLSI_HDR_LEN) { ++ dbg("%s - malformed packet", __func__); + return; + } + +- /* The data received is again preceded by a length double-byte in LSB- +- * first order (see klsi_105_write() ) +- */ +- if (urb->actual_length == 0) { +- /* empty urbs seem to happen, we ignore them */ +- /* dbg("%s - emtpy URB", __func__); */ +- ; +- } else if (urb->actual_length <= 2) { +- dbg("%s - size %d URB not understood", __func__, +- urb->actual_length); +- usb_serial_debug_data(debug, &port->dev, __func__, +- urb->actual_length, data); +- } else { +- int bytes_sent = ((__u8 *) data)[0] + +- ((unsigned int) ((__u8 *) data)[1] << 8); +- tty = tty_port_tty_get(&port->port); +- /* we should immediately resubmit the URB, before attempting +- * to pass the data on to the tty layer. But that needs locking +- * against re-entry an then mixed-up data because of +- * intermixed tty_flip_buffer_push()s +- * FIXME +- */ +- usb_serial_debug_data(debug, &port->dev, __func__, +- urb->actual_length, data); ++ tty = tty_port_tty_get(&port->port); ++ if (!tty) ++ return; + +- if (bytes_sent + 2 > urb->actual_length) { +- dbg("%s - trying to read more data than available" +- " (%d vs. %d)", __func__, +- bytes_sent+2, urb->actual_length); +- /* cap at implied limit */ +- bytes_sent = urb->actual_length - 2; +- } ++ len = get_unaligned_le16(data); ++ if (len > urb->actual_length - KLSI_HDR_LEN) { ++ dbg("%s - packet length mismatch", __func__); ++ len = urb->actual_length - KLSI_HDR_LEN; ++ } + +- tty_insert_flip_string(tty, data + 2, bytes_sent); +- tty_flip_buffer_push(tty); +- tty_kref_put(tty); +- +- /* again lockless, but debug info only */ +- priv->bytes_in += bytes_sent; +- } +- /* Continue trying to always read */ +- usb_fill_bulk_urb(port->read_urb, port->serial->dev, +- usb_rcvbulkpipe(port->serial->dev, +- port->bulk_in_endpointAddress), +- port->read_urb->transfer_buffer, +- port->read_urb->transfer_buffer_length, +- klsi_105_read_bulk_callback, +- port); +- rc = usb_submit_urb(port->read_urb, GFP_ATOMIC); +- if (rc) +- dev_err(&port->dev, +- "%s - failed resubmitting read urb, error %d\n", +- __func__, rc); ++ tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len); ++ tty_flip_buffer_push(tty); ++ tty_kref_put(tty); + } + + static void klsi_105_set_termios(struct tty_struct *tty, +@@ -954,28 +690,6 @@ static int klsi_105_tiocmset(struct tty_ + return retval; + } + +-static void klsi_105_throttle(struct tty_struct *tty) +-{ +- struct usb_serial_port *port = tty->driver_data; +- dbg("%s - port %d", __func__, port->number); +- usb_kill_urb(port->read_urb); +-} +- +-static void klsi_105_unthrottle(struct tty_struct *tty) +-{ +- struct usb_serial_port *port = tty->driver_data; +- int result; +- +- dbg("%s - port %d", __func__, port->number); +- +- port->read_urb->dev = port->serial->dev; +- result = usb_submit_urb(port->read_urb, GFP_KERNEL); +- if (result) +- dev_err(&port->dev, +- "%s - failed submitting read urb, error %d\n", +- __func__, result); +-} +- + + static int __init klsi_105_init(void) + { diff --git a/usb/usb-musb-update-gfp-slab.h-includes.patch b/usb/usb-musb-update-gfp-slab.h-includes.patch new file mode 100644 index 00000000000000..03df19d39384b3 --- /dev/null +++ b/usb/usb-musb-update-gfp-slab.h-includes.patch @@ -0,0 +1,29 @@ +From sfr@canb.auug.org.au Thu May 20 10:59:27 2010 +From: Tejun Heo <tj@kernel.org> +Date: Thu, 20 May 2010 01:44:20 +1000 +Subject: usb: musb: update gfp/slab.h includes +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-next@vger.kernel.org, linux-kernel@vger.kernel.org, Tejun Heo <tj@kernel.org> +Message-ID: <20100520014420.22a0e715.sfr@canb.auug.org.au> + +Implicit slab.h inclusion via percpu.h is about to go away. Make sure +gfp.h or slab.h is included as necessary. + +Signed-off-by: Tejun Heo <tj@kernel.org> +Cc: Stephen Rothwell <sfr@canb.auug.org.au> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/musb_debugfs.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/usb/musb/musb_debugfs.c ++++ b/drivers/usb/musb/musb_debugfs.c +@@ -34,7 +34,6 @@ + #include <linux/module.h> + #include <linux/kernel.h> + #include <linux/sched.h> +-#include <linux/slab.h> + #include <linux/init.h> + #include <linux/list.h> + #include <linux/kobject.h> diff --git a/usb/usb-safe_serial-reimplement-read-using-generic-framework.patch b/usb/usb-safe_serial-reimplement-read-using-generic-framework.patch new file mode 100644 index 00000000000000..4aad8f00a97e54 --- /dev/null +++ b/usb/usb-safe_serial-reimplement-read-using-generic-framework.patch @@ -0,0 +1,97 @@ +From jhovold@gmail.com Thu May 20 10:57:01 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:31 +0200 +Subject: USB: safe_serial: reimplement read using generic framework +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-3-git-send-email-jhovold@gmail.com> + + +Use process_read_urb to implement read processing. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/safe_serial.c | 47 ++++++--------------------------------- + 1 file changed, 8 insertions(+), 39 deletions(-) + +--- a/drivers/usb/serial/safe_serial.c ++++ b/drivers/usb/serial/safe_serial.c +@@ -213,38 +213,20 @@ static __u16 __inline__ fcs_compute10(un + return fcs; + } + +-static void safe_read_bulk_callback(struct urb *urb) ++static void safe_process_read_urb(struct urb *urb) + { +- struct usb_serial_port *port = urb->context; ++ struct usb_serial_port *port = urb->context; + unsigned char *data = urb->transfer_buffer; + unsigned char length = urb->actual_length; + struct tty_struct *tty; +- int result; +- int status = urb->status; + +- dbg("%s", __func__); +- +- if (status) { +- dbg("%s - nonzero read bulk status received: %d", +- __func__, status); ++ if (!length) + return; +- } + +- dbg("safe_read_bulk_callback length: %d", +- port->read_urb->actual_length); +-#ifdef ECHO_RCV +- { +- int i; +- unsigned char *cp = port->read_urb->transfer_buffer; +- for (i = 0; i < port->read_urb->actual_length; i++) { +- if ((i % 32) == 0) +- printk("\nru[%02x] ", i); +- printk("%02x ", *cp++); +- } +- printk("\n"); +- } +-#endif + tty = tty_port_tty_get(&port->port); ++ if (!tty) ++ return; ++ + if (safe) { + __u16 fcs; + fcs = fcs_compute10(data, length, CRC10_INITFCS); +@@ -268,21 +250,8 @@ static void safe_read_bulk_callback(stru + tty_insert_flip_string(tty, data, length); + tty_flip_buffer_push(tty); + } +- tty_kref_put(tty); + +- /* Continue trying to always read */ +- usb_fill_bulk_urb(urb, port->serial->dev, +- usb_rcvbulkpipe(port->serial->dev, +- port->bulk_in_endpointAddress), +- urb->transfer_buffer, urb->transfer_buffer_length, +- safe_read_bulk_callback, port); +- +- result = usb_submit_urb(urb, GFP_ATOMIC); +- if (result) +- dev_err(&port->dev, +- "%s - failed resubmitting read urb, error %d\n", +- __func__, result); +- /* FIXME: Need a mechanism to retry later if this happens */ ++ tty_kref_put(tty); + } + + static int safe_prepare_write_buffer(struct usb_serial_port *port, +@@ -343,7 +312,7 @@ static struct usb_serial_driver safe_dev + .id_table = id_table, + .usb_driver = &safe_driver, + .num_ports = 1, +- .read_bulk_callback = safe_read_bulk_callback, ++ .process_read_urb = safe_process_read_urb, + .prepare_write_buffer = safe_prepare_write_buffer, + .attach = safe_startup, + }; diff --git a/usb/usb-safe_serial-reimplement-write-using-generic-framework.patch b/usb/usb-safe_serial-reimplement-write-using-generic-framework.patch new file mode 100644 index 00000000000000..a2f927462f9a85 --- /dev/null +++ b/usb/usb-safe_serial-reimplement-write-using-generic-framework.patch @@ -0,0 +1,204 @@ +From jhovold@gmail.com Thu May 20 10:56:47 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:30 +0200 +Subject: USB: safe_serial: reimplement write using generic framework +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-2-git-send-email-jhovold@gmail.com> + + +Kill custom single-urb write implementation. + +Note that this driver still depended on the write callback from the old +generic framework. + +Tested against original read processing using a cp210x device in a +loopback setup. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/safe_serial.c | 143 ++++++++------------------------------- + 1 file changed, 32 insertions(+), 111 deletions(-) + +--- a/drivers/usb/serial/safe_serial.c ++++ b/drivers/usb/serial/safe_serial.c +@@ -1,6 +1,7 @@ + /* + * Safe Encapsulated USB Serial Driver + * ++ * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> + * Copyright (C) 2001 Lineo + * Copyright (C) 2001 Hewlett-Packard + * +@@ -84,8 +85,8 @@ static int debug; + static int safe = 1; + static int padded = CONFIG_USB_SERIAL_SAFE_PADDED; + +-#define DRIVER_VERSION "v0.0b" +-#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com" ++#define DRIVER_VERSION "v0.1" ++#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>" + #define DRIVER_DESC "USB Safe Encapsulated Serial" + + MODULE_AUTHOR(DRIVER_AUTHOR); +@@ -284,119 +285,40 @@ static void safe_read_bulk_callback(stru + /* FIXME: Need a mechanism to retry later if this happens */ + } + +-static int safe_write(struct tty_struct *tty, struct usb_serial_port *port, +- const unsigned char *buf, int count) ++static int safe_prepare_write_buffer(struct usb_serial_port *port, ++ void *dest, size_t size) + { +- unsigned char *data; +- int result; +- int i; +- int packet_length; +- +- dbg("safe_write port: %p %d urb: %p count: %d", +- port, port->number, port->write_urb, count); +- +- if (!port->write_urb) { +- dbg("%s - write urb NULL", __func__); +- return 0; +- } +- +- dbg("safe_write write_urb: %d transfer_buffer_length", +- port->write_urb->transfer_buffer_length); +- +- if (!port->write_urb->transfer_buffer_length) { +- dbg("%s - write urb transfer_buffer_length zero", __func__); +- return 0; +- } +- if (count == 0) { +- dbg("%s - write request of 0 bytes", __func__); +- return 0; +- } +- spin_lock_bh(&port->lock); +- if (port->write_urb_busy) { +- spin_unlock_bh(&port->lock); +- dbg("%s - already writing", __func__); +- return 0; +- } +- port->write_urb_busy = 1; +- spin_unlock_bh(&port->lock); +- +- packet_length = port->bulk_out_size; /* get max packetsize */ +- +- i = packet_length - (safe ? 2 : 0); /* get bytes to send */ +- count = (count > i) ? i : count; +- +- +- /* get the data into the transfer buffer */ +- data = port->write_urb->transfer_buffer; +- memset(data, '0', packet_length); +- +- memcpy(data, buf, count); +- +- if (safe) { +- __u16 fcs; +- +- /* pad if necessary */ +- if (!padded) +- packet_length = count + 2; +- /* set count */ +- data[packet_length - 2] = count << 2; +- data[packet_length - 1] = 0; +- +- /* compute fcs and insert into trailer */ +- fcs = fcs_compute10(data, packet_length, CRC10_INITFCS); +- data[packet_length - 2] |= fcs >> 8; +- data[packet_length - 1] |= fcs & 0xff; +- +- /* set length to send */ +- port->write_urb->transfer_buffer_length = packet_length; ++ unsigned char *buf = dest; ++ int count; ++ int trailer_len; ++ int pkt_len; ++ __u16 fcs; ++ ++ trailer_len = safe ? 2 : 0; ++ ++ count = kfifo_out_locked(&port->write_fifo, buf, size - trailer_len, ++ &port->lock); ++ if (!safe) ++ return count; ++ ++ /* pad if necessary */ ++ if (padded) { ++ pkt_len = size; ++ memset(buf + count, '0', pkt_len - count - trailer_len); + } else { +- port->write_urb->transfer_buffer_length = count; ++ pkt_len = count + trailer_len; + } + +- usb_serial_debug_data(debug, &port->dev, __func__, count, +- port->write_urb->transfer_buffer); +-#ifdef ECHO_TX +- { +- int i; +- unsigned char *cp = port->write_urb->transfer_buffer; +- for (i = 0; i < port->write_urb->transfer_buffer_length; i++) { +- if ((i % 32) == 0) +- printk("\nsu[%02x] ", i); +- printk("%02x ", *cp++); +- } +- printk("\n"); +- } +-#endif +- port->write_urb->dev = port->serial->dev; +- result = usb_submit_urb(port->write_urb, GFP_KERNEL); +- if (result) { +- port->write_urb_busy = 0; +- dev_err(&port->dev, +- "%s - failed submitting write urb, error %d\n", +- __func__, result); +- return 0; +- } +- dbg("%s urb: %p submitted", __func__, port->write_urb); +- +- return count; +-} +- +-static int safe_write_room(struct tty_struct *tty) +-{ +- struct usb_serial_port *port = tty->driver_data; +- int room = 0; /* Default: no room */ +- unsigned long flags; ++ /* set count */ ++ buf[pkt_len - 2] = count << 2; ++ buf[pkt_len - 1] = 0; + +- dbg("%s", __func__); ++ /* compute fcs and insert into trailer */ ++ fcs = fcs_compute10(buf, pkt_len, CRC10_INITFCS); ++ buf[pkt_len - 2] |= fcs >> 8; ++ buf[pkt_len - 1] |= fcs & 0xff; + +- spin_lock_irqsave(&port->lock, flags); +- if (port->write_urb_busy) +- room = port->bulk_out_size - (safe ? 2 : 0); +- spin_unlock_irqrestore(&port->lock, flags); +- +- if (room) +- dbg("safe_write_room returns %d", room); +- return room; ++ return pkt_len; + } + + static int safe_startup(struct usb_serial *serial) +@@ -421,9 +343,8 @@ static struct usb_serial_driver safe_dev + .id_table = id_table, + .usb_driver = &safe_driver, + .num_ports = 1, +- .write = safe_write, +- .write_room = safe_write_room, + .read_bulk_callback = safe_read_bulk_callback, ++ .prepare_write_buffer = safe_prepare_write_buffer, + .attach = safe_startup, + }; + diff --git a/usb/usb-safe_serial-straighten-out-read-processing.patch b/usb/usb-safe_serial-straighten-out-read-processing.patch new file mode 100644 index 00000000000000..80bcd6bc172bf9 --- /dev/null +++ b/usb/usb-safe_serial-straighten-out-read-processing.patch @@ -0,0 +1,82 @@ +From jhovold@gmail.com Thu May 20 10:57:10 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:32 +0200 +Subject: USB: safe_serial: straighten out read processing +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-4-git-send-email-jhovold@gmail.com> + + +Clean up read processing logic. + +Tested using a cp210x device in a loopback setup. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/safe_serial.c | 43 +++++++++++++++++++-------------------- + 1 file changed, 21 insertions(+), 22 deletions(-) + +--- a/drivers/usb/serial/safe_serial.c ++++ b/drivers/usb/serial/safe_serial.c +@@ -218,7 +218,9 @@ static void safe_process_read_urb(struct + struct usb_serial_port *port = urb->context; + unsigned char *data = urb->transfer_buffer; + unsigned char length = urb->actual_length; ++ int actual_length; + struct tty_struct *tty; ++ __u16 fcs; + + if (!length) + return; +@@ -227,30 +229,27 @@ static void safe_process_read_urb(struct + if (!tty) + return; + +- if (safe) { +- __u16 fcs; +- fcs = fcs_compute10(data, length, CRC10_INITFCS); +- if (!fcs) { +- int actual_length = data[length - 2] >> 2; +- if (actual_length <= (length - 2)) { +- dev_info(&urb->dev->dev, "%s - actual: %d\n", +- __func__, actual_length); +- tty_insert_flip_string(tty, +- data, actual_length); +- tty_flip_buffer_push(tty); +- } else { +- dev_err(&port->dev, +- "%s - inconsistent lengths %d:%d\n", +- __func__, actual_length, length); +- } +- } else { +- dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs); +- } +- } else { +- tty_insert_flip_string(tty, data, length); +- tty_flip_buffer_push(tty); ++ if (!safe) ++ goto out; ++ ++ fcs = fcs_compute10(data, length, CRC10_INITFCS); ++ if (fcs) { ++ dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs); ++ goto err; + } + ++ actual_length = data[length - 2] >> 2; ++ if (actual_length > (length - 2)) { ++ dev_err(&port->dev, "%s - inconsistent lengths %d:%d\n", ++ __func__, actual_length, length); ++ goto err; ++ } ++ dev_info(&urb->dev->dev, "%s - actual: %d\n", __func__, actual_length); ++ length = actual_length; ++out: ++ tty_insert_flip_string(tty, data, length); ++ tty_flip_buffer_push(tty); ++err: + tty_kref_put(tty); + } + diff --git a/usb/usb-ti_usb-use-kfifo-to-implement-write-buffering.patch b/usb/usb-ti_usb-use-kfifo-to-implement-write-buffering.patch new file mode 100644 index 00000000000000..6a792b738ead11 --- /dev/null +++ b/usb/usb-ti_usb-use-kfifo-to-implement-write-buffering.patch @@ -0,0 +1,302 @@ +From jhovold@gmail.com Thu May 20 10:57:53 2010 +From: Johan Hovold <jhovold@gmail.com> +Date: Wed, 19 May 2010 00:01:35 +0200 +Subject: USB: ti_usb: use kfifo to implement write buffering +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com> +Message-ID: <1274220101-13873-7-git-send-email-jhovold@gmail.com> + + +Kill custom fifo implementation. + +Compile-only tested. + +Signed-off-by: Johan Hovold <jhovold@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/serial/ti_usb_3410_5052.c | 179 ++-------------------------------- + 1 file changed, 14 insertions(+), 165 deletions(-) + +--- a/drivers/usb/serial/ti_usb_3410_5052.c ++++ b/drivers/usb/serial/ti_usb_3410_5052.c +@@ -30,7 +30,7 @@ + #include <linux/spinlock.h> + #include <linux/ioctl.h> + #include <linux/serial.h> +-#include <linux/circ_buf.h> ++#include <linux/kfifo.h> + #include <linux/mutex.h> + #include <linux/uaccess.h> + #include <linux/usb.h> +@@ -40,7 +40,7 @@ + + /* Defines */ + +-#define TI_DRIVER_VERSION "v0.9" ++#define TI_DRIVER_VERSION "v0.10" + #define TI_DRIVER_AUTHOR "Al Borchers <alborchers@steinerpoint.com>" + #define TI_DRIVER_DESC "TI USB 3410/5052 Serial Driver" + +@@ -82,7 +82,7 @@ struct ti_port { + spinlock_t tp_lock; + int tp_read_urb_state; + int tp_write_urb_in_use; +- struct circ_buf *tp_write_buf; ++ struct kfifo write_fifo; + }; + + struct ti_device { +@@ -144,15 +144,6 @@ static int ti_write_byte(struct ti_devic + + static int ti_download_firmware(struct ti_device *tdev); + +-/* circular buffer */ +-static struct circ_buf *ti_buf_alloc(void); +-static void ti_buf_free(struct circ_buf *cb); +-static void ti_buf_clear(struct circ_buf *cb); +-static int ti_buf_data_avail(struct circ_buf *cb); +-static int ti_buf_space_avail(struct circ_buf *cb); +-static int ti_buf_put(struct circ_buf *cb, const char *buf, int count); +-static int ti_buf_get(struct circ_buf *cb, char *buf, int count); +- + + /* Data */ + +@@ -450,8 +441,8 @@ static int ti_startup(struct usb_serial + tport->tp_closing_wait = closing_wait; + init_waitqueue_head(&tport->tp_msr_wait); + init_waitqueue_head(&tport->tp_write_wait); +- tport->tp_write_buf = ti_buf_alloc(); +- if (tport->tp_write_buf == NULL) { ++ if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, ++ GFP_KERNEL)) { + dev_err(&dev->dev, "%s - out of memory\n", __func__); + kfree(tport); + status = -ENOMEM; +@@ -468,7 +459,7 @@ static int ti_startup(struct usb_serial + free_tports: + for (--i; i >= 0; --i) { + tport = usb_get_serial_port_data(serial->port[i]); +- ti_buf_free(tport->tp_write_buf); ++ kfifo_free(&tport->write_fifo); + kfree(tport); + usb_set_serial_port_data(serial->port[i], NULL); + } +@@ -490,7 +481,7 @@ static void ti_release(struct usb_serial + for (i = 0; i < serial->num_ports; ++i) { + tport = usb_get_serial_port_data(serial->port[i]); + if (tport) { +- ti_buf_free(tport->tp_write_buf); ++ kfifo_free(&tport->write_fifo); + kfree(tport); + } + } +@@ -701,7 +692,6 @@ static int ti_write(struct tty_struct *t + const unsigned char *data, int count) + { + struct ti_port *tport = usb_get_serial_port_data(port); +- unsigned long flags; + + dbg("%s - port %d", __func__, port->number); + +@@ -713,10 +703,8 @@ static int ti_write(struct tty_struct *t + if (tport == NULL || !tport->tp_is_open) + return -ENODEV; + +- spin_lock_irqsave(&tport->tp_lock, flags); +- count = ti_buf_put(tport->tp_write_buf, data, count); +- spin_unlock_irqrestore(&tport->tp_lock, flags); +- ++ count = kfifo_in_locked(&tport->write_fifo, data, count, ++ &tport->tp_lock); + ti_send(tport); + + return count; +@@ -736,7 +724,7 @@ static int ti_write_room(struct tty_stru + return 0; + + spin_lock_irqsave(&tport->tp_lock, flags); +- room = ti_buf_space_avail(tport->tp_write_buf); ++ room = kfifo_avail(&tport->write_fifo); + spin_unlock_irqrestore(&tport->tp_lock, flags); + + dbg("%s - returns %d", __func__, room); +@@ -757,7 +745,7 @@ static int ti_chars_in_buffer(struct tty + return 0; + + spin_lock_irqsave(&tport->tp_lock, flags); +- chars = ti_buf_data_avail(tport->tp_write_buf); ++ chars = kfifo_len(&tport->write_fifo); + spin_unlock_irqrestore(&tport->tp_lock, flags); + + dbg("%s - returns %d", __func__, chars); +@@ -1309,7 +1297,7 @@ static void ti_send(struct ti_port *tpor + if (tport->tp_write_urb_in_use) + goto unlock; + +- count = ti_buf_get(tport->tp_write_buf, ++ count = kfifo_out(&tport->write_fifo, + port->write_urb->transfer_buffer, + port->bulk_out_size); + +@@ -1504,7 +1492,7 @@ static void ti_drain(struct ti_port *tpo + add_wait_queue(&tport->tp_write_wait, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); +- if (ti_buf_data_avail(tport->tp_write_buf) == 0 ++ if (kfifo_len(&tport->write_fifo) == 0 + || timeout == 0 || signal_pending(current) + || tdev->td_urb_error + || port->serial->disconnected) /* disconnect */ +@@ -1518,7 +1506,7 @@ static void ti_drain(struct ti_port *tpo + + /* flush any remaining data in the buffer */ + if (flush) +- ti_buf_clear(tport->tp_write_buf); ++ kfifo_reset_out(&tport->write_fifo); + + spin_unlock_irq(&tport->tp_lock); + +@@ -1761,142 +1749,3 @@ static int ti_download_firmware(struct t + + return 0; + } +- +- +-/* Circular Buffer Functions */ +- +-/* +- * ti_buf_alloc +- * +- * Allocate a circular buffer and all associated memory. +- */ +- +-static struct circ_buf *ti_buf_alloc(void) +-{ +- struct circ_buf *cb; +- +- cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL); +- if (cb == NULL) +- return NULL; +- +- cb->buf = kmalloc(TI_WRITE_BUF_SIZE, GFP_KERNEL); +- if (cb->buf == NULL) { +- kfree(cb); +- return NULL; +- } +- +- ti_buf_clear(cb); +- +- return cb; +-} +- +- +-/* +- * ti_buf_free +- * +- * Free the buffer and all associated memory. +- */ +- +-static void ti_buf_free(struct circ_buf *cb) +-{ +- kfree(cb->buf); +- kfree(cb); +-} +- +- +-/* +- * ti_buf_clear +- * +- * Clear out all data in the circular buffer. +- */ +- +-static void ti_buf_clear(struct circ_buf *cb) +-{ +- cb->head = cb->tail = 0; +-} +- +- +-/* +- * ti_buf_data_avail +- * +- * Return the number of bytes of data available in the circular +- * buffer. +- */ +- +-static int ti_buf_data_avail(struct circ_buf *cb) +-{ +- return CIRC_CNT(cb->head, cb->tail, TI_WRITE_BUF_SIZE); +-} +- +- +-/* +- * ti_buf_space_avail +- * +- * Return the number of bytes of space available in the circular +- * buffer. +- */ +- +-static int ti_buf_space_avail(struct circ_buf *cb) +-{ +- return CIRC_SPACE(cb->head, cb->tail, TI_WRITE_BUF_SIZE); +-} +- +- +-/* +- * ti_buf_put +- * +- * Copy data data from a user buffer and put it into the circular buffer. +- * Restrict to the amount of space available. +- * +- * Return the number of bytes copied. +- */ +- +-static int ti_buf_put(struct circ_buf *cb, const char *buf, int count) +-{ +- int c, ret = 0; +- +- while (1) { +- c = CIRC_SPACE_TO_END(cb->head, cb->tail, TI_WRITE_BUF_SIZE); +- if (count < c) +- c = count; +- if (c <= 0) +- break; +- memcpy(cb->buf + cb->head, buf, c); +- cb->head = (cb->head + c) & (TI_WRITE_BUF_SIZE-1); +- buf += c; +- count -= c; +- ret += c; +- } +- +- return ret; +-} +- +- +-/* +- * ti_buf_get +- * +- * Get data from the circular buffer and copy to the given buffer. +- * Restrict to the amount of data available. +- * +- * Return the number of bytes copied. +- */ +- +-static int ti_buf_get(struct circ_buf *cb, char *buf, int count) +-{ +- int c, ret = 0; +- +- while (1) { +- c = CIRC_CNT_TO_END(cb->head, cb->tail, TI_WRITE_BUF_SIZE); +- if (count < c) +- c = count; +- if (c <= 0) +- break; +- memcpy(buf, cb->buf + cb->tail, c); +- cb->tail = (cb->tail + c) & (TI_WRITE_BUF_SIZE-1); +- buf += c; +- count -= c; +- ret += c; +- } +- +- return ret; +-} diff --git a/usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch b/usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch index 7d371450313f57..1e8ffcb7b1c963 100644 --- a/usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch +++ b/usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch @@ -179,7 +179,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> SCT_FOR_CTX(SCT_PRI_TR) | --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -295,7 +295,8 @@ void xhci_ring_cmd_db(struct xhci_hcd *x +@@ -312,7 +312,8 @@ void xhci_ring_cmd_db(struct xhci_hcd *x static void ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, @@ -189,7 +189,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> { struct xhci_virt_ep *ep; unsigned int ep_state; -@@ -314,7 +315,8 @@ static void ring_ep_doorbell(struct xhci +@@ -331,7 +332,8 @@ static void ring_ep_doorbell(struct xhci if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING) && !(ep_state & EP_HALTED)) { field = xhci_readl(xhci, db_addr) & DB_MASK; @@ -199,7 +199,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* Flush PCI posted writes - FIXME Matthew Wilcox says this * isn't time-critical and we shouldn't make the CPU wait for * the flush. -@@ -323,6 +325,31 @@ static void ring_ep_doorbell(struct xhci +@@ -340,6 +342,31 @@ static void ring_ep_doorbell(struct xhci } } @@ -231,7 +231,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* * Find the segment that trb is in. Start searching in start_seg. * If we must move past a segment that has a link TRB with a toggle cycle state -@@ -365,14 +392,23 @@ static struct xhci_segment *find_trb_seg +@@ -382,14 +409,23 @@ static struct xhci_segment *find_trb_seg */ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, @@ -257,7 +257,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> state->new_cycle_state = 0; xhci_dbg(xhci, "Finding segment containing stopped TRB.\n"); state->new_deq_seg = find_trb_seg(cur_td->start_seg, -@@ -452,11 +488,13 @@ static void td_to_noop(struct xhci_hcd * +@@ -469,11 +505,13 @@ static void td_to_noop(struct xhci_hcd * } static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, @@ -272,7 +272,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> struct xhci_dequeue_state *deq_state) { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; -@@ -468,7 +506,7 @@ void xhci_queue_new_dequeue_state(struct +@@ -485,7 +523,7 @@ void xhci_queue_new_dequeue_state(struct deq_state->new_deq_ptr, (unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr), deq_state->new_cycle_state); @@ -281,7 +281,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> deq_state->new_deq_seg, deq_state->new_deq_ptr, (u32) deq_state->new_cycle_state); -@@ -536,11 +574,10 @@ static void handle_stopped_endpoint(stru +@@ -553,11 +591,10 @@ static void handle_stopped_endpoint(stru slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); ep = &xhci->devs[slot_id]->eps[ep_index]; @@ -294,7 +294,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> return; } -@@ -554,15 +591,36 @@ static void handle_stopped_endpoint(stru +@@ -571,15 +608,36 @@ static void handle_stopped_endpoint(stru xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n", cur_td->first_trb, (unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb)); @@ -333,7 +333,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* * The event handler won't see a completion for this TD anymore, * so remove it from the endpoint ring's TD list. Keep it in -@@ -576,11 +634,13 @@ static void handle_stopped_endpoint(stru +@@ -593,11 +651,13 @@ static void handle_stopped_endpoint(stru /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { xhci_queue_new_dequeue_state(xhci, @@ -350,7 +350,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } ep->stopped_td = NULL; ep->stopped_trb = NULL; -@@ -740,6 +800,7 @@ static void handle_set_deq_completion(st +@@ -757,6 +817,7 @@ static void handle_set_deq_completion(st { unsigned int slot_id; unsigned int ep_index; @@ -358,7 +358,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> struct xhci_ring *ep_ring; struct xhci_virt_device *dev; struct xhci_ep_ctx *ep_ctx; -@@ -747,8 +808,19 @@ static void handle_set_deq_completion(st +@@ -764,8 +825,19 @@ static void handle_set_deq_completion(st slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); @@ -379,7 +379,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); -@@ -793,7 +865,8 @@ static void handle_set_deq_completion(st +@@ -810,7 +882,8 @@ static void handle_set_deq_completion(st } dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING; @@ -389,7 +389,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } static void handle_reset_ep_completion(struct xhci_hcd *xhci, -@@ -802,11 +875,9 @@ static void handle_reset_ep_completion(s +@@ -819,11 +892,9 @@ static void handle_reset_ep_completion(s { int slot_id; unsigned int ep_index; @@ -401,7 +401,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* This command will only fail if the endpoint wasn't halted, * but we don't care. */ -@@ -824,9 +895,9 @@ static void handle_reset_ep_completion(s +@@ -841,9 +912,9 @@ static void handle_reset_ep_completion(s false); xhci_ring_cmd_db(xhci); } else { @@ -413,7 +413,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } } -@@ -912,8 +983,10 @@ static void handle_cmd_completion(struct +@@ -929,8 +1000,10 @@ static void handle_cmd_completion(struct /* Input ctx add_flags are the endpoint index plus one */ ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1; /* A usb_set_interface() call directly after clearing a halted @@ -426,7 +426,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> */ if (xhci->quirks & XHCI_RESET_EP_QUIRK && ep_index != (unsigned int) -1 && -@@ -926,10 +999,10 @@ static void handle_cmd_completion(struct +@@ -943,10 +1016,10 @@ static void handle_cmd_completion(struct xhci_dbg(xhci, "Completed config ep cmd - " "last ep index = %d, state = %d\n", ep_index, ep_state); @@ -439,7 +439,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> break; } bandwidth_change: -@@ -1062,12 +1135,14 @@ struct xhci_segment *trb_in_td(struct xh +@@ -1079,12 +1152,14 @@ struct xhci_segment *trb_in_td(struct xh static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, @@ -454,7 +454,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> xhci_queue_reset_ep(xhci, slot_id, ep_index); xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index); -@@ -1152,10 +1227,11 @@ static int handle_tx_event(struct xhci_h +@@ -1169,10 +1244,11 @@ static int handle_tx_event(struct xhci_h ep_index = TRB_TO_EP_ID(event->flags) - 1; xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index); ep = &xdev->eps[ep_index]; @@ -468,7 +468,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> return -ENODEV; } -@@ -1286,7 +1362,7 @@ static int handle_tx_event(struct xhci_h +@@ -1303,7 +1379,7 @@ static int handle_tx_event(struct xhci_h td->urb->actual_length = 0; xhci_cleanup_halted_endpoint(xhci, @@ -477,7 +477,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> goto td_cleanup; } /* -@@ -1435,6 +1511,7 @@ static int handle_tx_event(struct xhci_h +@@ -1452,6 +1528,7 @@ static int handle_tx_event(struct xhci_h */ ep->stopped_td = td; ep->stopped_trb = event_trb; @@ -485,7 +485,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } else if (xhci_requires_manual_halt_cleanup(xhci, ep_ctx, trb_comp_code)) { /* Other types of errors halt the endpoint, but the -@@ -1443,7 +1520,7 @@ static int handle_tx_event(struct xhci_h +@@ -1460,7 +1537,7 @@ static int handle_tx_event(struct xhci_h * xHCI hardware manually. */ xhci_cleanup_halted_endpoint(xhci, @@ -494,7 +494,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } else { /* Update ring dequeue pointer */ while (ep_ring->dequeue != td->last_trb) -@@ -1639,14 +1716,24 @@ static int prepare_ring(struct xhci_hcd +@@ -1656,14 +1733,24 @@ static int prepare_ring(struct xhci_hcd static int prepare_transfer(struct xhci_hcd *xhci, struct xhci_virt_device *xdev, unsigned int ep_index, @@ -520,7 +520,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> ep_ctx->ep_info & EP_STATE_MASK, num_trbs, mem_flags); if (ret) -@@ -1666,9 +1753,9 @@ static int prepare_transfer(struct xhci_ +@@ -1683,9 +1770,9 @@ static int prepare_transfer(struct xhci_ (*td)->urb = urb; urb->hcpriv = (void *) (*td); /* Add this TD to the tail of the endpoint ring's TD list */ @@ -533,7 +533,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> return 0; } -@@ -1734,7 +1821,7 @@ static void check_trb_math(struct urb *u +@@ -1751,7 +1838,7 @@ static void check_trb_math(struct urb *u } static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id, @@ -542,7 +542,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> struct xhci_generic_trb *start_trb, struct xhci_td *td) { /* -@@ -1743,7 +1830,7 @@ static void giveback_first_trb(struct xh +@@ -1760,7 +1847,7 @@ static void giveback_first_trb(struct xh */ wmb(); start_trb->field[3] |= start_cycle; @@ -551,7 +551,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } /* -@@ -1817,12 +1904,16 @@ static int queue_bulk_sg_tx(struct xhci_ +@@ -1834,12 +1921,16 @@ static int queue_bulk_sg_tx(struct xhci_ struct xhci_generic_trb *start_trb; int start_cycle; @@ -570,7 +570,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> if (trb_buff_len < 0) return trb_buff_len; /* -@@ -1931,7 +2022,8 @@ static int queue_bulk_sg_tx(struct xhci_ +@@ -1948,7 +2039,8 @@ static int queue_bulk_sg_tx(struct xhci_ } while (running_total < urb->transfer_buffer_length); check_trb_math(urb, num_trbs, running_total); @@ -580,7 +580,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> return 0; } -@@ -1953,7 +2045,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd * +@@ -1970,7 +2062,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd * if (urb->num_sgs) return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index); @@ -591,7 +591,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> num_trbs = 0; /* How much data is (potentially) left before the 64KB boundary? */ -@@ -1980,7 +2074,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * +@@ -1997,7 +2091,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * (unsigned long long)urb->transfer_dma, num_trbs); @@ -601,7 +601,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> num_trbs, urb, &td, mem_flags); if (ret < 0) return ret; -@@ -2050,7 +2145,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * +@@ -2067,7 +2162,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * } while (running_total < urb->transfer_buffer_length); check_trb_math(urb, num_trbs, running_total); @@ -611,7 +611,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> return 0; } -@@ -2067,7 +2163,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * +@@ -2084,7 +2180,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * u32 field, length_field; struct xhci_td *td; @@ -622,7 +622,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* * Need to copy setup packet into setup TRB, so we can't use the setup -@@ -2088,8 +2186,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * +@@ -2105,8 +2203,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * */ if (urb->transfer_buffer_length > 0) num_trbs++; @@ -634,7 +634,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> if (ret < 0) return ret; -@@ -2144,7 +2243,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * +@@ -2161,7 +2260,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * /* Event on completion */ field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); @@ -644,7 +644,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> return 0; } -@@ -2256,12 +2356,14 @@ int xhci_queue_stop_endpoint(struct xhci +@@ -2273,12 +2373,14 @@ int xhci_queue_stop_endpoint(struct xhci * This should not be used for endpoints that have streams enabled. */ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, @@ -660,7 +660,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> u32 type = TRB_TYPE(TRB_SET_DEQ); addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr); -@@ -2272,7 +2374,7 @@ static int queue_set_tr_deq(struct xhci_ +@@ -2289,7 +2391,7 @@ static int queue_set_tr_deq(struct xhci_ return 0; } return queue_command(xhci, lower_32_bits(addr) | cycle_state, diff --git a/usb/usb-xhci-fix-check-for-room-on-the-ring.patch b/usb/usb-xhci-fix-check-for-room-on-the-ring.patch new file mode 100644 index 00000000000000..096f3c94f33557 --- /dev/null +++ b/usb/usb-xhci-fix-check-for-room-on-the-ring.patch @@ -0,0 +1,66 @@ +From sarah.a.sharp@linux.intel.com Thu May 20 10:48:52 2010 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Tue, 18 May 2010 16:05:26 -0700 +Subject: USB: xhci: Fix check for room on the ring. +To: Greg KH <gregkh@suse.de> +Cc: John Youn <John.Youn@synopsys.com>, linux-usb@vger.kernel.org +Message-ID: <20100518230526.GA6092@xanatos> +Content-Disposition: inline + + +The length of the scatter gather list a driver can enqueue is limited by +the bus' sg_tablesize to 62 entries. Each entry will be described by at +least one transfer request block (TRB). If the entry's buffer crosses a +64KB boundary, then that entry will have to be described by two or more +TRBs. So even if the USB device driver respects sg_tablesize, the whole +scatter list may take more than 62 TRBs to describe, and won't fit on +the ring. + +Don't assume that an empty ring means there is enough room on the +transfer ring. The old code would unconditionally queue this too-large +transfer, and over write the beginning of the transfer. This would mean +the cycle bit was unchanged in those overwritten transfers, causing the +hardware to think it didn't own the TRBs, and the host would seem to +hang. + +Now drivers may see submit_urb() fail with -ENOMEM if the transfers are +too big to fit on the ring. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -242,10 +242,27 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, + int i; + union xhci_trb *enq = ring->enqueue; + struct xhci_segment *enq_seg = ring->enq_seg; ++ struct xhci_segment *cur_seg; ++ unsigned int left_on_ring; + + /* Check if ring is empty */ +- if (enq == ring->dequeue) ++ if (enq == ring->dequeue) { ++ /* Can't use link trbs */ ++ left_on_ring = TRBS_PER_SEGMENT - 1; ++ for (cur_seg = enq_seg->next; cur_seg != enq_seg; ++ cur_seg = cur_seg->next) ++ left_on_ring += TRBS_PER_SEGMENT - 1; ++ ++ /* Always need one TRB free in the ring. */ ++ left_on_ring -= 1; ++ if (num_trbs > left_on_ring) { ++ xhci_warn(xhci, "Not enough room on ring; " ++ "need %u TRBs, %u TRBs left\n", ++ num_trbs, left_on_ring); ++ return 0; ++ } + return 1; ++ } + /* Make sure there's an extra empty TRB available */ + for (i = 0; i <= num_trbs; ++i) { + if (enq == ring->dequeue) +-- +1.6.3.3 + diff --git a/usb/usb-xhci-fix-compiler-warning.patch b/usb/usb-xhci-fix-compiler-warning.patch index 869d4e16460771..30a22e21f59830 100644 --- a/usb/usb-xhci-fix-compiler-warning.patch +++ b/usb/usb-xhci-fix-compiler-warning.patch @@ -14,7 +14,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -1726,7 +1726,6 @@ static int prepare_ring(struct xhci_hcd +@@ -1743,7 +1743,6 @@ static int prepare_ring(struct xhci_hcd if (enqueue_is_link_trb(ep_ring)) { struct xhci_ring *ring = ep_ring; union xhci_trb *next; diff --git a/usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch b/usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch index 4e7dd916de1bb7..3a6ac0d146da24 100644 --- a/usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch +++ b/usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch @@ -22,7 +22,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -373,7 +373,8 @@ static struct xhci_segment *find_trb_seg +@@ -390,7 +390,8 @@ static struct xhci_segment *find_trb_seg while (cur_seg->trbs > trb || &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) { generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic; @@ -32,7 +32,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> (generic_trb->field[3] & LINK_TOGGLE)) *cycle_state = ~(*cycle_state) & 0x1; cur_seg = cur_seg->next; -@@ -438,7 +439,7 @@ void xhci_find_new_dequeue_state(struct +@@ -455,7 +456,7 @@ void xhci_find_new_dequeue_state(struct BUG(); trb = &state->new_deq_ptr->generic; @@ -41,7 +41,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> (trb->field[3] & LINK_TOGGLE)) state->new_cycle_state = ~(state->new_cycle_state) & 0x1; next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); -@@ -1487,8 +1488,10 @@ static int handle_tx_event(struct xhci_h +@@ -1504,8 +1505,10 @@ static int handle_tx_event(struct xhci_h for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; cur_trb != event_trb; next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { diff --git a/usb/usb-xhci-limit-bus-sg_tablesize-to-62-trbs.patch b/usb/usb-xhci-limit-bus-sg_tablesize-to-62-trbs.patch new file mode 100644 index 00000000000000..591281de20fb36 --- /dev/null +++ b/usb/usb-xhci-limit-bus-sg_tablesize-to-62-trbs.patch @@ -0,0 +1,36 @@ +From sarah.a.sharp@linux.intel.com Thu May 20 10:48:18 2010 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Tue, 18 May 2010 16:05:21 -0700 +Subject: USB: xhci: Limit bus sg_tablesize to 62 TRBs. +To: Greg KH <gregkh@suse.de> +Cc: John Youn <John.Youn@synopsys.com>, linux-usb@vger.kernel.org +Message-ID: <20100518230521.GA6036@xanatos> +Content-Disposition: inline + + +When a scatter-gather list is enqueued to the xHCI driver, it translates +each entry into a transfer request block (TRB). Only 63 TRBs can be +used per ring segment, and there must be one additional TRB reserved to +make sure the hardware does not think the ring is empty (so the enqueue +pointer doesn't equal the dequeue pointer). Limit the bus sg_tablesize +to 62 TRBs. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -54,7 +54,7 @@ static int xhci_pci_setup(struct usb_hcd + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + int retval; + +- hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 1; ++ hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; + + xhci->cap_regs = hcd->regs; + xhci->op_regs = hcd->regs + diff --git a/usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch b/usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch index be411d6ec60c92..ada1085f7f3862 100644 --- a/usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch +++ b/usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch @@ -21,7 +21,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -1149,6 +1149,7 @@ static void xhci_cleanup_halted_endpoint +@@ -1166,6 +1166,7 @@ static void xhci_cleanup_halted_endpoint ep->stopped_td = NULL; ep->stopped_trb = NULL; diff --git a/usb/usb-xhci-transfer-ring-link-trb-activation-change.patch b/usb/usb-xhci-transfer-ring-link-trb-activation-change.patch index d780c67e5b4663..37aaecf4cbb95e 100644 --- a/usb/usb-xhci-transfer-ring-link-trb-activation-change.patch +++ b/usb/usb-xhci-transfer-ring-link-trb-activation-change.patch @@ -65,9 +65,9 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } /* Toggle the cycle bit after the last ring segment. */ if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { -@@ -243,6 +244,13 @@ static int room_on_ring(struct xhci_hcd - union xhci_trb *enq = ring->enqueue; - struct xhci_segment *enq_seg = ring->enq_seg; +@@ -245,6 +246,13 @@ static int room_on_ring(struct xhci_hcd + struct xhci_segment *cur_seg; + unsigned int left_on_ring; + /* If we are currently pointing to a link TRB, advance the + * enqueue pointer before checking for space */ @@ -77,9 +77,9 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + } + /* Check if ring is empty */ - if (enq == ring->dequeue) - return 1; -@@ -1711,6 +1719,43 @@ static int prepare_ring(struct xhci_hcd + if (enq == ring->dequeue) { + /* Can't use link trbs */ +@@ -1728,6 +1736,43 @@ static int prepare_ring(struct xhci_hcd xhci_err(xhci, "ERROR no room on ep ring\n"); return -ENOMEM; } diff --git a/usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch b/usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch index 3b2cf069071721..6043170def5b43 100644 --- a/usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch +++ b/usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch @@ -488,7 +488,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> if (!xhci->cmd_ring) --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -306,6 +306,10 @@ static void ring_ep_doorbell(struct xhci +@@ -323,6 +323,10 @@ static void ring_ep_doorbell(struct xhci ep_state = ep->ep_state; /* Don't ring the doorbell for this endpoint if there are pending * cancellations because the we don't want to interrupt processing. @@ -499,7 +499,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> */ if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING) && !(ep_state & EP_HALTED)) { -@@ -899,8 +903,9 @@ static void handle_cmd_completion(struct +@@ -916,8 +920,9 @@ static void handle_cmd_completion(struct * Configure endpoint commands can come from the USB core * configuration or alt setting changes, or because the HW * needed an extra configure endpoint command after a reset |
