Skip to content

Commit b17a57f

Browse files
matnymangregkh
authored andcommitted
xhci: Refactor interrupter code for initial multi interrupter support.
xHC supports several interrupters, each with its own mmio register set, event ring and MSI/MSI-X vector. Transfers can be assigned different interrupters when queued. See xhci 4.17 for details. Current driver only supports one interrupter. Create a xhci_interrupter structure containing an event ring, pointer to mmio registers for this interrupter, variables to store registers over s3 suspend, erst, etc. Add functions to create and free an interrupter, and pass an interrupter pointer to functions that deal with events. Secondary interrupters are also useful without having an interrupt vector. One use case is the xHCI audio sideband offloading where a DSP can take care of specific audio endpoints. When all transfer events of an offloaded endpoint can be mapped to a separate interrupter event ring the DSP can poll this ring, and we can mask these events preventing waking up the CPU. Only minor functional changes such as clearing some of the interrupter registers when freeing the interrupter. Still create only one primary interrupter. Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20230202150505.618915-4-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 54f9927 commit b17a57f

File tree

5 files changed

+196
-120
lines changed

5 files changed

+196
-120
lines changed

drivers/usb/host/xhci-debugfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
692692
"command-ring",
693693
xhci->debugfs_root);
694694

695-
xhci_debugfs_create_ring_dir(xhci, &xhci->event_ring,
695+
xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
696696
"event-ring",
697697
xhci->debugfs_root);
698698

drivers/usb/host/xhci-mem.c

Lines changed: 110 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1819,17 +1819,43 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
18191819
return 0;
18201820
}
18211821

1822-
void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
1822+
static void
1823+
xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
18231824
{
1824-
size_t size;
18251825
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
1826+
size_t erst_size;
1827+
u64 tmp64;
1828+
u32 tmp;
18261829

1827-
size = sizeof(struct xhci_erst_entry) * (erst->num_entries);
1828-
if (erst->entries)
1829-
dma_free_coherent(dev, size,
1830-
erst->entries,
1831-
erst->erst_dma_addr);
1832-
erst->entries = NULL;
1830+
if (!ir)
1831+
return;
1832+
1833+
erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries);
1834+
if (ir->erst.entries)
1835+
dma_free_coherent(dev, erst_size,
1836+
ir->erst.entries,
1837+
ir->erst.erst_dma_addr);
1838+
ir->erst.entries = NULL;
1839+
1840+
/*
1841+
* Clean out interrupter registers except ERSTBA. Clearing either the
1842+
* low or high 32 bits of ERSTBA immediately causes the controller to
1843+
* dereference the partially cleared 64 bit address, causing IOMMU error.
1844+
*/
1845+
tmp = readl(&ir->ir_set->erst_size);
1846+
tmp &= ERST_SIZE_MASK;
1847+
writel(tmp, &ir->ir_set->erst_size);
1848+
1849+
tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
1850+
tmp64 &= (u64) ERST_PTR_MASK;
1851+
xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
1852+
1853+
/* free interrrupter event ring */
1854+
if (ir->event_ring)
1855+
xhci_ring_free(xhci, ir->event_ring);
1856+
ir->event_ring = NULL;
1857+
1858+
kfree(ir);
18331859
}
18341860

18351861
void xhci_mem_cleanup(struct xhci_hcd *xhci)
@@ -1839,12 +1865,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
18391865

18401866
cancel_delayed_work_sync(&xhci->cmd_timer);
18411867

1842-
xhci_free_erst(xhci, &xhci->erst);
1843-
1844-
if (xhci->event_ring)
1845-
xhci_ring_free(xhci, xhci->event_ring);
1846-
xhci->event_ring = NULL;
1847-
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
1868+
xhci_free_interrupter(xhci, xhci->interrupter);
1869+
xhci->interrupter = NULL;
1870+
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
18481871

18491872
if (xhci->cmd_ring)
18501873
xhci_ring_free(xhci, xhci->cmd_ring);
@@ -1929,18 +1952,18 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
19291952
xhci->usb3_rhub.bus_state.bus_suspended = 0;
19301953
}
19311954

1932-
static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
1955+
static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
19331956
{
19341957
u64 temp;
19351958
dma_addr_t deq;
19361959

1937-
deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
1938-
xhci->event_ring->dequeue);
1960+
deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
1961+
ir->event_ring->dequeue);
19391962
if (!deq)
19401963
xhci_warn(xhci, "WARN something wrong with SW event ring "
19411964
"dequeue ptr.\n");
19421965
/* Update HC event ring dequeue pointer */
1943-
temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
1966+
temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
19441967
temp &= ERST_PTR_MASK;
19451968
/* Don't clear the EHB bit (which is RW1C) because
19461969
* there might be more events to service.
@@ -1950,7 +1973,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
19501973
"// Write event ring dequeue pointer, "
19511974
"preserving EHB bit");
19521975
xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
1953-
&xhci->ir_set->erst_dequeue);
1976+
&ir->ir_set->erst_dequeue);
19541977
}
19551978

19561979
static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
@@ -2217,14 +2240,76 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
22172240
return 0;
22182241
}
22192242

2243+
static struct xhci_interrupter *
2244+
xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags)
2245+
{
2246+
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
2247+
struct xhci_interrupter *ir;
2248+
u64 erst_base;
2249+
u32 erst_size;
2250+
int ret;
2251+
2252+
if (intr_num > xhci->max_interrupters) {
2253+
xhci_warn(xhci, "Can't allocate interrupter %d, max interrupters %d\n",
2254+
intr_num, xhci->max_interrupters);
2255+
return NULL;
2256+
}
2257+
2258+
if (xhci->interrupter) {
2259+
xhci_warn(xhci, "Can't allocate already set up interrupter %d\n", intr_num);
2260+
return NULL;
2261+
}
2262+
2263+
ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
2264+
if (!ir)
2265+
return NULL;
2266+
2267+
ir->ir_set = &xhci->run_regs->ir_set[intr_num];
2268+
ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
2269+
0, flags);
2270+
if (!ir->event_ring) {
2271+
xhci_warn(xhci, "Failed to allocate interrupter %d event ring\n", intr_num);
2272+
goto fail_ir;
2273+
}
2274+
2275+
ret = xhci_alloc_erst(xhci, ir->event_ring, &ir->erst, flags);
2276+
if (ret) {
2277+
xhci_warn(xhci, "Failed to allocate interrupter %d erst\n", intr_num);
2278+
goto fail_ev;
2279+
2280+
}
2281+
/* set ERST count with the number of entries in the segment table */
2282+
erst_size = readl(&ir->ir_set->erst_size);
2283+
erst_size &= ERST_SIZE_MASK;
2284+
erst_size |= ERST_NUM_SEGS;
2285+
writel(erst_size, &ir->ir_set->erst_size);
2286+
2287+
erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
2288+
erst_base &= ERST_PTR_MASK;
2289+
erst_base |= (ir->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
2290+
xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
2291+
2292+
/* Set the event ring dequeue address of this interrupter */
2293+
xhci_set_hc_event_deq(xhci, ir);
2294+
2295+
return ir;
2296+
2297+
fail_ev:
2298+
xhci_ring_free(xhci, ir->event_ring);
2299+
fail_ir:
2300+
kfree(ir);
2301+
2302+
return NULL;
2303+
}
2304+
22202305
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
22212306
{
22222307
dma_addr_t dma;
22232308
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
22242309
unsigned int val, val2;
22252310
u64 val_64;
22262311
u32 page_size, temp;
2227-
int i, ret;
2312+
int i;
22282313

22292314
INIT_LIST_HEAD(&xhci->cmd_list);
22302315

@@ -2337,46 +2422,13 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
23372422
" from cap regs base addr", val);
23382423
xhci->dba = (void __iomem *) xhci->cap_regs + val;
23392424
/* Set ir_set to interrupt register set 0 */
2340-
xhci->ir_set = &xhci->run_regs->ir_set[0];
2341-
2342-
/*
2343-
* Event ring setup: Allocate a normal ring, but also setup
2344-
* the event ring segment table (ERST). Section 4.9.3.
2345-
*/
2346-
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
2347-
xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
2348-
0, flags);
2349-
if (!xhci->event_ring)
2350-
goto fail;
2351-
2352-
ret = xhci_alloc_erst(xhci, xhci->event_ring, &xhci->erst, flags);
2353-
if (ret)
2354-
goto fail;
2355-
2356-
/* set ERST count with the number of entries in the segment table */
2357-
val = readl(&xhci->ir_set->erst_size);
2358-
val &= ERST_SIZE_MASK;
2359-
val |= ERST_NUM_SEGS;
2360-
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
2361-
"// Write ERST size = %i to ir_set 0 (some bits preserved)",
2362-
val);
2363-
writel(val, &xhci->ir_set->erst_size);
23642425

2426+
/* allocate and set up primary interrupter with an event ring. */
23652427
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
2366-
"// Set ERST entries to point to event ring.");
2367-
/* set the segment table base address */
2368-
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
2369-
"// Set ERST base address for ir_set 0 = 0x%llx",
2370-
(unsigned long long)xhci->erst.erst_dma_addr);
2371-
val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
2372-
val_64 &= ERST_BASE_RSVDP;
2373-
val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_BASE_RSVDP);
2374-
xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
2375-
2376-
/* Set the event ring dequeue address */
2377-
xhci_set_hc_event_deq(xhci);
2378-
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
2379-
"Wrote ERST address to ir_set 0.");
2428+
"Allocating primary event ring");
2429+
xhci->interrupter = xhci_alloc_interrupter(xhci, 0, flags);
2430+
if (!xhci->interrupter)
2431+
goto fail;
23802432

23812433
xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
23822434

0 commit comments

Comments
 (0)