From d24213db2db2915ed1a91f0608d11c9ceb932284 Mon Sep 17 00:00:00 2001 From: Xiaoguang Wu Date: Wed, 11 Jul 2018 14:43:23 +0800 Subject: [PATCH] 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 Reviewed-by: Liang Yang Acked-by: Yu Wang --- devicemodel/hw/pci/xhci.c | 34 +++++++++++++++++++++++---- devicemodel/hw/platform/usb_pmapper.c | 26 ++++++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c index 56ae8d08f..9df331b53 100644 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -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; diff --git a/devicemodel/hw/platform/usb_pmapper.c b/devicemodel/hw/platform/usb_pmapper.c index b9416e3f4..153903448 100644 --- a/devicemodel/hw/platform/usb_pmapper.c +++ b/devicemodel/hw/platform/usb_pmapper.c @@ -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: