diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c index 4519cf3e6..582fe0b4e 100644 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -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; diff --git a/devicemodel/hw/platform/usb_pmapper.c b/devicemodel/hw/platform/usb_pmapper.c index 781e84155..1447b8461 100755 --- a/devicemodel/hw/platform/usb_pmapper.c +++ b/devicemodel/hw/platform/usb_pmapper.c @@ -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); diff --git a/devicemodel/include/usb_core.h b/devicemodel/include/usb_core.h index c3e101f06..324cd4bb1 100644 --- a/devicemodel/include/usb_core.h +++ b/devicemodel/include/usb_core.h @@ -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 diff --git a/devicemodel/include/usb_pmapper.h b/devicemodel/include/usb_pmapper.h index 1cd4aab89..496bb852a 100644 --- a/devicemodel/include/usb_pmapper.h +++ b/devicemodel/include/usb_pmapper.h @@ -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);