Thread (74 messages) 74 messages, 3 authors, 2023-10-25
STALE977d
Revisions (40)
  1. rfc [diff vs current]
  2. v2 [diff vs current]
  3. v3 [diff vs current]
  4. v4 [diff vs current]
  5. v5 [diff vs current]
  6. v6 [diff vs current]
  7. v7 [diff vs current]
  8. v8 [diff vs current]
  9. v9 current
  10. v10 [diff vs current]
  11. v11 [diff vs current]
  12. v12 [diff vs current]
  13. v13 [diff vs current]
  14. v14 [diff vs current]
  15. v15 [diff vs current]
  16. v16 [diff vs current]
  17. v17 [diff vs current]
  18. v18 [diff vs current]
  19. v19 [diff vs current]
  20. v20 [diff vs current]
  21. v21 [diff vs current]
  22. v22 [diff vs current]
  23. v23 [diff vs current]
  24. v24 [diff vs current]
  25. v25 [diff vs current]
  26. v26 [diff vs current]
  27. v27 [diff vs current]
  28. v28 [diff vs current]
  29. v28 [diff vs current]
  30. v28 [diff vs current]
  31. v29 [diff vs current]
  32. v30 [diff vs current]
  33. v31 [diff vs current]
  34. v32 [diff vs current]
  35. v33 [diff vs current]
  36. v34 [diff vs current]
  37. v35 [diff vs current]
  38. v36 [diff vs current]
  39. v37 [diff vs current]
  40. v38 [diff vs current]

[PATCH v9 01/34] xhci: split free interrupter into separate remove and free parts

From: Wesley Cheng <hidden>
Date: 2023-10-17 20:02:16
Also in: alsa-devel, linux-arm-msm, linux-devicetree, lkml
Subsystem: the rest, usb subsystem, usb xhci driver · Maintainers: Linus Torvalds, Greg Kroah-Hartman, Mathias Nyman

From: Mathias Nyman <redacted>

The current function that both removes and frees an interrupter isn't
optimal when using several interrupters. The array of interrupters need
to be protected with a lock while removing interrupters, but the default
xhci spin lock can't be used while freeing the interrupters event ring
segment table as dma_free_coherent() should be called with IRQs enabled.

There is no need to free the interrupter under the lock, so split this
code into separate unlocked free part, and a lock protected remove part.

Signed-off-by: Mathias Nyman <redacted>
Signed-off-by: Wesley Cheng <redacted>
---
 drivers/usb/host/xhci-mem.c | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 0a37f0d511cf..0994ca9fba44 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1797,23 +1797,14 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
 }
 
 static void
-xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
 {
-	struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
-	size_t erst_size;
 	u64 tmp64;
 	u32 tmp;
 
 	if (!ir)
 		return;
 
-	erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries;
-	if (ir->erst.entries)
-		dma_free_coherent(dev, erst_size,
-				  ir->erst.entries,
-				  ir->erst.erst_dma_addr);
-	ir->erst.entries = NULL;
-
 	/*
 	 * Clean out interrupter registers except ERSTBA. Clearing either the
 	 * low or high 32 bits of ERSTBA immediately causes the controller to
@@ -1828,10 +1819,28 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
 		tmp64 &= (u64) ERST_PTR_MASK;
 		xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
 	}
+}
+
+static void
+xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+{
+	struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+	size_t erst_size;
+
+	if (!ir)
+		return;
+
+	erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries;
+	if (ir->erst.entries)
+		dma_free_coherent(dev, erst_size,
+				  ir->erst.entries,
+				  ir->erst.erst_dma_addr);
+	ir->erst.entries = NULL;
 
-	/* free interrrupter event ring */
+	/* free interrupter event ring */
 	if (ir->event_ring)
 		xhci_ring_free(xhci, ir->event_ring);
+
 	ir->event_ring = NULL;
 
 	kfree(ir);
@@ -1844,6 +1853,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 
 	cancel_delayed_work_sync(&xhci->cmd_timer);
 
+	xhci_remove_interrupter(xhci, xhci->interrupter);
 	xhci_free_interrupter(xhci, xhci->interrupter);
 	xhci->interrupter = NULL;
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help