Paul, I think I see the bug you're trying to fix. Can you confirm my analysis is correct? This is the original code in xhci-ring.c: static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) { int num_sgs, num_trbs, running_total, temp, i; struct scatterlist *sg; sg = NULL; num_sgs = urb->num_sgs; temp = urb->transfer_buffer_length; xhci_dbg(xhci, "count sg list trbs: \n"); num_trbs = 0; for_each_sg(urb->sg, sg, num_sgs, i) { unsigned int previous_total_trbs = num_trbs; unsigned int len = sg_dma_len(sg); /* Scatter gather list entries may cross 64KB boundaries */ running_total = TRB_MAX_BUFF_SIZE - (sg_dma_address(sg) & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); if (running_total != 0) num_trbs++; /* How many more 64KB chunks to transfer, how many more TRBs? */ while (running_total < sg_dma_len(sg)) { num_trbs++; running_total += TRB_MAX_BUFF_SIZE; } ... len = min_t(int, len, temp); temp -= len; if (temp == 0) break; } ... return num_trbs; } I see that you've changed the while loop condition to this: > + while (running_total < sg_dma_len(sg) && running_total < temp) { I think that's the only bug fix in this patch; all the rest of the changes look like clean up. So the original code would fail if the driver submitted a scatter gather list where the total for all the entries was greater than urb->transfer_buffer_length, and at least one of the entries in the list was greater than 64KB. Is that correct? I think something like this scatter gather list might fail, if urb->transfer_buffer_length = 5K. ----------------------- | entry 1 | | 4K | ----------------------- ----------------------- | entry 2 | | 3K | | | | -- 64KB boundary -- | | | | 1K | ----------------------- The original code would say there needs to be 3 TRBs for this list, when there only needs to be two TRBs. Is that the bug you're trying to fix? Sarah Sharp On Thu, Jan 13, 2011 at 12:09:14PM -0800, Paul Zimmerman wrote: > xhci: Clarify some expressions in the TRB math, and fix some errors (I believe) > that this reveals. This allows the driver to work with the Synopsys xHCI controller. > I also verified that it still works with the NEC controller. > > Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx> > Cc: Greg Kroah-Hartman <gregkh@xxxxxxx> > --- > drivers/usb/host/xhci-ring.c | 27 ++++++++++++++------------- > 1 files changed, 14 insertions(+), 13 deletions(-) > > diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c > index b4be841..16632f1 100644 > --- a/drivers/usb/host/xhci-ring.c > +++ b/drivers/usb/host/xhci-ring.c > @@ -2374,12 +2374,13 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) > > /* Scatter gather list entries may cross 64KB boundaries */ > running_total = TRB_MAX_BUFF_SIZE - > - (sg_dma_address(sg) & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); > + (sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1)); > + running_total &= TRB_MAX_BUFF_SIZE - 1; > if (running_total != 0) > num_trbs++; > > /* How many more 64KB chunks to transfer, how many more TRBs? */ > - while (running_total < sg_dma_len(sg)) { > + while (running_total < sg_dma_len(sg) && running_total < temp) { > num_trbs++; > running_total += TRB_MAX_BUFF_SIZE; > } > @@ -2404,11 +2405,11 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) > static void check_trb_math(struct urb *urb, int num_trbs, int running_total) > { > if (num_trbs != 0) > - dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated number of " > + dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated number of " > "TRBs, %d left\n", __func__, > urb->ep->desc.bEndpointAddress, num_trbs); > if (running_total != urb->transfer_buffer_length) > - dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, " > + dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, " > "queued %#x (%d), asked for %#x (%d)\n", > __func__, > urb->ep->desc.bEndpointAddress, > @@ -2540,8 +2541,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > sg = urb->sg; > addr = (u64) sg_dma_address(sg); > this_sg_len = sg_dma_len(sg); > - trb_buff_len = TRB_MAX_BUFF_SIZE - > - (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); > + trb_buff_len = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1)); > trb_buff_len = min_t(int, trb_buff_len, this_sg_len); > if (trb_buff_len > urb->transfer_buffer_length) > trb_buff_len = urb->transfer_buffer_length; > @@ -2577,7 +2577,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), > (unsigned int) addr + trb_buff_len); > if (TRB_MAX_BUFF_SIZE - > - (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)) < trb_buff_len) { > + (addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) { > xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n"); > xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n", > (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), > @@ -2621,7 +2621,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > } > > trb_buff_len = TRB_MAX_BUFF_SIZE - > - (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); > + (addr & (TRB_MAX_BUFF_SIZE - 1)); > trb_buff_len = min_t(int, trb_buff_len, this_sg_len); > if (running_total + trb_buff_len > urb->transfer_buffer_length) > trb_buff_len = > @@ -2661,7 +2661,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > num_trbs = 0; > /* How much data is (potentially) left before the 64KB boundary? */ > running_total = TRB_MAX_BUFF_SIZE - > - (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); > + (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1)); > + running_total &= TRB_MAX_BUFF_SIZE - 1; > > /* If there's some data on this 64KB chunk, or we have to send a > * zero-length transfer, we need at least one TRB > @@ -2704,8 +2705,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > /* How much data is in the first TRB? */ > addr = (u64) urb->transfer_dma; > trb_buff_len = TRB_MAX_BUFF_SIZE - > - (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); > - if (urb->transfer_buffer_length < trb_buff_len) > + (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1)); > + if (trb_buff_len > urb->transfer_buffer_length) > trb_buff_len = urb->transfer_buffer_length; > > first_trb = true; > @@ -2877,8 +2878,8 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci, > addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset); > td_len = urb->iso_frame_desc[i].length; > > - running_total = TRB_MAX_BUFF_SIZE - > - (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); > + running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1)); > + running_total &= TRB_MAX_BUFF_SIZE - 1; > if (running_total != 0) > num_trbs++; > > -- > 1.6.5.1.69.g36942 > > > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html