aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2009-12-07 08:50:39 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 14:55:26 -0500
commit0d370755dd4ad3d119818579cfa3eb2e9978b3eb (patch)
treef8b7fa0640f156f4780f3c37a24e7af1f08729c2 /drivers/usb
parentf3f6faa9edf67c1018270793e0547b0f81abb47e (diff)
USB: whci-hcd: correctly handle sg lists longer than QTD_MAX_XFER_SIZE.
When building qTDs (sTDs) from a scatter-gather list, the length of the qTD must be a multiple of wMaxPacketSize if the transfer continues into another qTD. This also fixes a link failure on configurations for 32 bit processors with 64 bit dma_addr_t (e.g., CONFIG_HIGHMEM_64G). Signed-off-by: David Vrabel <david.vrabel@csr.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/whci/qset.c22
1 files changed, 11 insertions, 11 deletions
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index 39e855a55c63..7d4204db0f61 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -465,16 +465,16 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
465 * - the previous one isn't full. 465 * - the previous one isn't full.
466 * 466 *
467 * If a new std is needed but the previous one 467 * If a new std is needed but the previous one
468 * did not end on a wMaxPacketSize boundary 468 * was not a whole number of packets then this
469 * then this sg list cannot be mapped onto 469 * sg list cannot be mapped onto multiple
470 * multiple qTDs. Return an error and let the 470 * qTDs. Return an error and let the caller
471 * caller sort it out. 471 * sort it out.
472 */ 472 */
473 if (!std 473 if (!std
474 || (prev_end & (WHCI_PAGE_SIZE-1)) 474 || (prev_end & (WHCI_PAGE_SIZE-1))
475 || (dma_addr & (WHCI_PAGE_SIZE-1)) 475 || (dma_addr & (WHCI_PAGE_SIZE-1))
476 || std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) { 476 || std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) {
477 if (prev_end % qset->max_packet != 0) 477 if (std->len % qset->max_packet != 0)
478 return -EINVAL; 478 return -EINVAL;
479 std = qset_new_std(whc, qset, urb, mem_flags); 479 std = qset_new_std(whc, qset, urb, mem_flags);
480 if (std == NULL) { 480 if (std == NULL) {
@@ -487,14 +487,14 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
487 dma_len = dma_remaining; 487 dma_len = dma_remaining;
488 488
489 /* 489 /*
490 * If the remainder in this element doesn't 490 * If the remainder of this element doesn't
491 * fit in a single qTD, end the qTD on a 491 * fit in a single qTD, limit the qTD to a
492 * wMaxPacketSize boundary. 492 * whole number of packets. This allows the
493 * remainder to go into the next qTD.
493 */ 494 */
494 if (std->len + dma_len > QTD_MAX_XFER_SIZE) { 495 if (std->len + dma_len > QTD_MAX_XFER_SIZE) {
495 dma_len = QTD_MAX_XFER_SIZE - std->len; 496 dma_len = (QTD_MAX_XFER_SIZE / qset->max_packet)
496 ep = ((dma_addr + dma_len) / qset->max_packet) * qset->max_packet; 497 * qset->max_packet - std->len;
497 dma_len = ep - dma_addr;
498 } 498 }
499 499
500 std->len += dma_len; 500 std->len += dma_len;