diff options
| author | Mathias Nyman <mathias.nyman@linux.intel.com> | 2023-10-19 13:29:21 +0300 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-05-09 09:44:06 +0200 |
| commit | ff0a51339a3b74c8e23b6bc32c58b41340345b43 (patch) | |
| tree | c901cefe1536561b707216d5cc40873bbd230dfd /drivers | |
| parent | 3f6e8ad65b1eeaeb26e36844e45a3b9ac2124a1d (diff) | |
| download | linux-ff0a51339a3b74c8e23b6bc32c58b41340345b43.tar.gz linux-ff0a51339a3b74c8e23b6bc32c58b41340345b43.tar.bz2 linux-ff0a51339a3b74c8e23b6bc32c58b41340345b43.zip | |
xhci: split free interrupter into separate remove and free parts
[ Upstream commit 47f503cf5f799ec02e5f4b7c3b9afe145eca2aef ]
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>
Stable-dep-of: bea5892d0ed2 ("xhci: Limit time spent with xHC interrupts disabled during bus resume")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/usb/host/xhci-mem.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 45240299fa17..f00e96c9ca57 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1803,22 +1803,13 @@ 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; 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 @@ -1831,10 +1822,28 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) xhci_write_64(xhci, ERST_EHB, &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); @@ -1847,6 +1856,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"); |
