[PATCH for 4.14] xhci: add xhci_get_virt_ep() helper

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From 804d2db49c8db94ff4652f13826a2c74dac33941 Mon Sep 17 00:00:00 2001
From: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>
Date: Fri, 29 Jan 2021 15:00:22 +0200
Subject: [PATCH] xhci: add xhci_get_virt_ep() helper

[commit b1adc42d440df3233255e313a45ab7e9b2b74096 upstream]

In several event handlers we need to find the right endpoint
structure from slot_id and ep_index in the event.

Add a helper for this, check that slot_id and ep_index are valid.

Signed-off-by: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>
Link: https://lore.kernel.org/r/20210129130044.206855-6-mathias.nyman@xxxxxxxxxxxxxxx
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Carsten Schmid <carsten_schmid@xxxxxxxxxx>
---
Rationale:
>From mail thread " Possible race in 4.14 xhci stack"
Searched for fix that Mathias Nyman mentioned.
Fix didn't apply on 4.14 directly, needed some small adaption.
Result provided here.
@Greg: Patch is for 4.14, not tested if applies on other kernels.
---
 drivers/usb/host/xhci-ring.c | 58 ++++++++++++++++++++++++++++--------
 drivers/usb/host/xhci.h      |  3 +-
 2 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 9828c1eff9a5..ce5deac93418 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -444,6 +444,26 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
 }
 }

+static struct xhci_virt_ep *xhci_get_virt_ep(struct xhci_hcd *xhci,
+     unsigned int slot_id,
+     unsigned int ep_index)
+{
+if (slot_id == 0 || slot_id >= MAX_HC_SLOTS) {
+xhci_warn(xhci, "Invalid slot_id %u\n", slot_id);
+return NULL;
+}
+if (ep_index >= EP_CTX_PER_DEV) {
+xhci_warn(xhci, "Invalid endpoint index %u\n", ep_index);
+return NULL;
+}
+if (!xhci->devs[slot_id]) {
+xhci_warn(xhci, "No xhci virt device for slot_id %u\n", slot_id);
+return NULL;
+}
+
+return &xhci->devs[slot_id]->eps[ep_index];
+}
+
 /* Get the right ring for the given slot_id, ep_index and stream_id.
  * If the endpoint supports streams, boundary check the URB's stream ID.
  * If the endpoint doesn't support streams, return the singular endpoint ring.
@@ -454,7 +474,10 @@ struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
 {
 struct xhci_virt_ep *ep;

-ep = &xhci->devs[slot_id]->eps[ep_index];
+ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
+if (!ep)
+return NULL;
+
 /* Common case: no streams */
 if (!(ep->ep_state & EP_HAS_STREAMS))
 return ep->ring;
@@ -724,11 +747,14 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
 memset(&deq_state, 0, sizeof(deq_state));
 ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));

+ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
+if (!ep)
+return;
+
 vdev = xhci->devs[slot_id];
 ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
 trace_xhci_handle_cmd_stop_ep(ep_ctx);

-ep = &xhci->devs[slot_id]->eps[ep_index];
 last_unlinked_td = list_last_entry(&ep->cancelled_td_list,
 struct xhci_td, cancelled_td_list);

@@ -1052,9 +1078,11 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,

 ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));
 stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2]));
-dev = xhci->devs[slot_id];
-ep = &dev->eps[ep_index];
+ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
+if (!ep)
+return;

+dev = xhci->devs[slot_id];
 ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id);
 if (!ep_ring) {
 xhci_warn(xhci, "WARN Set TR deq ptr command for freed stream ID %u\n",
@@ -1127,9 +1155,9 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
 }

 cleanup:
-dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING;
-dev->eps[ep_index].queued_deq_seg = NULL;
-dev->eps[ep_index].queued_deq_ptr = NULL;
+ep->ep_state &= ~SET_DEQ_PENDING;
+ep->queued_deq_seg = NULL;
+ep->queued_deq_ptr = NULL;
 /* Restart any rings with pending URBs */
 ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
 }
@@ -1138,10 +1166,15 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
 union xhci_trb *trb, u32 cmd_comp_code)
 {
 struct xhci_virt_device *vdev;
+struct xhci_virt_ep *ep;
 struct xhci_ep_ctx *ep_ctx;
 unsigned int ep_index;

 ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));
+ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
+if (!ep)
+return;
+
 vdev = xhci->devs[slot_id];
 ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
 trace_xhci_handle_cmd_reset_ep(ep_ctx);
@@ -1171,7 +1204,7 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
 xhci_ring_cmd_db(xhci);
 } else {
 /* Clear our internal halted state */
-xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED;
+ep->ep_state &= ~EP_HALTED;
 }
 }

@@ -2347,14 +2380,13 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
 ep_trb_dma = le64_to_cpu(event->buffer);

-xdev = xhci->devs[slot_id];
-if (!xdev) {
-xhci_err(xhci, "ERROR Transfer event pointed to bad slot %u\n",
- slot_id);
+ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
+if (!ep) {
+xhci_err(xhci, "ERROR Invalid Transfer event\n");
 goto err_out;
 }

-ep = &xdev->eps[ep_index];
+xdev = xhci->devs[slot_id];
 ep_ring = xhci_dma_to_transfer_ring(ep, ep_trb_dma);
 ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);

diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 723cb31f592b..2b818dd12a8d 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -991,6 +991,7 @@ struct xhci_interval_bw_table {
 unsigned intss_bw_out;
 };

+#define EP_CTX_PER_DEV31

 struct xhci_virt_device {
 struct usb_device*udev;
@@ -1005,7 +1006,7 @@ struct xhci_virt_device {
 struct xhci_container_ctx       *out_ctx;
 /* Used for addressing devices and configuration changes */
 struct xhci_container_ctx       *in_ctx;
-struct xhci_virt_epeps[31];
+struct xhci_virt_epeps[EP_CTX_PER_DEV];
 u8fake_port;
 u8real_port;
 struct xhci_interval_bw_table*bw_table;
--
2.17.1
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux