Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: OHCI: add SG support

Apparently nobody ever remembered to add Scatter-Gather support to
ohci-hcd. This patch adds it.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
6f65126c 1299cff9

+73 -19
+32 -6
drivers/usb/host/ohci-hcd.c
··· 109 109 110 110 /*-------------------------------------------------------------------------*/ 111 111 112 + static int number_of_tds(struct urb *urb) 113 + { 114 + int len, i, num, this_sg_len; 115 + struct scatterlist *sg; 116 + 117 + len = urb->transfer_buffer_length; 118 + i = urb->num_mapped_sgs; 119 + 120 + if (len > 0 && i > 0) { /* Scatter-gather transfer */ 121 + num = 0; 122 + sg = urb->sg; 123 + for (;;) { 124 + this_sg_len = min_t(int, sg_dma_len(sg), len); 125 + num += DIV_ROUND_UP(this_sg_len, 4096); 126 + len -= this_sg_len; 127 + if (--i <= 0 || len <= 0) 128 + break; 129 + sg = sg_next(sg); 130 + } 131 + 132 + } else { /* Non-SG transfer */ 133 + /* one TD for every 4096 Bytes (could be up to 8K) */ 134 + num = DIV_ROUND_UP(len, 4096); 135 + } 136 + return num; 137 + } 138 + 112 139 /* 113 140 * queue up an urb for anything except the root hub 114 141 */ ··· 169 142 // case PIPE_INTERRUPT: 170 143 // case PIPE_BULK: 171 144 default: 172 - /* one TD for every 4096 Bytes (can be up to 8K) */ 173 - size += urb->transfer_buffer_length / 4096; 174 - /* ... and for any remaining bytes ... */ 175 - if ((urb->transfer_buffer_length % 4096) != 0) 176 - size++; 177 - /* ... and maybe a zero length packet to wrap it up */ 145 + size += number_of_tds(urb); 146 + /* maybe a zero-length packet to wrap it up */ 178 147 if (size == 0) 179 148 size++; 180 149 else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 ··· 528 505 { 529 506 int ret; 530 507 struct usb_hcd *hcd = ohci_to_hcd(ohci); 508 + 509 + /* Accept arbitrarily long scatter-gather lists */ 510 + hcd->self.sg_tablesize = ~0; 531 511 532 512 if (distrust_firmware) 533 513 ohci->flags |= OHCI_QUIRK_HUB_POWER;
+41 -13
drivers/usb/host/ohci-q.c
··· 602 602 u32 info = 0; 603 603 int is_out = usb_pipeout (urb->pipe); 604 604 int periodic = 0; 605 + int i, this_sg_len, n; 606 + struct scatterlist *sg; 605 607 606 608 /* OHCI handles the bulk/interrupt data toggles itself. We just 607 609 * use the device toggle bits for resetting, and rely on the fact ··· 617 615 618 616 list_add (&urb_priv->pending, &ohci->pending); 619 617 620 - if (data_len) 621 - data = urb->transfer_dma; 622 - else 623 - data = 0; 618 + i = urb->num_mapped_sgs; 619 + if (data_len > 0 && i > 0) { 620 + sg = urb->sg; 621 + data = sg_dma_address(sg); 622 + 623 + /* 624 + * urb->transfer_buffer_length may be smaller than the 625 + * size of the scatterlist (or vice versa) 626 + */ 627 + this_sg_len = min_t(int, sg_dma_len(sg), data_len); 628 + } else { 629 + sg = NULL; 630 + if (data_len) 631 + data = urb->transfer_dma; 632 + else 633 + data = 0; 634 + this_sg_len = data_len; 635 + } 624 636 625 637 /* NOTE: TD_CC is set so we can tell which TDs the HC processed by 626 638 * using TD_CC_GET, as well as by seeing them on the done list. ··· 655 639 ? TD_T_TOGGLE | TD_CC | TD_DP_OUT 656 640 : TD_T_TOGGLE | TD_CC | TD_DP_IN; 657 641 /* TDs _could_ transfer up to 8K each */ 658 - while (data_len > 4096) { 659 - td_fill (ohci, info, data, 4096, urb, cnt); 660 - data += 4096; 661 - data_len -= 4096; 642 + for (;;) { 643 + n = min(this_sg_len, 4096); 644 + 645 + /* maybe avoid ED halt on final TD short read */ 646 + if (n >= data_len || (i == 1 && n >= this_sg_len)) { 647 + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) 648 + info |= TD_R; 649 + } 650 + td_fill(ohci, info, data, n, urb, cnt); 651 + this_sg_len -= n; 652 + data_len -= n; 653 + data += n; 662 654 cnt++; 655 + 656 + if (this_sg_len <= 0) { 657 + if (--i <= 0 || data_len <= 0) 658 + break; 659 + sg = sg_next(sg); 660 + data = sg_dma_address(sg); 661 + this_sg_len = min_t(int, sg_dma_len(sg), 662 + data_len); 663 + } 663 664 } 664 - /* maybe avoid ED halt on final TD short read */ 665 - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) 666 - info |= TD_R; 667 - td_fill (ohci, info, data, data_len, urb, cnt); 668 - cnt++; 669 665 if ((urb->transfer_flags & URB_ZERO_PACKET) 670 666 && cnt < urb_priv->length) { 671 667 td_fill (ohci, info, 0, 0, urb, cnt);