diff options
| author | Arjan Mels <arjan.mels@gmx.net> | 2011-04-05 14:26:59 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-04-06 18:51:14 -0400 |
| commit | 28276a28d8b3cd19f4449991faad4945fe557656 (patch) | |
| tree | e3c5c6ceb249faf8a90e03519a198836235746a5 | |
| parent | 1325f85fa49f57df034869de430f7c302ae23109 (diff) | |
staging: usbip: bugfix for isochronous packets and optimization
For isochronous packets the actual_length is the sum of the actual
length of each of the packets, however between the packets might be
padding, so it is not sufficient to just send the first actual_length
bytes of the buffer. To fix this and simultanesouly optimize the
bandwidth the content of the isochronous packets are send without the
padding, the padding is restored on the receiving end.
Signed-off-by: Arjan Mels <arjan.mels@gmx.net>
Cc: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
Cc: Max Vozeler <max@vozeler.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/staging/usbip/stub_tx.c | 74 | ||||
| -rw-r--r-- | drivers/staging/usbip/usbip_common.c | 57 | ||||
| -rw-r--r-- | drivers/staging/usbip/usbip_common.h | 2 | ||||
| -rw-r--r-- | drivers/staging/usbip/vhci_rx.c | 3 |
4 files changed, 122 insertions, 14 deletions
diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c index 5523f25998e6..64a52b26dcf6 100644 --- a/drivers/staging/usbip/stub_tx.c +++ b/drivers/staging/usbip/stub_tx.c | |||
| @@ -170,7 +170,6 @@ static int stub_send_ret_submit(struct stub_device *sdev) | |||
| 170 | struct stub_priv *priv, *tmp; | 170 | struct stub_priv *priv, *tmp; |
| 171 | 171 | ||
| 172 | struct msghdr msg; | 172 | struct msghdr msg; |
| 173 | struct kvec iov[3]; | ||
| 174 | size_t txsize; | 173 | size_t txsize; |
| 175 | 174 | ||
| 176 | size_t total_size = 0; | 175 | size_t total_size = 0; |
| @@ -180,28 +179,73 @@ static int stub_send_ret_submit(struct stub_device *sdev) | |||
| 180 | struct urb *urb = priv->urb; | 179 | struct urb *urb = priv->urb; |
| 181 | struct usbip_header pdu_header; | 180 | struct usbip_header pdu_header; |
| 182 | void *iso_buffer = NULL; | 181 | void *iso_buffer = NULL; |
| 182 | struct kvec *iov = NULL; | ||
| 183 | int iovnum = 0; | ||
| 183 | 184 | ||
| 184 | txsize = 0; | 185 | txsize = 0; |
| 185 | memset(&pdu_header, 0, sizeof(pdu_header)); | 186 | memset(&pdu_header, 0, sizeof(pdu_header)); |
| 186 | memset(&msg, 0, sizeof(msg)); | 187 | memset(&msg, 0, sizeof(msg)); |
| 187 | memset(&iov, 0, sizeof(iov)); | ||
| 188 | 188 | ||
| 189 | usbip_dbg_stub_tx("setup txdata urb %p\n", urb); | 189 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) |
| 190 | iovnum = 2 + urb->number_of_packets; | ||
| 191 | else | ||
| 192 | iovnum = 2; | ||
| 193 | |||
| 194 | iov = kzalloc(iovnum * sizeof(struct kvec), GFP_KERNEL); | ||
| 190 | 195 | ||
| 196 | if (!iov) { | ||
| 197 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC); | ||
| 198 | return -1; | ||
| 199 | } | ||
| 200 | |||
| 201 | iovnum = 0; | ||
| 191 | 202 | ||
| 192 | /* 1. setup usbip_header */ | 203 | /* 1. setup usbip_header */ |
| 193 | setup_ret_submit_pdu(&pdu_header, urb); | 204 | setup_ret_submit_pdu(&pdu_header, urb); |
| 205 | usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n", | ||
| 206 | pdu_header.base.seqnum, urb); | ||
| 207 | /*usbip_dump_header(pdu_header);*/ | ||
| 194 | usbip_header_correct_endian(&pdu_header, 1); | 208 | usbip_header_correct_endian(&pdu_header, 1); |
| 195 | 209 | ||
| 196 | iov[0].iov_base = &pdu_header; | 210 | iov[iovnum].iov_base = &pdu_header; |
| 197 | iov[0].iov_len = sizeof(pdu_header); | 211 | iov[iovnum].iov_len = sizeof(pdu_header); |
| 212 | iovnum++; | ||
| 198 | txsize += sizeof(pdu_header); | 213 | txsize += sizeof(pdu_header); |
| 199 | 214 | ||
| 200 | /* 2. setup transfer buffer */ | 215 | /* 2. setup transfer buffer */ |
| 201 | if (usb_pipein(urb->pipe) && urb->actual_length > 0) { | 216 | if (usb_pipein(urb->pipe) && |
| 202 | iov[1].iov_base = urb->transfer_buffer; | 217 | usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS && |
| 203 | iov[1].iov_len = urb->actual_length; | 218 | urb->actual_length > 0) { |
| 219 | iov[iovnum].iov_base = urb->transfer_buffer; | ||
| 220 | iov[iovnum].iov_len = urb->actual_length; | ||
| 221 | iovnum++; | ||
| 204 | txsize += urb->actual_length; | 222 | txsize += urb->actual_length; |
| 223 | } else if (usb_pipein(urb->pipe) && | ||
| 224 | usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { | ||
| 225 | /* | ||
| 226 | * For isochronous packets: actual length is the sum of | ||
| 227 | * the actual length of the individual, packets, but as | ||
| 228 | * the packet offsets are not changed there will be | ||
| 229 | * padding between the packets. To optimally use the | ||
| 230 | * bandwidth the padding is not transmitted. | ||
| 231 | */ | ||
| 232 | |||
| 233 | int i; | ||
| 234 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 235 | iov[iovnum].iov_base = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
| 236 | iov[iovnum].iov_len = urb->iso_frame_desc[i].actual_length; | ||
| 237 | iovnum++; | ||
| 238 | txsize += urb->iso_frame_desc[i].actual_length; | ||
| 239 | } | ||
| 240 | |||
| 241 | if (txsize != sizeof(pdu_header) + urb->actual_length) { | ||
| 242 | dev_err(&sdev->interface->dev, | ||
| 243 | "actual length of urb (%d) does not match iso packet sizes (%d)\n", | ||
| 244 | urb->actual_length, txsize-sizeof(pdu_header)); | ||
| 245 | kfree(iov); | ||
| 246 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); | ||
| 247 | return -1; | ||
| 248 | } | ||
| 205 | } | 249 | } |
| 206 | 250 | ||
| 207 | /* 3. setup iso_packet_descriptor */ | 251 | /* 3. setup iso_packet_descriptor */ |
| @@ -212,32 +256,34 @@ static int stub_send_ret_submit(struct stub_device *sdev) | |||
| 212 | if (!iso_buffer) { | 256 | if (!iso_buffer) { |
| 213 | usbip_event_add(&sdev->ud, | 257 | usbip_event_add(&sdev->ud, |
| 214 | SDEV_EVENT_ERROR_MALLOC); | 258 | SDEV_EVENT_ERROR_MALLOC); |
| 259 | kfree(iov); | ||
| 215 | return -1; | 260 | return -1; |
| 216 | } | 261 | } |
| 217 | 262 | ||
| 218 | iov[2].iov_base = iso_buffer; | 263 | iov[iovnum].iov_base = iso_buffer; |
| 219 | iov[2].iov_len = len; | 264 | iov[iovnum].iov_len = len; |
| 220 | txsize += len; | 265 | txsize += len; |
| 266 | iovnum++; | ||
| 221 | } | 267 | } |
| 222 | 268 | ||
| 223 | ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, | 269 | ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, |
| 224 | 3, txsize); | 270 | iov, iovnum, txsize); |
| 225 | if (ret != txsize) { | 271 | if (ret != txsize) { |
| 226 | dev_err(&sdev->interface->dev, | 272 | dev_err(&sdev->interface->dev, |
| 227 | "sendmsg failed!, retval %d for %zd\n", | 273 | "sendmsg failed!, retval %d for %zd\n", |
| 228 | ret, txsize); | 274 | ret, txsize); |
| 275 | kfree(iov); | ||
| 229 | kfree(iso_buffer); | 276 | kfree(iso_buffer); |
| 230 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); | 277 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); |
| 231 | return -1; | 278 | return -1; |
| 232 | } | 279 | } |
| 233 | 280 | ||
| 281 | kfree(iov); | ||
| 234 | kfree(iso_buffer); | 282 | kfree(iso_buffer); |
| 235 | usbip_dbg_stub_tx("send txdata\n"); | ||
| 236 | 283 | ||
| 237 | total_size += txsize; | 284 | total_size += txsize; |
| 238 | } | 285 | } |
| 239 | 286 | ||
| 240 | |||
| 241 | spin_lock_irqsave(&sdev->priv_lock, flags); | 287 | spin_lock_irqsave(&sdev->priv_lock, flags); |
| 242 | 288 | ||
| 243 | list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) { | 289 | list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) { |
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 85622153ea7c..7b1fe45bf7dd 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c | |||
| @@ -730,6 +730,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) | |||
| 730 | int size = np * sizeof(*iso); | 730 | int size = np * sizeof(*iso); |
| 731 | int i; | 731 | int i; |
| 732 | int ret; | 732 | int ret; |
| 733 | int total_length = 0; | ||
| 733 | 734 | ||
| 734 | if (!usb_pipeisoc(urb->pipe)) | 735 | if (!usb_pipeisoc(urb->pipe)) |
| 735 | return 0; | 736 | return 0; |
| @@ -759,19 +760,75 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) | |||
| 759 | return -EPIPE; | 760 | return -EPIPE; |
| 760 | } | 761 | } |
| 761 | 762 | ||
| 763 | |||
| 762 | for (i = 0; i < np; i++) { | 764 | for (i = 0; i < np; i++) { |
| 763 | iso = buff + (i * sizeof(*iso)); | 765 | iso = buff + (i * sizeof(*iso)); |
| 764 | 766 | ||
| 765 | usbip_iso_pakcet_correct_endian(iso, 0); | 767 | usbip_iso_pakcet_correct_endian(iso, 0); |
