DM: xHCI: Implement the USB PLS Machine flow spec.

From the Figure 11-10. Downstream Facing Hub Port State Machine the
device connect status should be disabled and the PLS should be polling
for USB2.0, when the device be connected, then the xHCD send the port
reset, for acrn we use libusb_reset_device to emulate the bus reset
action.

Tracked-On: #5795
Signed-off-by: Liu Long <long.liu@intel.com>
Acked-by: Wang, Yu1 <yu1.wang@intel.com>
This commit is contained in:
Liu Long 2021-02-05 14:45:12 +08:00 committed by wenlingz
parent e3a8b09e62
commit cba7caf71f
2 changed files with 44 additions and 18 deletions

View File

@ -1135,6 +1135,11 @@ pci_xhci_change_port(struct pci_xhci_vdev *xdev, int port, int usb_speed,
speed = pci_xhci_convert_speed(usb_speed);
reg->portsc = XHCI_PS_CCS | XHCI_PS_PP | XHCI_PS_CSC;
reg->portsc |= XHCI_PS_SPEED_SET(speed);
if (speed == USB_SPEED_SUPER) {
reg->portsc |= XHCI_PS_PED;
reg->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_U0);
} else
reg->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_POLL);
}
if (!need_intr)
@ -1831,7 +1836,7 @@ pci_xhci_insert_event(struct pci_xhci_vdev *xdev,
evts = XHCI_GADDR(xdev, erst->qwRingSegBase);
if (!evts) {
UPRINTF(LFTL, "Invalid gpa 0x%x in insert event!\r\n",
UPRINTF(LFTL, "Invalid gpa 0x%lx in insert event!\r\n",
erst->qwRingSegBase);
return -EINVAL;
}
@ -2032,7 +2037,7 @@ pci_xhci_cmd_address_device(struct pci_xhci_vdev *xdev,
input_ctx = XHCI_GADDR(xdev, trb->qwTrb0 & ~0xFUL);
if (!input_ctx) {
UPRINTF(LFTL, "Invalid gpa 0x%x in address device!\r\n",
UPRINTF(LFTL, "Invalid gpa 0x%lx in address device!\r\n",
trb->qwTrb0 & ~0xFUL);
cmderr = XHCI_TRB_ERROR_TRB;
goto done;
@ -2227,7 +2232,7 @@ pci_xhci_cmd_config_ep(struct pci_xhci_vdev *xdev,
input_ctx = XHCI_GADDR(xdev, trb->qwTrb0 & ~0xFUL);
if (!input_ctx) {
UPRINTF(LFTL, "Invalid gpa 0x%x in configure endpoint!\r\n",
UPRINTF(LFTL, "Invalid gpa 0x%lx in configure endpoint!\r\n",
trb->qwTrb0 & ~0xFUL);
cmderr = XHCI_TRB_ERROR_TRB;
goto done;
@ -2418,7 +2423,7 @@ pci_xhci_find_stream(struct pci_xhci_vdev *xdev,
sctx = XHCI_GADDR(xdev, ep->qwEpCtx2 & ~0xFUL) + streamid;
if (!sctx) {
UPRINTF(LFTL, "Invalid gpa 0x%x in find stream!\r\n",
UPRINTF(LFTL, "Invalid gpa 0x%lx in find stream!\r\n",
ep->qwEpCtx2 & ~0xFUL);
return XHCI_TRB_ERROR_TRB;
}
@ -2525,7 +2530,7 @@ pci_xhci_cmd_eval_ctx(struct pci_xhci_vdev *xdev,
input_ctx = XHCI_GADDR(xdev, trb->qwTrb0 & ~0xFUL);
if (!input_ctx) {
UPRINTF(LFTL, "Invalid gpa 0x%x in eval context!\r\n",
UPRINTF(LFTL, "Invalid gpa 0x%lx in eval context!\r\n",
trb->qwTrb0 & ~0xFUL);
cmderr = XHCI_TRB_ERROR_TRB;
goto done;
@ -2848,7 +2853,7 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
evtrb.qwTrb0 = hcb->trb_addr;
trb = XHCI_GADDR(xdev, evtrb.qwTrb0);
if (!trb) {
UPRINTF(LFTL, "Invalid gpa 0x%x when get the trb!\r\n",
UPRINTF(LFTL, "Invalid gpa 0x%lx when get the trb!\r\n",
evtrb.qwTrb0);
continue;
}
@ -3345,7 +3350,7 @@ pci_xhci_device_doorbell(struct pci_xhci_vdev *xdev,
ccs = sctx_tr->ccs;
trb = XHCI_GADDR(xdev, sctx_tr->ringaddr & ~0xFUL);
if (!trb) {
UPRINTF(LDBG, "Invalid gpa 0x%x in write device doorbell!\r\n",
UPRINTF(LDBG, "Invalid gpa 0x%lx in write device doorbell!\r\n",
sctx_tr->ringaddr & ~0xFUL);
return;
}
@ -3455,7 +3460,7 @@ pci_xhci_rtsregs_write(struct pci_xhci_vdev *xdev,
rts->erstba_p->qwRingSegBase,
rts->erstba_p->dwRingSegSize);
else
UPRINTF(LFTL, "Invalid gpa 0x%x in write runtime register!\r\n",
UPRINTF(LFTL, "Invalid gpa 0x%lx in write runtime register!\r\n",
xdev->rtsregs.intrreg.erstba & ~0x3FUL);
break;
@ -3591,7 +3596,7 @@ pci_xhci_hostop_write(struct pci_xhci_vdev *xdev,
UPRINTF(LDBG, "opregs dcbaap = 0x%lx (vaddr 0x%lx)\r\n",
xdev->opregs.dcbaap, (uint64_t)xdev->opregs.dcbaa_p);
else
UPRINTF(LFTL, "Invalid gpa 0x%x when get XHCI_DCBAAP_HI\n",
UPRINTF(LFTL, "Invalid gpa 0x%lx when get XHCI_DCBAAP_HI\n",
xdev->opregs.dcbaap & ~0x3FUL);
break;
@ -3903,8 +3908,10 @@ pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
struct pci_xhci_portregs *port;
struct xhci_trb evtrb;
struct usb_native_devinfo *di;
struct pci_xhci_dev_emu *dev;
int speed;
int index;
int rc = 0;
UPRINTF(LINF, "reset port %d\r\n", portn);
@ -3915,11 +3922,24 @@ pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
return;
}
di = &xdev->native_ports[index].info;
dev = xdev->devices[portn];
if (dev && dev->dev_ue->ue_reset != NULL)
rc = dev->dev_ue->ue_reset(dev->dev_instance);
speed = pci_xhci_convert_speed(di->speed);
port->portsc &= ~(XHCI_PS_PLS_MASK | XHCI_PS_PR | XHCI_PS_PRC);
port->portsc |= XHCI_PS_PED | XHCI_PS_SPEED_SET(speed);
port->portsc &= ~(XHCI_PS_PR | XHCI_PS_PLS_MASK);
/*
* From xHCI spec 4.19.5 USB2 protocol ports never fail the bus
* reset seqence.
*/
if (rc != 0 && di->bcd >= 0x300) {
port->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_RX_DET)
| XHCI_PS_SPEED_SET(USB_SPEED_VARIABLE);
port->portsc &= ~XHCI_PS_CCS;
} else {
speed = pci_xhci_convert_speed(di->speed);
port->portsc |= XHCI_PS_PED | XHCI_PS_SPEED_SET(speed)
| XHCI_PS_PLS_SET(UPS_PORT_LS_U0);
}
if (warm && di->bcd >= 0x300)
port->portsc |= XHCI_PS_WRC;
@ -3927,10 +3947,10 @@ pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
port->portsc |= XHCI_PS_PRC;
pci_xhci_set_evtrb(&evtrb, portn,
XHCI_TRB_ERROR_SUCCESS,
XHCI_TRB_EVENT_PORT_STS_CHANGE);
if (pci_xhci_insert_event(xdev, &evtrb, 1) != 0)
UPRINTF(LFTL, "Failed to inject reset port event!\n");
XHCI_TRB_ERROR_SUCCESS,
XHCI_TRB_EVENT_PORT_STS_CHANGE);
if (pci_xhci_insert_event(xdev, &evtrb, 1) != 0)
UPRINTF(LFTL, "Failed to inject reset port event!\n");
}
}

View File

@ -730,6 +730,7 @@ int
usb_dev_reset(void *pdata)
{
struct usb_dev *udev;
int rc = 0;
udev = pdata;
@ -737,7 +738,12 @@ usb_dev_reset(void *pdata)
libusb_reset_device(udev->handle);
usb_dev_reset_ep(udev);
usb_dev_update_ep(udev);
return 0;
rc = libusb_reset_device(udev->handle);
if (!rc) {
usb_dev_reset_ep(udev);
usb_dev_update_ep(udev);
}
return rc;
}
int