mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
Revert "Merge 71147efd68 ("usb: xhci: fix loss of data on Cadence xHC") into android14-6.1-lts"
This reverts commitd2e4c7790d, reversing changes made to27d626695a. This reverts the recent USB xhci changes that were just merged, as they break the kernel abi. If they are needed, they can be brought back in the future in an abi-safe way. Bug: 161946584 Change-Id: I57060237f6709650a69373651accd2748fcb2aa3 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -62,9 +62,7 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
|
||||
.resume_quirk = xhci_cdns3_resume_quirk,
|
||||
};
|
||||
|
||||
static const struct xhci_plat_priv xhci_plat_cdnsp_xhci = {
|
||||
.quirks = XHCI_CDNS_SCTX_QUIRK,
|
||||
};
|
||||
static const struct xhci_plat_priv xhci_plat_cdnsp_xhci;
|
||||
|
||||
static int __cdns_host_init(struct cdns *cdns)
|
||||
{
|
||||
|
||||
@@ -693,7 +693,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
|
||||
"command-ring",
|
||||
xhci->debugfs_root);
|
||||
|
||||
xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
|
||||
xhci_debugfs_create_ring_dir(xhci, &xhci->event_ring,
|
||||
"event-ring",
|
||||
xhci->debugfs_root);
|
||||
|
||||
|
||||
@@ -1902,44 +1902,19 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xhci_alloc_erst);
|
||||
|
||||
static void
|
||||
xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
|
||||
{
|
||||
size_t size;
|
||||
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
|
||||
* dereference the partially cleared 64 bit address, causing IOMMU error.
|
||||
*/
|
||||
tmp = readl(&ir->ir_set->erst_size);
|
||||
tmp &= ERST_SIZE_MASK;
|
||||
writel(tmp, &ir->ir_set->erst_size);
|
||||
|
||||
tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
||||
tmp64 &= (u64) ERST_PTR_MASK;
|
||||
xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
|
||||
|
||||
/* free interrrupter event ring */
|
||||
if (ir->event_ring)
|
||||
xhci_ring_free(xhci, ir->event_ring);
|
||||
ir->event_ring = NULL;
|
||||
|
||||
kfree(ir);
|
||||
size = sizeof(struct xhci_erst_entry) * (erst->num_entries);
|
||||
if (erst->entries)
|
||||
dma_free_coherent(dev, size,
|
||||
erst->entries,
|
||||
erst->erst_dma_addr);
|
||||
erst->entries = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xhci_free_erst);
|
||||
|
||||
static struct xhci_device_context_array *xhci_vendor_alloc_dcbaa(
|
||||
struct xhci_hcd *xhci, gfp_t flags)
|
||||
@@ -1966,9 +1941,12 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
|
||||
cancel_delayed_work_sync(&xhci->cmd_timer);
|
||||
|
||||
xhci_free_interrupter(xhci, xhci->interrupter);
|
||||
xhci->interrupter = NULL;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
|
||||
xhci_free_erst(xhci, &xhci->erst);
|
||||
|
||||
if (xhci->event_ring)
|
||||
xhci_ring_free(xhci, xhci->event_ring);
|
||||
xhci->event_ring = NULL;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
|
||||
|
||||
if (xhci->cmd_ring)
|
||||
xhci_ring_free(xhci, xhci->cmd_ring);
|
||||
@@ -2057,18 +2035,177 @@ no_bw:
|
||||
xhci->usb3_rhub.bus_state.bus_suspended = 0;
|
||||
}
|
||||
|
||||
static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
|
||||
struct xhci_segment *input_seg,
|
||||
union xhci_trb *start_trb,
|
||||
union xhci_trb *end_trb,
|
||||
dma_addr_t input_dma,
|
||||
struct xhci_segment *result_seg,
|
||||
char *test_name, int test_number)
|
||||
{
|
||||
unsigned long long start_dma;
|
||||
unsigned long long end_dma;
|
||||
struct xhci_segment *seg;
|
||||
|
||||
start_dma = xhci_trb_virt_to_dma(input_seg, start_trb);
|
||||
end_dma = xhci_trb_virt_to_dma(input_seg, end_trb);
|
||||
|
||||
seg = trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma, false);
|
||||
if (seg != result_seg) {
|
||||
xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n",
|
||||
test_name, test_number);
|
||||
xhci_warn(xhci, "Tested TRB math w/ seg %p and "
|
||||
"input DMA 0x%llx\n",
|
||||
input_seg,
|
||||
(unsigned long long) input_dma);
|
||||
xhci_warn(xhci, "starting TRB %p (0x%llx DMA), "
|
||||
"ending TRB %p (0x%llx DMA)\n",
|
||||
start_trb, start_dma,
|
||||
end_trb, end_dma);
|
||||
xhci_warn(xhci, "Expected seg %p, got seg %p\n",
|
||||
result_seg, seg);
|
||||
trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma,
|
||||
true);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TRB math checks for xhci_trb_in_td(), using the command and event rings. */
|
||||
int xhci_check_trb_in_td_math(struct xhci_hcd *xhci)
|
||||
{
|
||||
struct {
|
||||
dma_addr_t input_dma;
|
||||
struct xhci_segment *result_seg;
|
||||
} simple_test_vector [] = {
|
||||
/* A zeroed DMA field should fail */
|
||||
{ 0, NULL },
|
||||
/* One TRB before the ring start should fail */
|
||||
{ xhci->event_ring->first_seg->dma - 16, NULL },
|
||||
/* One byte before the ring start should fail */
|
||||
{ xhci->event_ring->first_seg->dma - 1, NULL },
|
||||
/* Starting TRB should succeed */
|
||||
{ xhci->event_ring->first_seg->dma, xhci->event_ring->first_seg },
|
||||
/* Ending TRB should succeed */
|
||||
{ xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16,
|
||||
xhci->event_ring->first_seg },
|
||||
/* One byte after the ring end should fail */
|
||||
{ xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16 + 1, NULL },
|
||||
/* One TRB after the ring end should fail */
|
||||
{ xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT)*16, NULL },
|
||||
/* An address of all ones should fail */
|
||||
{ (dma_addr_t) (~0), NULL },
|
||||
};
|
||||
struct {
|
||||
struct xhci_segment *input_seg;
|
||||
union xhci_trb *start_trb;
|
||||
union xhci_trb *end_trb;
|
||||
dma_addr_t input_dma;
|
||||
struct xhci_segment *result_seg;
|
||||
} complex_test_vector [] = {
|
||||
/* Test feeding a valid DMA address from a different ring */
|
||||
{ .input_seg = xhci->event_ring->first_seg,
|
||||
.start_trb = xhci->event_ring->first_seg->trbs,
|
||||
.end_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
|
||||
.input_dma = xhci->cmd_ring->first_seg->dma,
|
||||
.result_seg = NULL,
|
||||
},
|
||||
/* Test feeding a valid end TRB from a different ring */
|
||||
{ .input_seg = xhci->event_ring->first_seg,
|
||||
.start_trb = xhci->event_ring->first_seg->trbs,
|
||||
.end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
|
||||
.input_dma = xhci->cmd_ring->first_seg->dma,
|
||||
.result_seg = NULL,
|
||||
},
|
||||
/* Test feeding a valid start and end TRB from a different ring */
|
||||
{ .input_seg = xhci->event_ring->first_seg,
|
||||
.start_trb = xhci->cmd_ring->first_seg->trbs,
|
||||
.end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
|
||||
.input_dma = xhci->cmd_ring->first_seg->dma,
|
||||
.result_seg = NULL,
|
||||
},
|
||||
/* TRB in this ring, but after this TD */
|
||||
{ .input_seg = xhci->event_ring->first_seg,
|
||||
.start_trb = &xhci->event_ring->first_seg->trbs[0],
|
||||
.end_trb = &xhci->event_ring->first_seg->trbs[3],
|
||||
.input_dma = xhci->event_ring->first_seg->dma + 4*16,
|
||||
.result_seg = NULL,
|
||||
},
|
||||
/* TRB in this ring, but before this TD */
|
||||
{ .input_seg = xhci->event_ring->first_seg,
|
||||
.start_trb = &xhci->event_ring->first_seg->trbs[3],
|
||||
.end_trb = &xhci->event_ring->first_seg->trbs[6],
|
||||
.input_dma = xhci->event_ring->first_seg->dma + 2*16,
|
||||
.result_seg = NULL,
|
||||
},
|
||||
/* TRB in this ring, but after this wrapped TD */
|
||||
{ .input_seg = xhci->event_ring->first_seg,
|
||||
.start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
|
||||
.end_trb = &xhci->event_ring->first_seg->trbs[1],
|
||||
.input_dma = xhci->event_ring->first_seg->dma + 2*16,
|
||||
.result_seg = NULL,
|
||||
},
|
||||
/* TRB in this ring, but before this wrapped TD */
|
||||
{ .input_seg = xhci->event_ring->first_seg,
|
||||
.start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
|
||||
.end_trb = &xhci->event_ring->first_seg->trbs[1],
|
||||
.input_dma = xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 4)*16,
|
||||
.result_seg = NULL,
|
||||
},
|
||||
/* TRB not in this ring, and we have a wrapped TD */
|
||||
{ .input_seg = xhci->event_ring->first_seg,
|
||||
.start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
|
||||
.end_trb = &xhci->event_ring->first_seg->trbs[1],
|
||||
.input_dma = xhci->cmd_ring->first_seg->dma + 2*16,
|
||||
.result_seg = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
unsigned int num_tests;
|
||||
int i, ret;
|
||||
|
||||
num_tests = ARRAY_SIZE(simple_test_vector);
|
||||
for (i = 0; i < num_tests; i++) {
|
||||
ret = xhci_test_trb_in_td(xhci,
|
||||
xhci->event_ring->first_seg,
|
||||
xhci->event_ring->first_seg->trbs,
|
||||
&xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
|
||||
simple_test_vector[i].input_dma,
|
||||
simple_test_vector[i].result_seg,
|
||||
"Simple", i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
num_tests = ARRAY_SIZE(complex_test_vector);
|
||||
for (i = 0; i < num_tests; i++) {
|
||||
ret = xhci_test_trb_in_td(xhci,
|
||||
complex_test_vector[i].input_seg,
|
||||
complex_test_vector[i].start_trb,
|
||||
complex_test_vector[i].end_trb,
|
||||
complex_test_vector[i].input_dma,
|
||||
complex_test_vector[i].result_seg,
|
||||
"Complex", i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
xhci_dbg(xhci, "TRB math tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xhci_check_trb_in_td_math);
|
||||
|
||||
static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
|
||||
{
|
||||
u64 temp;
|
||||
dma_addr_t deq;
|
||||
|
||||
deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
|
||||
ir->event_ring->dequeue);
|
||||
deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
|
||||
xhci->event_ring->dequeue);
|
||||
if (!deq)
|
||||
xhci_warn(xhci, "WARN something wrong with SW event ring "
|
||||
"dequeue ptr.\n");
|
||||
/* Update HC event ring dequeue pointer */
|
||||
temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
||||
temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
temp &= ERST_PTR_MASK;
|
||||
/* Don't clear the EHB bit (which is RW1C) because
|
||||
* there might be more events to service.
|
||||
@@ -2078,7 +2215,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter
|
||||
"// Write event ring dequeue pointer, "
|
||||
"preserving EHB bit");
|
||||
xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
|
||||
&ir->ir_set->erst_dequeue);
|
||||
&xhci->ir_set->erst_dequeue);
|
||||
}
|
||||
|
||||
static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
||||
@@ -2362,71 +2499,6 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct xhci_interrupter *
|
||||
xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags)
|
||||
{
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
struct xhci_interrupter *ir;
|
||||
u64 erst_base;
|
||||
u32 erst_size;
|
||||
int ret;
|
||||
|
||||
if (intr_num > xhci->max_interrupters) {
|
||||
xhci_warn(xhci, "Can't allocate interrupter %d, max interrupters %d\n",
|
||||
intr_num, xhci->max_interrupters);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (xhci->interrupter) {
|
||||
xhci_warn(xhci, "Can't allocate already set up interrupter %d\n", intr_num);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
|
||||
if (!ir)
|
||||
return NULL;
|
||||
|
||||
ir->ir_set = &xhci->run_regs->ir_set[intr_num];
|
||||
ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
|
||||
0, flags);
|
||||
if (!ir->event_ring) {
|
||||
xhci_warn(xhci, "Failed to allocate interrupter %d event ring\n", intr_num);
|
||||
goto fail_ir;
|
||||
}
|
||||
|
||||
ret = xhci_alloc_erst(xhci, ir->event_ring, &ir->erst, flags);
|
||||
if (ret) {
|
||||
xhci_warn(xhci, "Failed to allocate interrupter %d erst\n", intr_num);
|
||||
goto fail_ev;
|
||||
|
||||
}
|
||||
/* set ERST count with the number of entries in the segment table */
|
||||
erst_size = readl(&ir->ir_set->erst_size);
|
||||
erst_size &= ERST_SIZE_MASK;
|
||||
erst_size |= ERST_NUM_SEGS;
|
||||
writel(erst_size, &ir->ir_set->erst_size);
|
||||
|
||||
erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
|
||||
erst_base &= ERST_BASE_RSVDP;
|
||||
erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
|
||||
if (xhci->quirks & XHCI_WRITE_64_HI_LO)
|
||||
hi_lo_writeq(erst_base, &ir->ir_set->erst_base);
|
||||
else
|
||||
xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
|
||||
|
||||
/* Set the event ring dequeue address of this interrupter */
|
||||
xhci_set_hc_event_deq(xhci, ir);
|
||||
|
||||
return ir;
|
||||
|
||||
fail_ev:
|
||||
xhci_ring_free(xhci, ir->event_ring);
|
||||
fail_ir:
|
||||
kfree(ir);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
{
|
||||
dma_addr_t dma;
|
||||
@@ -2434,7 +2506,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
unsigned int val, val2;
|
||||
u64 val_64;
|
||||
u32 page_size, temp;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
INIT_LIST_HEAD(&xhci->cmd_list);
|
||||
|
||||
@@ -2557,13 +2629,48 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
" from cap regs base addr", val);
|
||||
xhci->dba = (void __iomem *) xhci->cap_regs + val;
|
||||
/* Set ir_set to interrupt register set 0 */
|
||||
xhci->ir_set = &xhci->run_regs->ir_set[0];
|
||||
|
||||
/* allocate and set up primary interrupter with an event ring. */
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"Allocating primary event ring");
|
||||
xhci->interrupter = xhci_alloc_interrupter(xhci, 0, flags);
|
||||
if (!xhci->interrupter)
|
||||
/*
|
||||
* Event ring setup: Allocate a normal ring, but also setup
|
||||
* the event ring segment table (ERST). Section 4.9.3.
|
||||
*/
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
|
||||
xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
|
||||
0, flags);
|
||||
if (!xhci->event_ring)
|
||||
goto fail;
|
||||
if (xhci_check_trb_in_td_math(xhci) < 0)
|
||||
goto fail;
|
||||
|
||||
ret = xhci_alloc_erst(xhci, xhci->event_ring, &xhci->erst, flags);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/* set ERST count with the number of entries in the segment table */
|
||||
val = readl(&xhci->ir_set->erst_size);
|
||||
val &= ERST_SIZE_MASK;
|
||||
val |= ERST_NUM_SEGS;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"// Write ERST size = %i to ir_set 0 (some bits preserved)",
|
||||
val);
|
||||
writel(val, &xhci->ir_set->erst_size);
|
||||
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"// Set ERST entries to point to event ring.");
|
||||
/* set the segment table base address */
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"// Set ERST base address for ir_set 0 = 0x%llx",
|
||||
(unsigned long long)xhci->erst.erst_dma_addr);
|
||||
val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
|
||||
val_64 &= ERST_PTR_MASK;
|
||||
val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
|
||||
xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
|
||||
|
||||
/* Set the event ring dequeue address */
|
||||
xhci_set_hc_event_deq(xhci);
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"Wrote ERST address to ir_set 0.");
|
||||
|
||||
xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
|
||||
|
||||
|
||||
@@ -75,9 +75,6 @@
|
||||
#define PCI_DEVICE_ID_ASMEDIA_2142_XHCI 0x2142
|
||||
#define PCI_DEVICE_ID_ASMEDIA_3242_XHCI 0x3242
|
||||
|
||||
#define PCI_DEVICE_ID_CADENCE 0x17CD
|
||||
#define PCI_DEVICE_ID_CADENCE_SSP 0x0200
|
||||
|
||||
static const char hcd_name[] = "xhci_hcd";
|
||||
|
||||
static struct hc_driver __read_mostly xhci_pci_hc_driver;
|
||||
@@ -355,10 +352,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
|
||||
}
|
||||
|
||||
if (pdev->vendor == PCI_DEVICE_ID_CADENCE &&
|
||||
pdev->device == PCI_DEVICE_ID_CADENCE_SSP)
|
||||
xhci->quirks |= XHCI_CDNS_SCTX_QUIRK;
|
||||
|
||||
/* xHC spec requires PCI devices to support D3hot and D3cold */
|
||||
if (xhci->hci_version >= 0x120)
|
||||
xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
|
||||
|
||||
@@ -1385,20 +1385,6 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
|
||||
struct xhci_stream_ctx *ctx =
|
||||
&ep->stream_info->stream_ctx_array[stream_id];
|
||||
deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK;
|
||||
|
||||
/*
|
||||
* Cadence xHCI controllers store some endpoint state
|
||||
* information within Rsvd0 fields of Stream Endpoint
|
||||
* context. This field is not cleared during Set TR
|
||||
* Dequeue Pointer command which causes XDMA to skip
|
||||
* over transfer ring and leads to data loss on stream
|
||||
* pipe.
|
||||
* To fix this issue driver must clear Rsvd0 field.
|
||||
*/
|
||||
if (xhci->quirks & XHCI_CDNS_SCTX_QUIRK) {
|
||||
ctx->reserved[0] = 0;
|
||||
ctx->reserved[1] = 0;
|
||||
}
|
||||
} else {
|
||||
deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
|
||||
}
|
||||
@@ -1879,8 +1865,7 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
|
||||
}
|
||||
|
||||
static void handle_port_status(struct xhci_hcd *xhci,
|
||||
struct xhci_interrupter *ir,
|
||||
union xhci_trb *event)
|
||||
union xhci_trb *event)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
u32 port_id;
|
||||
@@ -1903,7 +1888,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||
if ((port_id <= 0) || (port_id > max_ports)) {
|
||||
xhci_warn(xhci, "Port change event with invalid port ID %d\n",
|
||||
port_id);
|
||||
inc_deq(xhci, ir->event_ring);
|
||||
inc_deq(xhci, xhci->event_ring);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2033,7 +2018,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||
|
||||
cleanup:
|
||||
/* Update event ring dequeue pointer before dropping the lock */
|
||||
inc_deq(xhci, ir->event_ring);
|
||||
inc_deq(xhci, xhci->event_ring);
|
||||
|
||||
/* Don't make the USB core poll the roothub if we got a bad port status
|
||||
* change event. Besides, at that point we can't tell which roothub
|
||||
@@ -2594,8 +2579,7 @@ finish_td:
|
||||
* At this point, the host controller is probably hosed and should be reset.
|
||||
*/
|
||||
static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
struct xhci_interrupter *ir,
|
||||
struct xhci_transfer_event *event)
|
||||
struct xhci_transfer_event *event)
|
||||
{
|
||||
struct xhci_virt_ep *ep;
|
||||
struct xhci_ring *ep_ring;
|
||||
@@ -2981,7 +2965,7 @@ cleanup:
|
||||
* processing missed tds.
|
||||
*/
|
||||
if (!handling_skipped_tds)
|
||||
inc_deq(xhci, ir->event_ring);
|
||||
inc_deq(xhci, xhci->event_ring);
|
||||
|
||||
/*
|
||||
* If ep->skip is set, it means there are missed tds on the
|
||||
@@ -2996,8 +2980,8 @@ cleanup:
|
||||
err_out:
|
||||
xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
|
||||
(unsigned long long) xhci_trb_virt_to_dma(
|
||||
ir->event_ring->deq_seg,
|
||||
ir->event_ring->dequeue),
|
||||
xhci->event_ring->deq_seg,
|
||||
xhci->event_ring->dequeue),
|
||||
lower_32_bits(le64_to_cpu(event->buffer)),
|
||||
upper_32_bits(le64_to_cpu(event->buffer)),
|
||||
le32_to_cpu(event->transfer_len),
|
||||
@@ -3011,7 +2995,7 @@ err_out:
|
||||
* Returns >0 for "possibly more events to process" (caller should call again),
|
||||
* otherwise 0 if done. In future, <0 returns should indicate error code.
|
||||
*/
|
||||
static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
static int xhci_handle_event(struct xhci_hcd *xhci)
|
||||
{
|
||||
union xhci_trb *event;
|
||||
int update_ptrs = 1;
|
||||
@@ -3019,18 +3003,18 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
int ret;
|
||||
|
||||
/* Event ring hasn't been allocated yet. */
|
||||
if (!ir || !ir->event_ring || !ir->event_ring->dequeue) {
|
||||
xhci_err(xhci, "ERROR interrupter not ready\n");
|
||||
if (!xhci->event_ring || !xhci->event_ring->dequeue) {
|
||||
xhci_err(xhci, "ERROR event ring not ready\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
event = ir->event_ring->dequeue;
|
||||
event = xhci->event_ring->dequeue;
|
||||
/* Does the HC or OS own the TRB? */
|
||||
if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=
|
||||
ir->event_ring->cycle_state)
|
||||
xhci->event_ring->cycle_state)
|
||||
return 0;
|
||||
|
||||
trace_xhci_handle_event(ir->event_ring, &event->generic);
|
||||
trace_xhci_handle_event(xhci->event_ring, &event->generic);
|
||||
|
||||
/*
|
||||
* Barrier between reading the TRB_CYCLE (valid) flag above and any
|
||||
@@ -3045,11 +3029,11 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
handle_cmd_completion(xhci, &event->event_cmd);
|
||||
break;
|
||||
case TRB_PORT_STATUS:
|
||||
handle_port_status(xhci, ir, event);
|
||||
handle_port_status(xhci, event);
|
||||
update_ptrs = 0;
|
||||
break;
|
||||
case TRB_TRANSFER:
|
||||
ret = handle_tx_event(xhci, ir, &event->trans_event);
|
||||
ret = handle_tx_event(xhci, &event->trans_event);
|
||||
if (ret >= 0)
|
||||
update_ptrs = 0;
|
||||
break;
|
||||
@@ -3073,7 +3057,7 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
|
||||
if (update_ptrs)
|
||||
/* Update SW event ring dequeue pointer */
|
||||
inc_deq(xhci, ir->event_ring);
|
||||
inc_deq(xhci, xhci->event_ring);
|
||||
|
||||
/* Are there more items on the event ring? Caller will call us again to
|
||||
* check.
|
||||
@@ -3087,17 +3071,16 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
* - To avoid "Event Ring Full Error" condition
|
||||
*/
|
||||
static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
|
||||
struct xhci_interrupter *ir,
|
||||
union xhci_trb *event_ring_deq)
|
||||
union xhci_trb *event_ring_deq)
|
||||
{
|
||||
u64 temp_64;
|
||||
dma_addr_t deq;
|
||||
|
||||
temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
||||
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
/* If necessary, update the HW's version of the event ring deq ptr. */
|
||||
if (event_ring_deq != ir->event_ring->dequeue) {
|
||||
deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
|
||||
ir->event_ring->dequeue);
|
||||
if (event_ring_deq != xhci->event_ring->dequeue) {
|
||||
deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
|
||||
xhci->event_ring->dequeue);
|
||||
if (deq == 0)
|
||||
xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n");
|
||||
/*
|
||||
@@ -3115,7 +3098,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
|
||||
|
||||
/* Clear the event handler busy flag (RW1C) */
|
||||
temp_64 |= ERST_EHB;
|
||||
xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue);
|
||||
xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3127,7 +3110,6 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
union xhci_trb *event_ring_deq;
|
||||
struct xhci_interrupter *ir;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u64 temp_64;
|
||||
u32 status;
|
||||
@@ -3160,13 +3142,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
status |= STS_EINT;
|
||||
writel(status, &xhci->op_regs->status);
|
||||
|
||||
/* This is the handler of the primary interrupter */
|
||||
ir = xhci->interrupter;
|
||||
if (!hcd->msi_enabled) {
|
||||
u32 irq_pending;
|
||||
irq_pending = readl(&ir->ir_set->irq_pending);
|
||||
irq_pending = readl(&xhci->ir_set->irq_pending);
|
||||
irq_pending |= IMAN_IP;
|
||||
writel(irq_pending, &ir->ir_set->irq_pending);
|
||||
writel(irq_pending, &xhci->ir_set->irq_pending);
|
||||
}
|
||||
|
||||
if (xhci->xhc_state & XHCI_STATE_DYING ||
|
||||
@@ -3176,22 +3156,22 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
/* Clear the event handler busy flag (RW1C);
|
||||
* the event ring should be empty.
|
||||
*/
|
||||
temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
||||
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
xhci_write_64(xhci, temp_64 | ERST_EHB,
|
||||
&ir->ir_set->erst_dequeue);
|
||||
&xhci->ir_set->erst_dequeue);
|
||||
ret = IRQ_HANDLED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
event_ring_deq = ir->event_ring->dequeue;
|
||||
event_ring_deq = xhci->event_ring->dequeue;
|
||||
/* FIXME this should be a delayed service routine
|
||||
* that clears the EHB.
|
||||
*/
|
||||
while (xhci_handle_event(xhci, ir) > 0) {
|
||||
while (xhci_handle_event(xhci) > 0) {
|
||||
if (event_loop++ < TRBS_PER_SEGMENT / 2)
|
||||
continue;
|
||||
xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
|
||||
event_ring_deq = ir->event_ring->dequeue;
|
||||
xhci_update_erst_dequeue(xhci, event_ring_deq);
|
||||
event_ring_deq = xhci->event_ring->dequeue;
|
||||
|
||||
/* ring is half-full, force isoc trbs to interrupt more often */
|
||||
if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
|
||||
@@ -3200,7 +3180,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
event_loop = 0;
|
||||
}
|
||||
|
||||
xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
|
||||
xhci_update_erst_dequeue(xhci, event_ring_deq);
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
out:
|
||||
|
||||
@@ -619,7 +619,6 @@ static int xhci_init(struct usb_hcd *hcd)
|
||||
|
||||
static int xhci_run_finished(struct xhci_hcd *xhci)
|
||||
{
|
||||
struct xhci_interrupter *ir = xhci->interrupter;
|
||||
unsigned long flags;
|
||||
u32 temp;
|
||||
|
||||
@@ -635,8 +634,8 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
|
||||
writel(temp, &xhci->op_regs->command);
|
||||
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Enable primary interrupter");
|
||||
temp = readl(&ir->ir_set->irq_pending);
|
||||
writel(ER_IRQ_ENABLE(temp), &ir->ir_set->irq_pending);
|
||||
temp = readl(&xhci->ir_set->irq_pending);
|
||||
writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
|
||||
|
||||
if (xhci_start(xhci)) {
|
||||
xhci_halt(xhci);
|
||||
@@ -672,7 +671,7 @@ int xhci_run(struct usb_hcd *hcd)
|
||||
u64 temp_64;
|
||||
int ret;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct xhci_interrupter *ir = xhci->interrupter;
|
||||
|
||||
/* Start the xHCI host controller running only after the USB 2.0 roothub
|
||||
* is setup.
|
||||
*/
|
||||
@@ -687,17 +686,17 @@ int xhci_run(struct usb_hcd *hcd)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
||||
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
temp_64 &= ~ERST_PTR_MASK;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"ERST deq = 64'h%0lx", (long unsigned int) temp_64);
|
||||
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"// Set the interrupt modulation register");
|
||||
temp = readl(&ir->ir_set->irq_control);
|
||||
temp = readl(&xhci->ir_set->irq_control);
|
||||
temp &= ~ER_IRQ_INTERVAL_MASK;
|
||||
temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
|
||||
writel(temp, &ir->ir_set->irq_control);
|
||||
writel(temp, &xhci->ir_set->irq_control);
|
||||
|
||||
if (xhci->quirks & XHCI_NEC_HOST) {
|
||||
struct xhci_command *command;
|
||||
@@ -776,8 +775,8 @@ static void xhci_stop(struct usb_hcd *hcd)
|
||||
"// Disabling event ring interrupts");
|
||||
temp = readl(&xhci->op_regs->status);
|
||||
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
|
||||
temp = readl(&xhci->interrupter->ir_set->irq_pending);
|
||||
writel(ER_IRQ_DISABLE(temp), &xhci->interrupter->ir_set->irq_pending);
|
||||
temp = readl(&xhci->ir_set->irq_pending);
|
||||
writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
|
||||
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
|
||||
xhci_mem_cleanup(xhci);
|
||||
@@ -839,36 +838,28 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
|
||||
#ifdef CONFIG_PM
|
||||
static void xhci_save_registers(struct xhci_hcd *xhci)
|
||||
{
|
||||
struct xhci_interrupter *ir = xhci->interrupter;
|
||||
|
||||
xhci->s3.command = readl(&xhci->op_regs->command);
|
||||
xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
|
||||
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
|
||||
xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
|
||||
|
||||
if (!ir)
|
||||
return;
|
||||
|
||||
ir->s3_erst_size = readl(&ir->ir_set->erst_size);
|
||||
ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
|
||||
ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
||||
ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
|
||||
ir->s3_irq_control = readl(&ir->ir_set->irq_control);
|
||||
xhci->s3.erst_size = readl(&xhci->ir_set->erst_size);
|
||||
xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
|
||||
xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending);
|
||||
xhci->s3.irq_control = readl(&xhci->ir_set->irq_control);
|
||||
}
|
||||
|
||||
static void xhci_restore_registers(struct xhci_hcd *xhci)
|
||||
{
|
||||
struct xhci_interrupter *ir = xhci->interrupter;
|
||||
|
||||
writel(xhci->s3.command, &xhci->op_regs->command);
|
||||
writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
|
||||
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
|
||||
writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
|
||||
writel(ir->s3_erst_size, &ir->ir_set->erst_size);
|
||||
xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
|
||||
xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
|
||||
writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
|
||||
writel(ir->s3_irq_control, &ir->ir_set->irq_control);
|
||||
writel(xhci->s3.erst_size, &xhci->ir_set->erst_size);
|
||||
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
|
||||
xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
|
||||
writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
|
||||
writel(xhci->s3.irq_control, &xhci->ir_set->irq_control);
|
||||
}
|
||||
|
||||
static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
|
||||
@@ -1235,8 +1226,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
||||
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
|
||||
temp = readl(&xhci->op_regs->status);
|
||||
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
|
||||
temp = readl(&xhci->interrupter->ir_set->irq_pending);
|
||||
writel(ER_IRQ_DISABLE(temp), &xhci->interrupter->ir_set->irq_pending);
|
||||
temp = readl(&xhci->ir_set->irq_pending);
|
||||
writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
|
||||
|
||||
xhci_dbg(xhci, "cleaning up memory\n");
|
||||
xhci_mem_cleanup(xhci);
|
||||
@@ -5465,11 +5456,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
||||
if (xhci->hci_version > 0x100)
|
||||
xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
|
||||
|
||||
/* xhci-plat or xhci-pci might have set max_interrupters already */
|
||||
if ((!xhci->max_interrupters) ||
|
||||
xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1))
|
||||
xhci->max_interrupters = HCS_MAX_INTRS(xhci->hcs_params1);
|
||||
|
||||
xhci->quirks |= quirks;
|
||||
|
||||
get_quirks(dev, xhci);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||
#include <linux/android_kabi.h>
|
||||
|
||||
/* Code sharing between pci-quirks and xhci hcd */
|
||||
@@ -515,9 +514,6 @@ struct xhci_intr_reg {
|
||||
/* Preserve bits 16:31 of erst_size */
|
||||
#define ERST_SIZE_MASK (0xffff << 16)
|
||||
|
||||
/* erst_base bitmasks */
|
||||
#define ERST_BASE_RSVDP (GENMASK_ULL(5, 0))
|
||||
|
||||
/* erst_dequeue bitmasks */
|
||||
/* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
|
||||
* where the current dequeue pointer lies. This is an optional HW hint.
|
||||
@@ -1701,6 +1697,11 @@ struct s3_save {
|
||||
u32 dev_nt;
|
||||
u64 dcbaa_ptr;
|
||||
u32 config_reg;
|
||||
u32 irq_pending;
|
||||
u32 irq_control;
|
||||
u32 erst_size;
|
||||
u64 erst_base;
|
||||
u64 erst_dequeue;
|
||||
};
|
||||
|
||||
/* Use for lpm */
|
||||
@@ -1727,18 +1728,7 @@ struct xhci_bus_state {
|
||||
struct completion u3exit_done[USB_MAXCHILDREN];
|
||||
};
|
||||
|
||||
struct xhci_interrupter {
|
||||
struct xhci_ring *event_ring;
|
||||
struct xhci_erst erst;
|
||||
struct xhci_intr_reg __iomem *ir_set;
|
||||
unsigned int intr_num;
|
||||
/* For interrupter registers save and restore over suspend/resume */
|
||||
u32 s3_irq_pending;
|
||||
u32 s3_irq_control;
|
||||
u32 s3_erst_size;
|
||||
u64 s3_erst_base;
|
||||
u64 s3_erst_dequeue;
|
||||
};
|
||||
|
||||
/*
|
||||
* It can take up to 20 ms to transition from RExit to U0 on the
|
||||
* Intel Lynx Point LP xHCI host.
|
||||
@@ -1781,6 +1771,8 @@ struct xhci_hcd {
|
||||
struct xhci_op_regs __iomem *op_regs;
|
||||
struct xhci_run_regs __iomem *run_regs;
|
||||
struct xhci_doorbell_array __iomem *dba;
|
||||
/* Our HCD's current interrupter register set */
|
||||
struct xhci_intr_reg __iomem *ir_set;
|
||||
|
||||
/* Cached register copies of read-only HC data */
|
||||
__u32 hcs_params1;
|
||||
@@ -1795,7 +1787,7 @@ struct xhci_hcd {
|
||||
u8 sbrn;
|
||||
u16 hci_version;
|
||||
u8 max_slots;
|
||||
u16 max_interrupters;
|
||||
u8 max_interrupters;
|
||||
u8 max_ports;
|
||||
u8 isoc_threshold;
|
||||
/* imod_interval in ns (I * 250ns) */
|
||||
@@ -1815,7 +1807,6 @@ struct xhci_hcd {
|
||||
struct reset_control *reset;
|
||||
/* data structures */
|
||||
struct xhci_device_context_array *dcbaa;
|
||||
struct xhci_interrupter *interrupter;
|
||||
struct xhci_ring *cmd_ring;
|
||||
unsigned int cmd_ring_state;
|
||||
#define CMD_RING_STATE_RUNNING (1 << 0)
|
||||
@@ -1826,7 +1817,8 @@ struct xhci_hcd {
|
||||
struct delayed_work cmd_timer;
|
||||
struct completion cmd_ring_stop_completion;
|
||||
struct xhci_command *current_cmd;
|
||||
|
||||
struct xhci_ring *event_ring;
|
||||
struct xhci_erst erst;
|
||||
/* Scratchpad */
|
||||
struct xhci_scratchpad *scratchpad;
|
||||
|
||||
@@ -1922,8 +1914,6 @@ struct xhci_hcd {
|
||||
#define XHCI_RESET_TO_DEFAULT BIT_ULL(44)
|
||||
#define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45)
|
||||
#define XHCI_ZHAOXIN_HOST BIT_ULL(46)
|
||||
#define XHCI_WRITE_64_HI_LO BIT_ULL(47)
|
||||
#define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
|
||||
|
||||
unsigned int num_active_eps;
|
||||
unsigned int limit_active_eps;
|
||||
@@ -2117,6 +2107,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
|
||||
gfp_t flags);
|
||||
void xhci_initialize_ring_info(struct xhci_ring *ring,
|
||||
unsigned int cycle_state);
|
||||
void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
|
||||
void xhci_free_endpoint_ring(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
unsigned int ep_index);
|
||||
|
||||
Reference in New Issue
Block a user