xhci: dbc: detect and recover hung DbC during enumeraton

Add a timeout between the detection of the debug host connection and
the DbC Run transition to ‘1’. Toggle the DCE bit to re-enable DbC in
order to retry the debug device enumeration process if the DbC run
transition takes too long.

Set the timeout to 2 seconds

See xhci specification section 7.6.4.1 "Debug Capability Initialization"

Also detect cable disconnect during enable and connected state.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://patch.msgid.link/20260603091132.1110849-12-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Mathias Nyman 2026-06-03 12:11:28 +03:00 committed by Greg Kroah-Hartman
parent 724eab31dd
commit a3d34e5525
2 changed files with 28 additions and 1 deletions

View File

@ -901,23 +901,49 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
return EVT_ERR;
case DS_ENABLED:
portsc = readl(&dbc->regs->portsc);
ctrl = readl(&dbc->regs->control);
if (portsc & DBC_PORTSC_CONN_STATUS) {
xhci_dbc_set_state(dbc, DS_CONNECTED);
dev_info(dbc->dev, "DbC connected\n");
} else if (!(ctrl & DBC_CTRL_DBC_ENABLE)) {
dev_err(dbc->dev, "unexpected DbC disable, xHC reset?\n");
}
return EVT_DONE;
case DS_CONNECTED:
ctrl = readl(&dbc->regs->control);
portsc = readl(&dbc->regs->portsc);
if (ctrl & DBC_CTRL_DBC_RUN) {
xhci_dbc_set_state(dbc, DS_CONFIGURED);
dev_info(dbc->dev, "DbC configured\n");
portsc = readl(&dbc->regs->portsc);
writel(portsc, &dbc->regs->portsc);
ret = EVT_GSER;
break;
}
/* Connection lost */
if (!(portsc & DBC_PORTSC_CONN_STATUS)) {
/* covers DCE == 0 as it also sets CONN_STATUS to 0 */
dev_warn(dbc->dev, "DbC connection lost mid enumeration\n");
xhci_dbc_set_state(dbc, DS_ENABLED);
return EVT_DONE;
}
/* Enumeration timeout */
if (time_is_before_jiffies(dbc->state_timestamp +
msecs_to_jiffies(DBC_ENUMERATION_TIMEOUT))) {
dev_err(dbc->dev, "DbC enumeration timeout, re-enabling DbC\n");
dev_dbg(dbc->dev, "dcctrl %x, dcportsc %x\n", ctrl, portsc);
/* Toggle DCE to retry enumeration */
ret = xhci_dbc_enable_dce(dbc, false);
udelay(100);
ret = xhci_dbc_enable_dce(dbc, true);
xhci_dbc_set_state(dbc, DS_ENABLED);
}
return EVT_DONE;
case DS_CONFIGURED:
/* Handle cable unplug event: */

View File

@ -113,6 +113,7 @@ struct dbc_ep {
#define DBC_POLL_INTERVAL_DEFAULT 64 /* milliseconds */
#define DBC_POLL_INTERVAL_MAX 5000 /* milliseconds */
#define DBC_XFER_INACTIVITY_TIMEOUT 10 /* milliseconds */
#define DBC_ENUMERATION_TIMEOUT 2000 /* milliseconds */
/*
* Private structure for DbC hardware state:
*/