DM USB: xHCI: fix xhci speed emulation logic

The xHCI speed emulation is not right, which will cause failure
during enumeration of certain USB device. This patch is used to
fix it.

Change-Id: I2d996298983882ed6921a75a10dec9e8684a393e
Tracked-On:
Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com>
Reviewed-by: Liang Yang <liang3.yang@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Xiaoguang Wu 2018-07-11 14:43:23 +08:00 committed by lijinxia
parent d6cc701c89
commit d24213db2d
2 changed files with 55 additions and 5 deletions

View File

@ -757,6 +757,31 @@ pci_xhci_is_valid_portnum(int n)
return n > 0 && n <= XHCI_MAX_DEVS;
}
static int
pci_xhci_convert_speed(int lspeed)
{
/* according to xhci spec, zero means undefined speed */
int speed = 0;
switch (lspeed) {
case USB_SPEED_LOW:
speed = 0x2;
break;
case USB_SPEED_FULL:
speed = 0x1;
break;
case USB_SPEED_HIGH:
speed = 0x3;
break;
case USB_SPEED_SUPER:
speed = 0x4;
break;
default:
UPRINTF(LFTL, "unkown speed %08x\r\n", lspeed);
}
return speed;
}
static int
pci_xhci_port_chg(struct pci_xhci_vdev *xdev, int port, int conn)
{
@ -779,12 +804,11 @@ pci_xhci_port_chg(struct pci_xhci_vdev *xdev, int port, int conn)
reg->portsc |= (XHCI_PS_CSC |
XHCI_PS_PLS_SET(UPS_PORT_LS_RX_DET));
} else {
speed = dev->dev_ue->ue_usbspeed;
speed = pci_xhci_convert_speed(dev->dev_ue->ue_usbspeed);
reg->portsc = XHCI_PS_CCS | XHCI_PS_PP | XHCI_PS_CSC;
reg->portsc |= XHCI_PS_SPEED_SET(speed);
}
/* make an event for the guest OS */
pci_xhci_set_evtrb(&evtrb,
port,
@ -3150,7 +3174,7 @@ pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
struct pci_xhci_portregs *port;
struct pci_xhci_dev_emu *dev;
struct xhci_trb evtrb;
int error;
int speed, error;
assert(portn <= XHCI_MAX_DEVS);
@ -3159,9 +3183,9 @@ pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
port = XHCI_PORTREG_PTR(xdev, portn);
dev = XHCI_DEVINST_PTR(xdev, portn);
if (dev) {
speed = pci_xhci_convert_speed(dev->dev_ue->ue_usbspeed);
port->portsc &= ~(XHCI_PS_PLS_MASK | XHCI_PS_PR | XHCI_PS_PRC);
port->portsc |= XHCI_PS_PED |
XHCI_PS_SPEED_SET(dev->dev_ue->ue_usbspeed);
port->portsc |= XHCI_PS_PED | XHCI_PS_SPEED_SET(speed);
if (warm && dev->dev_ue->ue_usbver == 3)
port->portsc |= XHCI_PS_WRC;

View File

@ -21,6 +21,31 @@ static struct usb_dev_sys_ctx_info g_ctx;
static inline uint8_t usb_dev_get_ep_type(struct usb_dev *udev, int pid,
int epnum);
static int
libusb_speed_to_usb_speed(int libusb_speed)
{
int speed = LIBUSB_SPEED_UNKNOWN;
switch (libusb_speed) {
case LIBUSB_SPEED_LOW:
speed = USB_SPEED_LOW;
break;
case LIBUSB_SPEED_FULL:
speed = USB_SPEED_FULL;
break;
case LIBUSB_SPEED_HIGH:
speed = USB_SPEED_HIGH;
break;
case LIBUSB_SPEED_SUPER:
speed = USB_SPEED_SUPER;
break;
default:
UPRINTF(LWRN, "%s unexpect speed %d\r\n", __func__,
libusb_speed);
}
return speed;
}
static void
usb_dev_comp_req(struct libusb_transfer *libusb_xfer)
{
@ -852,6 +877,7 @@ usb_dev_info(void *pdata, int type, void *value, int size)
break;
case USB_INFO_SPEED:
sz = sizeof(udev->speed);
udev->speed = libusb_speed_to_usb_speed(udev->speed);
pv = &udev->speed;
break;
case USB_INFO_BUS: