@@ -300,42 +300,36 @@ static struct xhci_segment *dma_in_range(struct xhci_segment *start_seg, union x
dma_addr_t dma)
{
struct xhci_segment *seg = start_seg;
+ union xhci_trb *trb;
- if (start_seg == end_seg) {
- if (start_trb <= end_trb) {
- if (xhci_trb_virt_to_dma(start_seg, start_trb) <= dma &&
- dma <= xhci_trb_virt_to_dma(end_seg, end_trb))
- return seg;
- return NULL;
+ /* check if dma is a TRB in start_seg */
+ if (in_range(dma, seg->dma, TRB_SEGMENT_SIZE)) {
+ trb = seg->trbs + (dma - seg->dma) / sizeof(*trb);
+
+ if (trb >= start_trb)
+ /* check if the range covers it and we are done */
+ return (end_seg != seg || trb <= end_trb) ? seg : NULL;
+
+ /* check if the range circles back to the beginning of start_seg */
+ return (end_seg == seg && end_trb < start_trb && trb <= end_trb) ? seg : NULL;
+ }
+
+ /* stop if the range doesn't pass through any other segment */
+ if (end_seg == seg && (end_trb >= start_trb || seg->next == seg))
+ return NULL;
+
+ /* search remaining segments knowing that start_trb isn't there */
+ do {
+ seg = seg->next;
+
+ if (in_range(dma, seg->dma, TRB_SEGMENT_SIZE)) {
+ trb = seg->trbs + (dma - seg->dma) / sizeof(*trb);
+
+ return (seg != end_seg || trb <= end_trb) ? seg : NULL;
}
+ } while (seg != end_seg && seg != start_seg);
- /* Edge case, the TD wrapped around to the start segment. */
- if (xhci_trb_virt_to_dma(end_seg, end_trb) < dma &&
- dma < xhci_trb_virt_to_dma(start_seg, start_trb))
- return NULL;
- if (seg->dma <= dma && dma <= (seg->dma + TRB_SEGMENT_SIZE))
- return seg;
- seg = seg->next;
- }
-
- /* Loop through segment which don't contain the DMA address. */
- while (dma < seg->dma || (seg->dma + TRB_SEGMENT_SIZE) <= dma) {
- if (seg == end_seg)
- return NULL;
-
- seg = seg->next;
- if (seg == start_seg)
- return NULL;
- }
-
- if (seg == start_seg) {
- if (dma < xhci_trb_virt_to_dma(start_seg, start_trb))
- return NULL;
- } else if (seg == end_seg) {
- if (xhci_trb_virt_to_dma(end_seg, end_trb) < dma)
- return NULL;
- }
- return seg;
+ return NULL;
}
static struct xhci_segment *trb_in_td(struct xhci_td *td, dma_addr_t dma)