Skip to content

Commit ed968a1

Browse files
matnymangregkh
authored andcommitted
xhci: dbc: Fix STALL transfer event handling
commit 9044ad5 upstream. Don't flush all pending DbC data requests when an endpoint halts. An endpoint may halt and xHC DbC triggers a STALL error event if there's an issue with a bulk data transfer. The transfer should restart once xHC DbC receives a ClearFeature(ENDPOINT_HALT) request from the host. Once xHC DbC restarts it will start from the TRB pointed to by dequeue field in the endpoint context, which might be the same TRB we got the STALL event for. Turn the TRB to a no-op in this case to make sure xHC DbC doesn't reuse and tries to retransmit this same TRB after we already handled it, and gave its corresponding data request back. Other STALL events might be completely bogus. Lukasz Bartosik discovered that xHC DbC might issue spurious STALL events if hosts sends a ClearFeature(ENDPOINT_HALT) request to non-halted endpoints even without any active bulk transfers. Assume STALL event is spurious if it reports 0 bytes transferred, and the endpoint stopped on the STALLED TRB. Don't give back the data request corresponding to the TRB in this case. The halted status is per endpoint. Track it with a per endpoint flag instead of the driver invented DbC wide DS_STALLED state. DbC remains in DbC-Configured state even if endpoints halt. There is no Stalled state in the DbC Port state Machine (xhci section 7.6.6) Reported-by: Łukasz Bartosik <[email protected]> Closes: https://lore.kernel.org/linux-usb/[email protected]/ Tested-by: Łukasz Bartosik <[email protected]> Signed-off-by: Mathias Nyman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 1af5e8b commit ed968a1

File tree

2 files changed

+83
-54
lines changed

2 files changed

+83
-54
lines changed

drivers/usb/host/xhci-dbgcap.c

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,18 @@ static void xhci_dbc_giveback(struct dbc_request *req, int status)
158158
spin_lock(&dbc->lock);
159159
}
160160

161-
static void xhci_dbc_flush_single_request(struct dbc_request *req)
161+
static void trb_to_noop(union xhci_trb *trb)
162162
{
163-
union xhci_trb *trb = req->trb;
164-
165163
trb->generic.field[0] = 0;
166164
trb->generic.field[1] = 0;
167165
trb->generic.field[2] = 0;
168166
trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
169167
trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(TRB_TR_NOOP));
168+
}
170169

170+
static void xhci_dbc_flush_single_request(struct dbc_request *req)
171+
{
172+
trb_to_noop(req->trb);
171173
xhci_dbc_giveback(req, -ESHUTDOWN);
172174
}
173175

@@ -637,7 +639,6 @@ static void xhci_dbc_stop(struct xhci_dbc *dbc)
637639
case DS_DISABLED:
638640
return;
639641
case DS_CONFIGURED:
640-
case DS_STALLED:
641642
if (dbc->driver->disconnect)
642643
dbc->driver->disconnect(dbc);
643644
break;
@@ -657,6 +658,23 @@ static void xhci_dbc_stop(struct xhci_dbc *dbc)
657658
}
658659
}
659660

661+
static void
662+
handle_ep_halt_changes(struct xhci_dbc *dbc, struct dbc_ep *dep, bool halted)
663+
{
664+
if (halted) {
665+
dev_info(dbc->dev, "DbC Endpoint halted\n");
666+
dep->halted = 1;
667+
668+
} else if (dep->halted) {
669+
dev_info(dbc->dev, "DbC Endpoint halt cleared\n");
670+
dep->halted = 0;
671+
672+
if (!list_empty(&dep->list_pending))
673+
writel(DBC_DOOR_BELL_TARGET(dep->direction),
674+
&dbc->regs->doorbell);
675+
}
676+
}
677+
660678
static void
661679
dbc_handle_port_status(struct xhci_dbc *dbc, union xhci_trb *event)
662680
{
@@ -685,6 +703,7 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event)
685703
struct xhci_ring *ring;
686704
int ep_id;
687705
int status;
706+
struct xhci_ep_ctx *ep_ctx;
688707
u32 comp_code;
689708
size_t remain_length;
690709
struct dbc_request *req = NULL, *r;
@@ -694,8 +713,30 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event)
694713
ep_id = TRB_TO_EP_ID(le32_to_cpu(event->generic.field[3]));
695714
dep = (ep_id == EPID_OUT) ?
696715
get_out_ep(dbc) : get_in_ep(dbc);
716+
ep_ctx = (ep_id == EPID_OUT) ?
717+
dbc_bulkout_ctx(dbc) : dbc_bulkin_ctx(dbc);
697718
ring = dep->ring;
698719

720+
/* Match the pending request: */
721+
list_for_each_entry(r, &dep->list_pending, list_pending) {
722+
if (r->trb_dma == event->trans_event.buffer) {
723+
req = r;
724+
break;
725+
}
726+
if (r->status == -COMP_STALL_ERROR) {
727+
dev_warn(dbc->dev, "Give back stale stalled req\n");
728+
ring->num_trbs_free++;
729+
xhci_dbc_giveback(r, 0);
730+
}
731+
}
732+
733+
if (!req) {
734+
dev_warn(dbc->dev, "no matched request\n");
735+
return;
736+
}
737+
738+
trace_xhci_dbc_handle_transfer(ring, &req->trb->generic);
739+
699740
switch (comp_code) {
700741
case COMP_SUCCESS:
701742
remain_length = 0;
@@ -706,31 +747,49 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event)
706747
case COMP_TRB_ERROR:
707748
case COMP_BABBLE_DETECTED_ERROR:
708749
case COMP_USB_TRANSACTION_ERROR:
709-
case COMP_STALL_ERROR:
710750
dev_warn(dbc->dev, "tx error %d detected\n", comp_code);
711751
status = -comp_code;
712752
break;
753+
case COMP_STALL_ERROR:
754+
dev_warn(dbc->dev, "Stall error at bulk TRB %llx, remaining %zu, ep deq %llx\n",
755+
event->trans_event.buffer, remain_length, ep_ctx->deq);
756+
status = 0;
757+
dep->halted = 1;
758+
759+
/*
760+
* xHC DbC may trigger a STALL bulk xfer event when host sends a
761+
* ClearFeature(ENDPOINT_HALT) request even if there wasn't an
762+
* active bulk transfer.
763+
*
764+
* Don't give back this transfer request as hardware will later
765+
* start processing TRBs starting from this 'STALLED' TRB,
766+
* causing TRBs and requests to be out of sync.
767+
*
768+
* If STALL event shows some bytes were transferred then assume
769+
* it's an actual transfer issue and give back the request.
770+
* In this case mark the TRB as No-Op to avoid hw from using the
771+
* TRB again.
772+
*/
773+
774+
if ((ep_ctx->deq & ~TRB_CYCLE) == event->trans_event.buffer) {
775+
dev_dbg(dbc->dev, "Ep stopped on Stalled TRB\n");
776+
if (remain_length == req->length) {
777+
dev_dbg(dbc->dev, "Spurious stall event, keep req\n");
778+
req->status = -COMP_STALL_ERROR;
779+
req->actual = 0;
780+
return;
781+
}
782+
dev_dbg(dbc->dev, "Give back stalled req, but turn TRB to No-op\n");
783+
trb_to_noop(req->trb);
784+
}
785+
break;
786+
713787
default:
714788
dev_err(dbc->dev, "unknown tx error %d\n", comp_code);
715789
status = -comp_code;
716790
break;
717791
}
718792

719-
/* Match the pending request: */
720-
list_for_each_entry(r, &dep->list_pending, list_pending) {
721-
if (r->trb_dma == event->trans_event.buffer) {
722-
req = r;
723-
break;
724-
}
725-
}
726-
727-
if (!req) {
728-
dev_warn(dbc->dev, "no matched request\n");
729-
return;
730-
}
731-
732-
trace_xhci_dbc_handle_transfer(ring, &req->trb->generic);
733-
734793
ring->num_trbs_free++;
735794
req->actual = req->length - remain_length;
736795
xhci_dbc_giveback(req, status);
@@ -750,7 +809,6 @@ static void inc_evt_deq(struct xhci_ring *ring)
750809
static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
751810
{
752811
dma_addr_t deq;
753-
struct dbc_ep *dep;
754812
union xhci_trb *evt;
755813
u32 ctrl, portsc;
756814
bool update_erdp = false;
@@ -802,43 +860,17 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
802860
return EVT_DISC;
803861
}
804862

805-
/* Handle endpoint stall event: */
863+
/* Check and handle changes in endpoint halt status */
806864
ctrl = readl(&dbc->regs->control);
807-
if ((ctrl & DBC_CTRL_HALT_IN_TR) ||
808-
(ctrl & DBC_CTRL_HALT_OUT_TR)) {
809-
dev_info(dbc->dev, "DbC Endpoint stall\n");
810-
dbc->state = DS_STALLED;
811-
812-
if (ctrl & DBC_CTRL_HALT_IN_TR) {
813-
dep = get_in_ep(dbc);
814-
xhci_dbc_flush_endpoint_requests(dep);
815-
}
816-
817-
if (ctrl & DBC_CTRL_HALT_OUT_TR) {
818-
dep = get_out_ep(dbc);
819-
xhci_dbc_flush_endpoint_requests(dep);
820-
}
821-
822-
return EVT_DONE;
823-
}
865+
handle_ep_halt_changes(dbc, get_in_ep(dbc), ctrl & DBC_CTRL_HALT_IN_TR);
866+
handle_ep_halt_changes(dbc, get_out_ep(dbc), ctrl & DBC_CTRL_HALT_OUT_TR);
824867

825868
/* Clear DbC run change bit: */
826869
if (ctrl & DBC_CTRL_DBC_RUN_CHANGE) {
827870
writel(ctrl, &dbc->regs->control);
828871
ctrl = readl(&dbc->regs->control);
829872
}
830-
831873
break;
832-
case DS_STALLED:
833-
ctrl = readl(&dbc->regs->control);
834-
if (!(ctrl & DBC_CTRL_HALT_IN_TR) &&
835-
!(ctrl & DBC_CTRL_HALT_OUT_TR) &&
836-
(ctrl & DBC_CTRL_DBC_RUN)) {
837-
dbc->state = DS_CONFIGURED;
838-
break;
839-
}
840-
841-
return EVT_DONE;
842874
default:
843875
dev_err(dbc->dev, "Unknown DbC state %d\n", dbc->state);
844876
break;
@@ -941,9 +973,6 @@ static ssize_t dbc_show(struct device *dev,
941973
case DS_CONFIGURED:
942974
p = "configured";
943975
break;
944-
case DS_STALLED:
945-
p = "stalled";
946-
break;
947976
default:
948977
p = "unknown";
949978
}

drivers/usb/host/xhci-dbgcap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ enum dbc_state {
8181
DS_ENABLED,
8282
DS_CONNECTED,
8383
DS_CONFIGURED,
84-
DS_STALLED,
8584
};
8685

8786
struct dbc_ep {
8887
struct xhci_dbc *dbc;
8988
struct list_head list_pending;
9089
struct xhci_ring *ring;
9190
unsigned int direction:1;
91+
unsigned int halted:1;
9292
};
9393

9494
#define DBC_QUEUE_SIZE 16

0 commit comments

Comments
 (0)