mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-23 05:57:33 +00:00
DM USB: xHCI: refine the emulation of Stop Endpoint Command
Old implementation does nothing when Stop Endpoint cmd is received, it is not right. The new implementation will cancel all the libusb requests in processing. Tracked-On: #3054 Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
parent
1be719c630
commit
5a9627ced8
@ -201,6 +201,7 @@ struct pci_xhci_dev_ep {
|
||||
#define ep_sctx_trbs _ep_trb_rings._epu_sctx_trbs
|
||||
|
||||
struct usb_data_xfer *ep_xfer; /* transfer chain */
|
||||
pthread_mutex_t mtx;
|
||||
};
|
||||
|
||||
/* device context base address array: maps slot->device context */
|
||||
@ -958,6 +959,42 @@ pci_xhci_usb_dev_intr_cb(void *hci_data, void *udev_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pci_xhci_usb_dev_lock_ep_cb(void *hci_data, void *udev_data)
|
||||
{
|
||||
struct pci_xhci_dev_emu *edev;
|
||||
struct pci_xhci_dev_ep *ep;
|
||||
int epid;
|
||||
|
||||
edev = hci_data;
|
||||
epid = *((int *)udev_data);
|
||||
|
||||
if (edev && edev->xdev && epid > 0 && epid < 32) {
|
||||
ep = &edev->eps[epid];
|
||||
pthread_mutex_lock(&ep->mtx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pci_xhci_usb_dev_unlock_ep_cb(void *hci_data, void *udev_data)
|
||||
{
|
||||
struct pci_xhci_dev_emu *edev;
|
||||
struct pci_xhci_dev_ep *ep;
|
||||
int epid;
|
||||
|
||||
edev = hci_data;
|
||||
epid = *((int *)udev_data);
|
||||
|
||||
if (edev && edev->xdev && epid > 0 && epid < 32) {
|
||||
ep = &edev->eps[epid];
|
||||
pthread_mutex_unlock(&ep->mtx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_xhci_dev_emu*
|
||||
pci_xhci_dev_create(struct pci_xhci_vdev *xdev, void *dev_data)
|
||||
{
|
||||
@ -1473,7 +1510,7 @@ pci_xhci_get_dev_ctx(struct pci_xhci_vdev *xdev, uint32_t slot)
|
||||
devctx_addr = xdev->opregs.dcbaa_p->dcba[slot];
|
||||
|
||||
if (devctx_addr == 0) {
|
||||
UPRINTF(LDBG, "get_dev_ctx devctx_addr == 0\r\n");
|
||||
UPRINTF(LDBG, "get_dev_ctx devctx_addr == 0 slot %d\r\n", slot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1536,15 +1573,35 @@ pci_xhci_deassert_interrupt(struct pci_xhci_vdev *xdev)
|
||||
static int
|
||||
pci_xhci_init_ep(struct pci_xhci_dev_emu *dev, int epid)
|
||||
{
|
||||
struct xhci_dev_ctx *dev_ctx;
|
||||
struct pci_xhci_dev_ep *devep;
|
||||
struct xhci_endp_ctx *ep_ctx;
|
||||
uint32_t pstreams;
|
||||
int i;
|
||||
struct xhci_dev_ctx *dev_ctx;
|
||||
struct pci_xhci_dev_ep *devep;
|
||||
struct xhci_endp_ctx *ep_ctx;
|
||||
pthread_mutexattr_t attr;
|
||||
uint32_t pstreams;
|
||||
int i, rc;
|
||||
|
||||
dev_ctx = dev->dev_ctx;
|
||||
ep_ctx = &dev_ctx->ctx_ep[epid];
|
||||
devep = &dev->eps[epid];
|
||||
|
||||
rc = pthread_mutexattr_init(&attr);
|
||||
if (rc) {
|
||||
UPRINTF(LFTL, "%s: mutexattr init failed %d\r\n", __func__, rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
if (rc) {
|
||||
UPRINTF(LFTL, "%s: mutexattr set failed %d\r\n", __func__, rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = pthread_mutex_init(&devep->mtx, &attr);
|
||||
if (rc) {
|
||||
UPRINTF(LFTL, "%s: mutexlock init failed %d\r\n", __func__, rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pstreams = XHCI_EPCTX_0_MAXP_STREAMS_GET(ep_ctx->dwEpCtx0);
|
||||
if (pstreams > 0) {
|
||||
UPRINTF(LDBG, "init_ep %d with pstreams %d\r\n",
|
||||
@ -1572,16 +1629,20 @@ pci_xhci_init_ep(struct pci_xhci_dev_emu *dev, int epid)
|
||||
}
|
||||
|
||||
if (devep->ep_xfer == NULL) {
|
||||
devep->ep_xfer = malloc(sizeof(struct usb_data_xfer));
|
||||
devep->ep_xfer = calloc(1, sizeof(struct usb_data_xfer));
|
||||
if (devep->ep_xfer) {
|
||||
USB_DATA_XFER_INIT(devep->ep_xfer);
|
||||
devep->ep_xfer->dev = (void *)dev;
|
||||
devep->ep_xfer->epid = epid;
|
||||
devep->ep_xfer->magic = USB_DROPPED_XFER_MAGIC;
|
||||
} else
|
||||
return -1;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
pthread_mutex_destroy(&devep->mtx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1592,12 +1653,13 @@ pci_xhci_disable_ep(struct pci_xhci_dev_emu *dev, int epid)
|
||||
struct xhci_endp_ctx *ep_ctx;
|
||||
|
||||
UPRINTF(LDBG, "pci_xhci disable_ep %d\r\n", epid);
|
||||
|
||||
dev_ctx = dev->dev_ctx;
|
||||
ep_ctx = &dev_ctx->ctx_ep[epid];
|
||||
ep_ctx->dwEpCtx0 = (ep_ctx->dwEpCtx0 & ~0x7) | XHCI_ST_EPCTX_DISABLED;
|
||||
|
||||
devep = &dev->eps[epid];
|
||||
pthread_mutex_lock(&devep->mtx);
|
||||
|
||||
if (XHCI_EPCTX_0_MAXP_STREAMS_GET(ep_ctx->dwEpCtx0) > 0 &&
|
||||
devep->ep_sctx_trbs != NULL)
|
||||
free(devep->ep_sctx_trbs);
|
||||
@ -1608,7 +1670,8 @@ pci_xhci_disable_ep(struct pci_xhci_dev_emu *dev, int epid)
|
||||
devep->ep_xfer = NULL;
|
||||
}
|
||||
|
||||
memset(devep, 0, sizeof(struct pci_xhci_dev_ep));
|
||||
pthread_mutex_unlock(&devep->mtx);
|
||||
pthread_mutex_destroy(&devep->mtx);
|
||||
}
|
||||
|
||||
/* reset device at slot and data structures related to it */
|
||||
@ -2143,11 +2206,14 @@ pci_xhci_cmd_reset_ep(struct pci_xhci_vdev *xdev,
|
||||
struct xhci_trb *trb)
|
||||
{
|
||||
struct pci_xhci_dev_emu *dev;
|
||||
struct pci_xhci_dev_ep *devep;
|
||||
struct pci_xhci_dev_ep *devep;
|
||||
struct xhci_dev_ctx *dev_ctx;
|
||||
struct xhci_endp_ctx *ep_ctx;
|
||||
uint32_t cmderr, epid;
|
||||
uint32_t type;
|
||||
struct usb_data_xfer *xfer;
|
||||
struct usb_dev_req *r;
|
||||
uint32_t cmderr, epid;
|
||||
uint32_t type;
|
||||
int i;
|
||||
|
||||
epid = XHCI_TRB_3_EP_GET(trb->dwTrb3);
|
||||
|
||||
@ -2182,15 +2248,20 @@ pci_xhci_cmd_reset_ep(struct pci_xhci_vdev *xdev,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* FIXME: Currently nothing to do when Stop Endpoint Command is
|
||||
* received. Will refine it strictly according to xHCI spec.
|
||||
*/
|
||||
if (type == XHCI_TRB_TYPE_STOP_EP)
|
||||
goto done;
|
||||
|
||||
devep = &dev->eps[epid];
|
||||
if (devep->ep_xfer != NULL)
|
||||
USB_DATA_XFER_RESET(devep->ep_xfer);
|
||||
pthread_mutex_lock(&devep->mtx);
|
||||
|
||||
xfer = devep->ep_xfer;
|
||||
for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) {
|
||||
r = xfer->requests[i];
|
||||
if (r && r->trn)
|
||||
/* let usb_dev_comp_req to free the memory */
|
||||
libusb_cancel_transfer(r->trn);
|
||||
}
|
||||
memset(xfer, 0, sizeof(*xfer));
|
||||
|
||||
if (devep->ep_xfer)
|
||||
memset(devep->ep_xfer, 0, sizeof(*devep->ep_xfer));
|
||||
|
||||
ep_ctx->dwEpCtx0 = (ep_ctx->dwEpCtx0 & ~0x7) | XHCI_ST_EPCTX_STOPPED;
|
||||
|
||||
@ -2200,6 +2271,7 @@ pci_xhci_cmd_reset_ep(struct pci_xhci_vdev *xdev,
|
||||
UPRINTF(LDBG, "reset ep[%u] %08x %08x %016lx %08x\r\n",
|
||||
epid, ep_ctx->dwEpCtx0, ep_ctx->dwEpCtx1, ep_ctx->qwEpCtx2,
|
||||
ep_ctx->dwEpCtx4);
|
||||
pthread_mutex_unlock(&devep->mtx);
|
||||
|
||||
done:
|
||||
return cmderr;
|
||||
@ -2589,7 +2661,6 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev,
|
||||
int rem_len = 0;
|
||||
|
||||
dev_ctx = pci_xhci_get_dev_ctx(xdev, slot);
|
||||
|
||||
assert(dev_ctx != NULL);
|
||||
|
||||
ep_ctx = &dev_ctx->ctx_ep[epid];
|
||||
@ -2751,7 +2822,7 @@ pci_xhci_try_usb_xfer(struct pci_xhci_vdev *xdev,
|
||||
do_intr = 0;
|
||||
|
||||
xfer = devep->ep_xfer;
|
||||
USB_DATA_XFER_LOCK(xfer);
|
||||
pthread_mutex_lock(&devep->mtx);
|
||||
|
||||
/* outstanding requests queued up */
|
||||
if (dev->dev_ue->ue_data != NULL) {
|
||||
@ -2772,12 +2843,11 @@ pci_xhci_try_usb_xfer(struct pci_xhci_vdev *xdev,
|
||||
if (err == XHCI_TRB_ERROR_SUCCESS && do_intr)
|
||||
pci_xhci_assert_interrupt(xdev);
|
||||
|
||||
/* XXX should not do it if error? */
|
||||
USB_DATA_XFER_RESET(xfer);
|
||||
memset(xfer, 0, sizeof(*xfer));
|
||||
}
|
||||
}
|
||||
|
||||
USB_DATA_XFER_UNLOCK(xfer);
|
||||
pthread_mutex_unlock(&devep->mtx);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2806,7 +2876,7 @@ pci_xhci_handle_transfer(struct pci_xhci_vdev *xdev,
|
||||
XHCI_ST_EPCTX_RUNNING, 0x7, 0);
|
||||
|
||||
xfer = devep->ep_xfer;
|
||||
USB_DATA_XFER_LOCK(xfer);
|
||||
pthread_mutex_lock(&devep->mtx);
|
||||
|
||||
UPRINTF(LDBG, "handle_transfer slot %u\r\n", slot);
|
||||
|
||||
@ -2991,23 +3061,19 @@ errout:
|
||||
UPRINTF(LDBG, "[%d]: event ring full\r\n", __LINE__);
|
||||
|
||||
if (!do_retry)
|
||||
USB_DATA_XFER_UNLOCK(xfer);
|
||||
pthread_mutex_unlock(&devep->mtx);
|
||||
|
||||
if (do_intr)
|
||||
pci_xhci_assert_interrupt(xdev);
|
||||
|
||||
if (do_retry) {
|
||||
if (epid == 1)
|
||||
USB_DATA_XFER_RESET(xfer);
|
||||
memset(xfer, 0, sizeof(*xfer));
|
||||
|
||||
UPRINTF(LDBG, "[%d]: retry:continuing with next TRBs\r\n",
|
||||
__LINE__);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (epid == 1)
|
||||
USB_DATA_XFER_RESET(xfer);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -4116,6 +4182,8 @@ pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
pci_xhci_native_usb_dev_disconn_cb,
|
||||
pci_xhci_usb_dev_notify_cb,
|
||||
pci_xhci_usb_dev_intr_cb,
|
||||
pci_xhci_usb_dev_lock_ep_cb,
|
||||
pci_xhci_usb_dev_unlock_ep_cb,
|
||||
xdev, usb_get_log_level()) < 0) {
|
||||
error = -3;
|
||||
goto done;
|
||||
|
@ -193,7 +193,6 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
|
||||
/* async transfer */
|
||||
xfer = r->xfer;
|
||||
assert(xfer);
|
||||
assert(xfer->dev);
|
||||
|
||||
maxp = usb_dev_get_ep_maxp(r->udev, r->in, xfer->epid / 2);
|
||||
if (trn->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
|
||||
@ -210,7 +209,6 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
|
||||
USB_MAX_XFER_BLOCKS, r->buf_length, trn->status);
|
||||
|
||||
/* lock for protecting the transfer */
|
||||
USB_DATA_XFER_LOCK(xfer);
|
||||
xfer->status = USB_ERR_NORMAL_COMPLETION;
|
||||
|
||||
switch (trn->status) {
|
||||
@ -228,7 +226,7 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
|
||||
goto stall_out;
|
||||
case LIBUSB_TRANSFER_CANCELLED:
|
||||
xfer->status = USB_ERR_IOERROR;
|
||||
goto out;
|
||||
goto cancel_out;
|
||||
case LIBUSB_TRANSFER_TIMED_OUT:
|
||||
xfer->status = USB_ERR_TIMEOUT;
|
||||
goto out;
|
||||
@ -242,6 +240,7 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
|
||||
break;
|
||||
}
|
||||
|
||||
g_ctx.lock_ep_cb(xfer->dev, &xfer->epid);
|
||||
for (i = 0; i < trn->num_iso_packets; i++)
|
||||
UPRINTF(LDBG, "iso_frame %d len %u act_len %u\n", i,
|
||||
trn->iso_packet_desc[i].length,
|
||||
@ -313,12 +312,15 @@ out:
|
||||
if (do_intr && g_ctx.intr_cb)
|
||||
g_ctx.intr_cb(xfer->dev, NULL);
|
||||
|
||||
cancel_out:
|
||||
/* unlock and release memory */
|
||||
USB_DATA_XFER_UNLOCK(xfer);
|
||||
g_ctx.unlock_ep_cb(xfer->dev, &xfer->epid);
|
||||
libusb_free_transfer(trn);
|
||||
|
||||
if (r && r->buffer)
|
||||
free(r->buffer);
|
||||
|
||||
xfer->requests[r->blk_start] = NULL;
|
||||
free(r);
|
||||
}
|
||||
|
||||
@ -842,6 +844,7 @@ usb_dev_data(void *pdata, struct usb_data_xfer *xfer, int dir, int epctx)
|
||||
r->buf_length = data_size;
|
||||
r->blk_start = blk_start;
|
||||
r->blk_count = blk_count;
|
||||
xfer->requests[blk_start] = r;
|
||||
UPRINTF(LDBG, "%s: transfer_length %d ep%d-transfer (%d-%d %d) request"
|
||||
"-%d (%d-%d %d) direction %s type %s\r\n", __func__,
|
||||
data_size, epctx, xfer->head, (xfer->tail - 1) %
|
||||
@ -1227,6 +1230,7 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
|
||||
int
|
||||
usb_dev_sys_init(usb_dev_sys_cb conn_cb, usb_dev_sys_cb disconn_cb,
|
||||
usb_dev_sys_cb notify_cb, usb_dev_sys_cb intr_cb,
|
||||
usb_dev_sys_cb lock_ep_cb, usb_dev_sys_cb unlock_ep_cb,
|
||||
void *hci_data, int log_level)
|
||||
{
|
||||
libusb_hotplug_event native_conn_evt;
|
||||
@ -1257,6 +1261,8 @@ usb_dev_sys_init(usb_dev_sys_cb conn_cb, usb_dev_sys_cb disconn_cb,
|
||||
g_ctx.disconn_cb = disconn_cb;
|
||||
g_ctx.notify_cb = notify_cb;
|
||||
g_ctx.intr_cb = intr_cb;
|
||||
g_ctx.lock_ep_cb = lock_ep_cb;
|
||||
g_ctx.unlock_ep_cb = unlock_ep_cb;
|
||||
|
||||
num_devs = usb_dev_scan_dev(&g_ctx.devlist);
|
||||
UPRINTF(LINF, "found %d devices before Guest OS booted\r\n", num_devs);
|
||||
|
@ -163,6 +163,7 @@ struct usb_data_xfer_block {
|
||||
struct usb_data_xfer {
|
||||
uint64_t magic;
|
||||
struct usb_data_xfer_block data[USB_MAX_XFER_BLOCKS];
|
||||
struct usb_dev_req *requests[USB_MAX_XFER_BLOCKS];
|
||||
struct usb_device_request *ureq; /* setup ctl request */
|
||||
int ndata; /* # of data items */
|
||||
int head;
|
||||
@ -171,7 +172,6 @@ struct usb_data_xfer {
|
||||
int epid; /* related endpoint id */
|
||||
int pid; /* token id */
|
||||
int status;
|
||||
pthread_mutex_t mtx;
|
||||
};
|
||||
|
||||
struct usb_devpath {
|
||||
@ -207,28 +207,6 @@ enum USB_ERRCODE {
|
||||
|
||||
#define USB_DATA_OK(x, i) ((x)->data[(i)].buf != NULL)
|
||||
|
||||
#define USB_DATA_XFER_INIT(x) do { \
|
||||
pthread_mutexattr_t attr; \
|
||||
pthread_mutexattr_init(&attr); \
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
|
||||
memset((x), 0, sizeof(*(x))); \
|
||||
pthread_mutex_init(&((x)->mtx), &attr); \
|
||||
} while (0)
|
||||
|
||||
#define USB_DATA_XFER_RESET(x) do { \
|
||||
pthread_mutex_lock(&((x)->mtx)); \
|
||||
memset((x)->data, 0, sizeof((x)->data)); \
|
||||
(x)->ndata = 0; \
|
||||
(x)->head = (x)->tail = 0; \
|
||||
pthread_mutex_unlock((&(x)->mtx)); \
|
||||
} while (0)
|
||||
|
||||
#define USB_DATA_XFER_LOCK(x) \
|
||||
pthread_mutex_lock(&((x)->mtx))
|
||||
|
||||
#define USB_DATA_XFER_UNLOCK(x) \
|
||||
pthread_mutex_unlock(&((x)->mtx))
|
||||
|
||||
#define LOG_TAG "USB: "
|
||||
#define LFTL 0
|
||||
#define LWRN 1
|
||||
|
@ -106,6 +106,8 @@ struct usb_dev_sys_ctx_info {
|
||||
usb_dev_sys_cb disconn_cb;
|
||||
usb_dev_sys_cb notify_cb;
|
||||
usb_dev_sys_cb intr_cb;
|
||||
usb_dev_sys_cb lock_ep_cb;
|
||||
usb_dev_sys_cb unlock_ep_cb;
|
||||
|
||||
libusb_device **devlist;
|
||||
|
||||
@ -118,6 +120,8 @@ struct usb_dev_sys_ctx_info {
|
||||
/* intialize the usb_dev subsystem and register callbacks for HCD layer */
|
||||
int usb_dev_sys_init(usb_dev_sys_cb conn_cb, usb_dev_sys_cb disconn_cb,
|
||||
usb_dev_sys_cb notify_cb, usb_dev_sys_cb intr_cb,
|
||||
usb_dev_sys_cb lock_ep_cb,
|
||||
usb_dev_sys_cb unlock_ep_cb,
|
||||
void *hci_data, int log_level);
|
||||
void usb_dev_sys_deinit(void);
|
||||
void *usb_dev_init(void *pdata, char *opt);
|
||||
|
Loading…
Reference in New Issue
Block a user