Skip to content

Commit 4bf398e

Browse files
matnymangregkh
authored andcommitted
xhci: split allocate interrupter into separate alloacte and add parts
The current function that both allocates and adds the interrupter isn't optimal when using several interrupters. The array of interrupters need to be protected with a lock while adding or removing interrupters. If memory is allocated under the default xhci spinlock then GFP_KERNEL can't be used. There is no need to allocate the interrupter memory under the lock, so split this code into separate unlocked allocate part, and a lock protected add part. Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Message-ID: <20230602144009.1225632-6-mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0a47762 commit 4bf398e

File tree

1 file changed

+41
-37
lines changed

1 file changed

+41
-37
lines changed

drivers/usb/host/xhci-mem.c

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,13 +1831,15 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
18311831
* low or high 32 bits of ERSTBA immediately causes the controller to
18321832
* dereference the partially cleared 64 bit address, causing IOMMU error.
18331833
*/
1834-
tmp = readl(&ir->ir_set->erst_size);
1835-
tmp &= ERST_SIZE_MASK;
1836-
writel(tmp, &ir->ir_set->erst_size);
1837-
1838-
tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
1839-
tmp64 &= (u64) ERST_PTR_MASK;
1840-
xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
1834+
if (ir->ir_set) {
1835+
tmp = readl(&ir->ir_set->erst_size);
1836+
tmp &= ERST_SIZE_MASK;
1837+
writel(tmp, &ir->ir_set->erst_size);
1838+
1839+
tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
1840+
tmp64 &= (u64) ERST_PTR_MASK;
1841+
xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
1842+
}
18411843

18421844
/* free interrrupter event ring */
18431845
if (ir->event_ring)
@@ -2227,43 +2229,50 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
22272229
}
22282230

22292231
static struct xhci_interrupter *
2230-
xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags)
2232+
xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags)
22312233
{
22322234
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
22332235
struct xhci_interrupter *ir;
2234-
u64 erst_base;
2235-
u32 erst_size;
22362236
int ret;
22372237

2238-
if (intr_num > xhci->max_interrupters) {
2239-
xhci_warn(xhci, "Can't allocate interrupter %d, max interrupters %d\n",
2240-
intr_num, xhci->max_interrupters);
2241-
return NULL;
2242-
}
2243-
2244-
if (xhci->interrupter) {
2245-
xhci_warn(xhci, "Can't allocate already set up interrupter %d\n", intr_num);
2246-
return NULL;
2247-
}
2248-
22492238
ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
22502239
if (!ir)
22512240
return NULL;
22522241

2253-
ir->ir_set = &xhci->run_regs->ir_set[intr_num];
22542242
ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
22552243
0, flags);
22562244
if (!ir->event_ring) {
2257-
xhci_warn(xhci, "Failed to allocate interrupter %d event ring\n", intr_num);
2258-
goto fail_ir;
2245+
xhci_warn(xhci, "Failed to allocate interrupter event ring\n");
2246+
kfree(ir);
2247+
return NULL;
22592248
}
22602249

22612250
ret = xhci_alloc_erst(xhci, ir->event_ring, &ir->erst, flags);
22622251
if (ret) {
2263-
xhci_warn(xhci, "Failed to allocate interrupter %d erst\n", intr_num);
2264-
goto fail_ev;
2252+
xhci_warn(xhci, "Failed to allocate interrupter erst\n");
2253+
xhci_ring_free(xhci, ir->event_ring);
2254+
kfree(ir);
2255+
return NULL;
2256+
}
2257+
2258+
return ir;
2259+
}
2260+
2261+
static int
2262+
xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
2263+
unsigned int intr_num)
2264+
{
2265+
u64 erst_base;
2266+
u32 erst_size;
22652267

2268+
if (intr_num > xhci->max_interrupters) {
2269+
xhci_warn(xhci, "Can't add interrupter %d, max interrupters %d\n",
2270+
intr_num, xhci->max_interrupters);
2271+
return -EINVAL;
22662272
}
2273+
2274+
ir->ir_set = &xhci->run_regs->ir_set[intr_num];
2275+
22672276
/* set ERST count with the number of entries in the segment table */
22682277
erst_size = readl(&ir->ir_set->erst_size);
22692278
erst_size &= ERST_SIZE_MASK;
@@ -2278,14 +2287,7 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
22782287
/* Set the event ring dequeue address of this interrupter */
22792288
xhci_set_hc_event_deq(xhci, ir);
22802289

2281-
return ir;
2282-
2283-
fail_ev:
2284-
xhci_ring_free(xhci, ir->event_ring);
2285-
fail_ir:
2286-
kfree(ir);
2287-
2288-
return NULL;
2290+
return 0;
22892291
}
22902292

22912293
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
@@ -2407,15 +2409,17 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
24072409
"// Doorbell array is located at offset 0x%x from cap regs base addr",
24082410
val);
24092411
xhci->dba = (void __iomem *) xhci->cap_regs + val;
2410-
/* Set ir_set to interrupt register set 0 */
24112412

2412-
/* allocate and set up primary interrupter with an event ring. */
2413+
/* Allocate and set up primary interrupter 0 with an event ring. */
24132414
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
24142415
"Allocating primary event ring");
2415-
xhci->interrupter = xhci_alloc_interrupter(xhci, 0, flags);
2416+
xhci->interrupter = xhci_alloc_interrupter(xhci, flags);
24162417
if (!xhci->interrupter)
24172418
goto fail;
24182419

2420+
if (xhci_add_interrupter(xhci, xhci->interrupter, 0))
2421+
goto fail;
2422+
24192423
xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
24202424

24212425
/*

0 commit comments

Comments
 (0)