Skip to content

Commit 47f503c

Browse files
matnymangregkh
authored andcommitted
xhci: split free interrupter into separate remove and free parts
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 <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20231019102924.2797346-17-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a5d6264 commit 47f503c

File tree

1 file changed

+21
-11
lines changed

1 file changed

+21
-11
lines changed

drivers/usb/host/xhci-mem.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,22 +1807,13 @@ static int xhci_alloc_erst(struct xhci_hcd *xhci,
18071807
}
18081808

18091809
static void
1810-
xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
1810+
xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
18111811
{
1812-
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
1813-
size_t erst_size;
18141812
u32 tmp;
18151813

18161814
if (!ir)
18171815
return;
18181816

1819-
erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries;
1820-
if (ir->erst.entries)
1821-
dma_free_coherent(dev, erst_size,
1822-
ir->erst.entries,
1823-
ir->erst.erst_dma_addr);
1824-
ir->erst.entries = NULL;
1825-
18261817
/*
18271818
* Clean out interrupter registers except ERSTBA. Clearing either the
18281819
* low or high 32 bits of ERSTBA immediately causes the controller to
@@ -1835,10 +1826,28 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
18351826

18361827
xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue);
18371828
}
1829+
}
1830+
1831+
static void
1832+
xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
1833+
{
1834+
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
1835+
size_t erst_size;
1836+
1837+
if (!ir)
1838+
return;
1839+
1840+
erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries;
1841+
if (ir->erst.entries)
1842+
dma_free_coherent(dev, erst_size,
1843+
ir->erst.entries,
1844+
ir->erst.erst_dma_addr);
1845+
ir->erst.entries = NULL;
18381846

1839-
/* free interrrupter event ring */
1847+
/* free interrupter event ring */
18401848
if (ir->event_ring)
18411849
xhci_ring_free(xhci, ir->event_ring);
1850+
18421851
ir->event_ring = NULL;
18431852

18441853
kfree(ir);
@@ -1851,6 +1860,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
18511860

18521861
cancel_delayed_work_sync(&xhci->cmd_timer);
18531862

1863+
xhci_remove_interrupter(xhci, xhci->interrupter);
18541864
xhci_free_interrupter(xhci, xhci->interrupter);
18551865
xhci->interrupter = NULL;
18561866
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");

0 commit comments

Comments
 (0)