mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-23 07:33:47 +00:00
DM USB: xHCI: change logic of binding libusb to native device
Previous implementation binds libusb (in other words: usbfs) with native device when DM receives the Enable Slot command. But according to xHCI spec 4.6.5, the binding relationship is decided when the Address Device command is received, so this implementation is not consistent with hardware behaviors. And this incompatible could induce following issue. When two or more USB devices are connected at the same time, eg, connecting two devices before Guest OS is booted, the virtual slot id may bind to wrong root hub port. This patch will do the binding when Address Device command is received and related issues will be fixed. 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> Tracked-On: #1366
This commit is contained in:
parent
2d00a99a4c
commit
0d4a88e620
@ -366,6 +366,8 @@ struct pci_xhci_vdev {
|
|||||||
struct pci_xhci_portregs *portregs;
|
struct pci_xhci_portregs *portregs;
|
||||||
struct pci_xhci_dev_emu **devices; /* XHCI[port] = device */
|
struct pci_xhci_dev_emu **devices; /* XHCI[port] = device */
|
||||||
struct pci_xhci_dev_emu **slots; /* slots assigned from 1 */
|
struct pci_xhci_dev_emu **slots; /* slots assigned from 1 */
|
||||||
|
|
||||||
|
bool slot_allocated[XHCI_MAX_SLOTS];
|
||||||
int ndevices;
|
int ndevices;
|
||||||
uint16_t pid;
|
uint16_t pid;
|
||||||
uint16_t vid;
|
uint16_t vid;
|
||||||
@ -1482,85 +1484,39 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct usb_native_devinfo *
|
static struct usb_native_devinfo *
|
||||||
pci_xhci_find_native_devinfo(struct pci_xhci_vdev *xdev)
|
pci_xhci_find_native_devinfo_by_vport(struct pci_xhci_vdev *xdev, uint8_t vport)
|
||||||
{
|
{
|
||||||
int i, j, x, y;
|
int i, j;
|
||||||
int minp = XHCI_MAX_DEVS;
|
|
||||||
int temp;
|
|
||||||
|
|
||||||
assert(xdev);
|
assert(xdev);
|
||||||
|
|
||||||
/* FIXME
|
|
||||||
* Use the device with minimum port number to do the 'Enable Slot'
|
|
||||||
* command. This is ok with Linux, but not 100% compatible with
|
|
||||||
* xHCI spec. Will fix this in future. Need follow xHCI spec to bind
|
|
||||||
* slot to device in address device command.
|
|
||||||
*/
|
|
||||||
x = y = -1;
|
|
||||||
for (i = 0; i < USB_NATIVE_NUM_BUS; ++i)
|
for (i = 0; i < USB_NATIVE_NUM_BUS; ++i)
|
||||||
for (j = 0; j < USB_NATIVE_NUM_PORT; ++j)
|
for (j = 0; j < USB_NATIVE_NUM_PORT; ++j)
|
||||||
if (VPORT_STATE(xdev->port_map_tbl[i][j]) ==
|
if (VPORT_NUM(xdev->port_map_tbl[i][j]) == vport)
|
||||||
VPORT_CONNECTED) {
|
return &xdev->native_dev_info[i][j];
|
||||||
temp = VPORT_NUM(xdev->port_map_tbl[i][j]);
|
return NULL;
|
||||||
if (minp > temp) {
|
|
||||||
x = i;
|
|
||||||
y = j;
|
|
||||||
minp = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (x == -1 || y == -1)
|
|
||||||
return NULL;
|
|
||||||
else
|
|
||||||
return &xdev->native_dev_info[x][y];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
pci_xhci_cmd_enable_slot(struct pci_xhci_vdev *xdev, uint32_t *slot)
|
pci_xhci_cmd_enable_slot(struct pci_xhci_vdev *xdev, uint32_t *slot)
|
||||||
{
|
{
|
||||||
struct pci_xhci_dev_emu *dev;
|
|
||||||
uint32_t cmderr;
|
uint32_t cmderr;
|
||||||
struct usb_native_devinfo *di;
|
int i;
|
||||||
int i, vport;
|
|
||||||
|
|
||||||
cmderr = XHCI_TRB_ERROR_NO_SLOTS;
|
cmderr = XHCI_TRB_ERROR_SUCCESS;
|
||||||
|
for (i = 1; i <= XHCI_MAX_SLOTS; i++)
|
||||||
di = pci_xhci_find_native_devinfo(xdev);
|
if (xdev->slot_allocated[i] == false)
|
||||||
if (!di) {
|
|
||||||
UPRINTF(LWRN, "unexpected Enable Slot commnad\r\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(di->priv_data);
|
|
||||||
dev = pci_xhci_dev_create(xdev, di);
|
|
||||||
if (!dev) {
|
|
||||||
UPRINTF(LFTL, "fail to create device\r\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
vport = VPORT_NUM(xdev->port_map_tbl[di->bus][di->port]);
|
|
||||||
assert(vport > 0);
|
|
||||||
assert(!xdev->devices[vport]);
|
|
||||||
|
|
||||||
xdev->devices[vport] = dev;
|
|
||||||
xdev->ndevices++;
|
|
||||||
|
|
||||||
for (i = 1; i <= XHCI_MAX_SLOTS; i++) {
|
|
||||||
if (XHCI_SLOTDEV_PTR(xdev, i) == NULL) {
|
|
||||||
xdev->slots[i] = dev;
|
|
||||||
*slot = i;
|
|
||||||
dev->dev_slotstate = XHCI_ST_ENABLED;
|
|
||||||
cmderr = XHCI_TRB_ERROR_SUCCESS;
|
|
||||||
dev->hci.hci_address = i;
|
|
||||||
xdev->port_map_tbl[di->bus][di->port] =
|
|
||||||
VPORT_NUM_STATE(VPORT_EMULATED, vport);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
if (i > XHCI_MAX_SLOTS)
|
||||||
|
cmderr = XHCI_TRB_ERROR_NO_SLOTS;
|
||||||
|
else {
|
||||||
|
xdev->slot_allocated[i] = true;
|
||||||
|
*slot = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
UPRINTF(LDBG, "enable slot (error=%d) slot %u for native device "
|
UPRINTF(LDBG, "enable slot (error=%d) return slot %u\r\n",
|
||||||
"%d-%d\r\n", cmderr != XHCI_TRB_ERROR_SUCCESS, *slot,
|
cmderr != XHCI_TRB_ERROR_SUCCESS, *slot);
|
||||||
di->bus, di->port);
|
|
||||||
|
|
||||||
return cmderr;
|
return cmderr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1611,6 +1567,7 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
|
|||||||
|
|
||||||
xdev->devices[i] = NULL;
|
xdev->devices[i] = NULL;
|
||||||
xdev->slots[slot] = NULL;
|
xdev->slots[slot] = NULL;
|
||||||
|
xdev->slot_allocated[slot] = false;
|
||||||
|
|
||||||
di = &udev->info;
|
di = &udev->info;
|
||||||
xdev->port_map_tbl[di->bus][di->port] =
|
xdev->port_map_tbl[di->bus][di->port] =
|
||||||
@ -1688,10 +1645,12 @@ pci_xhci_cmd_address_device(struct pci_xhci_vdev *xdev,
|
|||||||
{
|
{
|
||||||
struct pci_xhci_dev_emu *dev;
|
struct pci_xhci_dev_emu *dev;
|
||||||
struct xhci_input_dev_ctx *input_ctx;
|
struct xhci_input_dev_ctx *input_ctx;
|
||||||
struct xhci_slot_ctx *islot_ctx;
|
struct xhci_slot_ctx *islot_ctx;
|
||||||
struct xhci_dev_ctx *dev_ctx;
|
struct xhci_dev_ctx *dev_ctx;
|
||||||
struct xhci_endp_ctx *ep0_ctx;
|
struct xhci_endp_ctx *ep0_ctx;
|
||||||
uint32_t cmderr;
|
struct usb_native_devinfo *di;
|
||||||
|
uint32_t cmderr;
|
||||||
|
uint8_t rh_port;
|
||||||
|
|
||||||
input_ctx = XHCI_GADDR(xdev, trb->qwTrb0 & ~0xFUL);
|
input_ctx = XHCI_GADDR(xdev, trb->qwTrb0 & ~0xFUL);
|
||||||
islot_ctx = &input_ctx->ctx_slot;
|
islot_ctx = &input_ctx->ctx_slot;
|
||||||
@ -1716,6 +1675,40 @@ pci_xhci_cmd_address_device(struct pci_xhci_vdev *xdev,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (slot <= 0 || slot > XHCI_MAX_SLOTS ||
|
||||||
|
xdev->slot_allocated[slot] == false) {
|
||||||
|
UPRINTF(LDBG, "address device, invalid slot %d\r\n", slot);
|
||||||
|
cmderr = XHCI_TRB_ERROR_SLOT_NOT_ON;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = xdev->slots[slot];
|
||||||
|
if (!dev) {
|
||||||
|
rh_port = XHCI_SCTX_1_RH_PORT_GET(islot_ctx->dwSctx1);
|
||||||
|
|
||||||
|
di = pci_xhci_find_native_devinfo_by_vport(xdev, rh_port);
|
||||||
|
if (di == NULL) {
|
||||||
|
cmderr = XHCI_TRB_ERROR_TRB;
|
||||||
|
UPRINTF(LFTL, "invalid root hub port %d\r\n", rh_port);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
UPRINTF(LDBG, "create virtual device for %d-%d on virtual "
|
||||||
|
"port %d\r\n", di->bus, di->port, rh_port);
|
||||||
|
|
||||||
|
dev = pci_xhci_dev_create(xdev, di);
|
||||||
|
if (!dev) {
|
||||||
|
UPRINTF(LFTL, "fail to create device for %d-%d\r\n",
|
||||||
|
di->bus, di->port);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
xdev->devices[rh_port] = dev;
|
||||||
|
xdev->ndevices++;
|
||||||
|
xdev->slots[slot] = dev;
|
||||||
|
dev->hci.hci_address = slot;
|
||||||
|
}
|
||||||
|
|
||||||
/* assign address to slot */
|
/* assign address to slot */
|
||||||
dev_ctx = pci_xhci_get_dev_ctx(xdev, slot);
|
dev_ctx = pci_xhci_get_dev_ctx(xdev, slot);
|
||||||
if (!dev_ctx) {
|
if (!dev_ctx) {
|
||||||
@ -3349,8 +3342,8 @@ static void
|
|||||||
pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
|
pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
|
||||||
{
|
{
|
||||||
struct pci_xhci_portregs *port;
|
struct pci_xhci_portregs *port;
|
||||||
struct pci_xhci_dev_emu *dev;
|
struct xhci_trb evtrb;
|
||||||
struct xhci_trb evtrb;
|
struct usb_native_devinfo *di;
|
||||||
int speed, error;
|
int speed, error;
|
||||||
|
|
||||||
assert(portn <= XHCI_MAX_DEVS);
|
assert(portn <= XHCI_MAX_DEVS);
|
||||||
@ -3358,26 +3351,29 @@ pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
|
|||||||
UPRINTF(LDBG, "reset port %d\r\n", portn);
|
UPRINTF(LDBG, "reset port %d\r\n", portn);
|
||||||
|
|
||||||
port = XHCI_PORTREG_PTR(xdev, portn);
|
port = XHCI_PORTREG_PTR(xdev, portn);
|
||||||
dev = XHCI_DEVINST_PTR(xdev, portn);
|
di = pci_xhci_find_native_devinfo_by_vport(xdev, portn);
|
||||||
if (dev) {
|
if (!di) {
|
||||||
speed = pci_xhci_convert_speed(dev->dev_ue->ue_usbspeed);
|
UPRINTF(LWRN, "fail to reset port %d\r\n", portn);
|
||||||
port->portsc &= ~(XHCI_PS_PLS_MASK | XHCI_PS_PR | XHCI_PS_PRC);
|
return;
|
||||||
port->portsc |= XHCI_PS_PED | XHCI_PS_SPEED_SET(speed);
|
}
|
||||||
|
|
||||||
if (warm && dev->dev_ue->ue_usbver == 3)
|
speed = pci_xhci_convert_speed(di->speed);
|
||||||
port->portsc |= XHCI_PS_WRC;
|
port->portsc &= ~(XHCI_PS_PLS_MASK | XHCI_PS_PR | XHCI_PS_PRC);
|
||||||
|
port->portsc |= XHCI_PS_PED | XHCI_PS_SPEED_SET(speed);
|
||||||
|
|
||||||
if ((port->portsc & XHCI_PS_PRC) == 0) {
|
if (warm && di->bcd >= 0x300)
|
||||||
port->portsc |= XHCI_PS_PRC;
|
port->portsc |= XHCI_PS_WRC;
|
||||||
|
|
||||||
pci_xhci_set_evtrb(&evtrb, portn,
|
if ((port->portsc & XHCI_PS_PRC) == 0) {
|
||||||
XHCI_TRB_ERROR_SUCCESS,
|
port->portsc |= XHCI_PS_PRC;
|
||||||
XHCI_TRB_EVENT_PORT_STS_CHANGE);
|
|
||||||
error = pci_xhci_insert_event(xdev, &evtrb, 1);
|
pci_xhci_set_evtrb(&evtrb, portn,
|
||||||
if (error != XHCI_TRB_ERROR_SUCCESS)
|
XHCI_TRB_ERROR_SUCCESS,
|
||||||
UPRINTF(LWRN, "reset port insert event "
|
XHCI_TRB_EVENT_PORT_STS_CHANGE);
|
||||||
"failed\n");
|
error = pci_xhci_insert_event(xdev, &evtrb, 1);
|
||||||
}
|
if (error != XHCI_TRB_ERROR_SUCCESS)
|
||||||
|
UPRINTF(LWRN, "reset port insert event "
|
||||||
|
"failed\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user