hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/usb/host/xhci-ring.c
....@@ -277,6 +277,26 @@
277277 trace_xhci_inc_enq(ring);
278278 }
279279
280
+static int xhci_num_trbs_to(struct xhci_segment *start_seg, union xhci_trb *start,
281
+ struct xhci_segment *end_seg, union xhci_trb *end,
282
+ unsigned int num_segs)
283
+{
284
+ union xhci_trb *last_on_seg;
285
+ int num = 0;
286
+ int i = 0;
287
+
288
+ do {
289
+ if (start_seg == end_seg && end >= start)
290
+ return num + (end - start);
291
+ last_on_seg = &start_seg->trbs[TRBS_PER_SEGMENT - 1];
292
+ num += last_on_seg - start;
293
+ start_seg = start_seg->next;
294
+ start = start_seg->trbs;
295
+ } while (i++ <= num_segs);
296
+
297
+ return -EINVAL;
298
+}
299
+
280300 /*
281301 * Check to see if there's room to enqueue num_trbs on the ring and make sure
282302 * enqueue pointer will not advance into dequeue segment. See rules above.
....@@ -1182,7 +1202,10 @@
11821202 struct xhci_virt_ep *ep;
11831203 struct xhci_ring *ring;
11841204
1185
- ep = &xhci->devs[slot_id]->eps[ep_index];
1205
+ ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
1206
+ if (!ep)
1207
+ return;
1208
+
11861209 if ((ep->ep_state & EP_HAS_STREAMS) ||
11871210 (ep->ep_state & EP_GETTING_NO_STREAMS)) {
11881211 int stream_id;
....@@ -2198,6 +2221,7 @@
21982221 u32 trb_comp_code)
21992222 {
22002223 struct xhci_ep_ctx *ep_ctx;
2224
+ int trbs_freed;
22012225
22022226 ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index);
22032227
....@@ -2269,9 +2293,15 @@
22692293 }
22702294
22712295 /* Update ring dequeue pointer */
2296
+ trbs_freed = xhci_num_trbs_to(ep_ring->deq_seg, ep_ring->dequeue,
2297
+ td->last_trb_seg, td->last_trb,
2298
+ ep_ring->num_segs);
2299
+ if (trbs_freed < 0)
2300
+ xhci_dbg(xhci, "Failed to count freed trbs at TD finish\n");
2301
+ else
2302
+ ep_ring->num_trbs_free += trbs_freed;
22722303 ep_ring->dequeue = td->last_trb;
22732304 ep_ring->deq_seg = td->last_trb_seg;
2274
- ep_ring->num_trbs_free += td->num_trbs - 1;
22752305 inc_deq(xhci, ep_ring);
22762306
22772307 return xhci_td_cleanup(xhci, td, ep_ring, td->status);