mirror of
https://github.com/apache/nuttx.git
synced 2026-09-02 15:12:59 +00:00
drivers/usbhost: Stop an xHCI controller only when it is running.
xhci_ctrl_halt() wrote USBCMD zero unconditionally and then waited for HCH. A controller that was never started is already halted, so the wait ran to its full length, and clearing the whole register also dropped INTE and HSEE. Test HCH first, clear only R/S when it is set, bound the wait with XHCI_HALT_TIMEOUT_MS, and report USBCMD and USBSTS on failure. Assisted-by: Claude:claude-opus-5 Signed-off-by: Justin Hammond <justin@dynam.ac>
This commit is contained in:
parent
edb7d03467
commit
c94fbeebcb
1 changed files with 41 additions and 18 deletions
|
|
@ -68,6 +68,12 @@
|
|||
#define XHCI_CMD_MAX (16)
|
||||
#define XHCI_EVENT_MAX (232)
|
||||
#define XHCI_TD_MAX (8)
|
||||
|
||||
/* Milliseconds allowed for the controller to halt. The specification
|
||||
* asks for 16.
|
||||
*/
|
||||
|
||||
#define XHCI_HALT_TIMEOUT_MS (100)
|
||||
#define XHCI_BUFSIZE (512)
|
||||
|
||||
/* Port numbers macros */
|
||||
|
|
@ -1104,9 +1110,12 @@ static int xhci_ctrl_start(FAR struct usbhost_xhci_s *priv)
|
|||
|
||||
xhci_oper_putreg(priv, XHCI_CONFIG, priv->no_slots);
|
||||
|
||||
/* Slot 0 in Device Context is reserved for Scratchpad Buffer Array */
|
||||
/* Slot 0 of the Device Context array points at the Scratchpad Buffer
|
||||
* Array, or is zero when the controller asked for none.
|
||||
*/
|
||||
|
||||
priv->pg_ctx[0] = htole64(up_addrenv_va_to_pa(priv->pg_sb));
|
||||
priv->pg_ctx[0] = priv->pg_sb ?
|
||||
htole64(up_addrenv_va_to_pa(priv->pg_sb)) : 0;
|
||||
|
||||
/* Device Context Base Address Array Pointer */
|
||||
|
||||
|
|
@ -1227,27 +1236,41 @@ static int xhci_ctrl_start(FAR struct usbhost_xhci_s *priv)
|
|||
|
||||
static int xhci_ctrl_halt(FAR struct usbhost_xhci_s *priv)
|
||||
{
|
||||
int ret = -EAGAIN;
|
||||
int i;
|
||||
uint32_t regval;
|
||||
int i;
|
||||
|
||||
/* Halt controller */
|
||||
/* A controller that was never started is already halted and says so.
|
||||
* There is no transition to wait for, so check before waiting.
|
||||
*/
|
||||
|
||||
xhci_oper_putreg(priv, XHCI_USBCMD, 0);
|
||||
|
||||
/* Wait for controller halted */
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
regval = xhci_oper_getreg(priv, XHCI_USBSTS);
|
||||
if ((regval & XHCI_USBSTS_HCH) != 0)
|
||||
{
|
||||
up_mdelay(100);
|
||||
|
||||
if (xhci_oper_getreg(priv, XHCI_USBSTS) & XHCI_USBSTS_HCH)
|
||||
{
|
||||
ret = OK;
|
||||
break;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* Clear Run/Stop and leave the rest of the register alone. Writing the
|
||||
* whole of it zero would clear the interrupt and host system error
|
||||
* enables along with it.
|
||||
*/
|
||||
|
||||
regval = xhci_oper_getreg(priv, XHCI_USBCMD);
|
||||
regval &= ~XHCI_USBCMD_RS;
|
||||
xhci_oper_putreg(priv, XHCI_USBCMD, regval);
|
||||
|
||||
for (i = 0; i < XHCI_HALT_TIMEOUT_MS; i++)
|
||||
{
|
||||
regval = xhci_oper_getreg(priv, XHCI_USBSTS);
|
||||
if ((regval & XHCI_USBSTS_HCH) != 0)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
up_udelay(1000);
|
||||
}
|
||||
|
||||
pcierr("controller will not halt, USBSTS %08" PRIx32 "\n", regval);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue