dm: add thread for usb doorbell array write

Host doorbell array write can be asynchronous, so add an async thread
which is used to deal doorbell write.

Tracked-On: #8504
Signed-off-by: Yuanyuan Zhao <yuanyuan.zhao@intel.com>
Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com>
This commit is contained in:
Yuanyuan Zhao 2023-08-14 17:18:03 +08:00 committed by acrnsi-robot
parent 64d999e703
commit 863f220a19

View File

@ -384,6 +384,12 @@ struct pci_xhci_vbdp_dev_state {
uint8_t state; uint8_t state;
}; };
struct pci_xhci_async_request_node {
STAILQ_ENTRY(pci_xhci_async_request_node) link;
uint64_t offset;
uint64_t value;
};
struct pci_xhci_vdev { struct pci_xhci_vdev {
struct pci_vdev *dev; struct pci_vdev *dev;
pthread_mutex_t mtx; pthread_mutex_t mtx;
@ -424,6 +430,12 @@ struct pci_xhci_vdev {
int vbdp_dev_num; int vbdp_dev_num;
struct pci_xhci_vbdp_dev_state vbdp_devs[XHCI_MAX_VIRT_PORTS]; struct pci_xhci_vbdp_dev_state vbdp_devs[XHCI_MAX_VIRT_PORTS];
pthread_t async_thread;
bool async_transfer;
pthread_cond_t async_cond;
pthread_mutex_t async_tmx;
STAILQ_HEAD(, pci_xhci_async_request_node) async_head;
/* /*
* native_ports uses for record the command line assigned native root * native_ports uses for record the command line assigned native root
* hub ports and its child external hub ports. * hub ports and its child external hub ports.
@ -485,6 +497,7 @@ static int pci_xhci_parse_extcap(struct pci_xhci_vdev *xdev, char *opts);
static int pci_xhci_convert_speed(int lspeed); static int pci_xhci_convert_speed(int lspeed);
static void pci_xhci_free_usb_xfer(struct pci_xhci_dev_emu *dev, struct usb_xfer *xfer); static void pci_xhci_free_usb_xfer(struct pci_xhci_dev_emu *dev, struct usb_xfer *xfer);
static void pci_xhci_isoc_handler(void *arg, uint64_t param); static void pci_xhci_isoc_handler(void *arg, uint64_t param);
static void pci_xhci_async_enqueue(struct pci_xhci_vdev *xdev, uint64_t offset, uint64_t value);
#define XHCI_OPT_MAX_LEN 32 #define XHCI_OPT_MAX_LEN 32
static struct pci_xhci_option_elem xhci_option_table[] = { static struct pci_xhci_option_elem xhci_option_table[] = {
@ -1982,7 +1995,9 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
slot, di->path.bus, usb_dev_path(&di->path)); slot, di->path.bus, usb_dev_path(&di->path));
/* release all the resource allocated for virtual device */ /* release all the resource allocated for virtual device */
pthread_mutex_unlock(&xdev->mtx);
pci_xhci_dev_destroy(dev); pci_xhci_dev_destroy(dev);
pthread_mutex_lock(&xdev->mtx);
} else } else
UPRINTF(LWRN, "invalid slot %d\r\n", slot); UPRINTF(LWRN, "invalid slot %d\r\n", slot);
@ -2056,6 +2071,7 @@ pci_xhci_cmd_address_device(struct pci_xhci_vdev *xdev,
struct usb_native_devinfo *di; struct usb_native_devinfo *di;
uint32_t cmderr; uint32_t cmderr;
uint8_t rh_port; uint8_t rh_port;
int ret;
input_ctx = XHCI_GADDR(xdev, trb->qwTrb0 & ~0xFUL); input_ctx = XHCI_GADDR(xdev, trb->qwTrb0 & ~0xFUL);
if (!input_ctx) { if (!input_ctx) {
@ -2110,7 +2126,10 @@ pci_xhci_cmd_address_device(struct pci_xhci_vdev *xdev,
"port %d\r\n", di->path.bus, "port %d\r\n", di->path.bus,
usb_dev_path(&di->path), rh_port); usb_dev_path(&di->path), rh_port);
pthread_mutex_unlock(&xdev->mtx);
dev = pci_xhci_dev_create(xdev, di); dev = pci_xhci_dev_create(xdev, di);
pthread_mutex_lock(&xdev->mtx);
if (!dev) { if (!dev) {
UPRINTF(LFTL, "fail to create device for %d-%s\r\n", UPRINTF(LFTL, "fail to create device for %d-%s\r\n",
di->path.bus, di->path.bus,
@ -2142,8 +2161,15 @@ pci_xhci_cmd_address_device(struct pci_xhci_vdev *xdev,
dev->hci.hci_address = slot; dev->hci.hci_address = slot;
dev->dev_ctx = dev_ctx; dev->dev_ctx = dev_ctx;
if (dev->dev_ue->ue_reset == NULL || if (dev->dev_ue->ue_reset == NULL) {
dev->dev_ue->ue_reset(dev->dev_instance) < 0) { cmderr = XHCI_TRB_ERROR_ENDP_NOT_ON;
goto done;
}
pthread_mutex_unlock(&xdev->mtx);
ret = dev->dev_ue->ue_reset(dev->dev_instance);
pthread_mutex_lock(&xdev->mtx);
if (ret < 0) {
cmderr = XHCI_TRB_ERROR_ENDP_NOT_ON; cmderr = XHCI_TRB_ERROR_ENDP_NOT_ON;
goto done; goto done;
} }
@ -2391,6 +2417,7 @@ pci_xhci_cmd_reset_ep(struct pci_xhci_vdev *xdev,
devep = &dev->eps[epid]; devep = &dev->eps[epid];
pthread_mutex_lock(&devep->mtx); pthread_mutex_lock(&devep->mtx);
pthread_mutex_unlock(&xdev->mtx);
xfer = devep->ep_xfer; xfer = devep->ep_xfer;
for (i = 0; i < xfer->max_blk_cnt; ++i) { for (i = 0; i < xfer->max_blk_cnt; ++i) {
@ -2413,6 +2440,7 @@ pci_xhci_cmd_reset_ep(struct pci_xhci_vdev *xdev,
UPRINTF(LDBG, "reset ep[%u] %08x %08x %016lx %08x\r\n", UPRINTF(LDBG, "reset ep[%u] %08x %08x %016lx %08x\r\n",
epid, ep_ctx->dwEpCtx0, ep_ctx->dwEpCtx1, ep_ctx->qwEpCtx2, epid, ep_ctx->dwEpCtx0, ep_ctx->dwEpCtx1, ep_ctx->qwEpCtx2,
ep_ctx->dwEpCtx4); ep_ctx->dwEpCtx4);
pthread_mutex_lock(&xdev->mtx);
pthread_mutex_unlock(&devep->mtx); pthread_mutex_unlock(&devep->mtx);
done: done:
@ -3022,8 +3050,10 @@ pci_xhci_try_usb_xfer(struct pci_xhci_vdev *xdev,
/* outstanding requests queued up */ /* outstanding requests queued up */
if (dev->dev_ue->ue_data != NULL) { if (dev->dev_ue->ue_data != NULL) {
pthread_mutex_unlock(&xdev->mtx);
err = dev->dev_ue->ue_data(dev->dev_instance, xfer, epid & 0x1 ? err = dev->dev_ue->ue_data(dev->dev_instance, xfer, epid & 0x1 ?
USB_XFER_IN : USB_XFER_OUT, epid/2); USB_XFER_IN : USB_XFER_OUT, epid/2);
pthread_mutex_lock(&xdev->mtx);
if (err == USB_ERR_CANCELLED) { if (err == USB_ERR_CANCELLED) {
if (USB_DATA_GET_ERRCODE(&xfer->data[xfer->head]) == if (USB_DATA_GET_ERRCODE(&xfer->data[xfer->head]) ==
USB_NAK) USB_NAK)
@ -3286,8 +3316,11 @@ retry:
if (epid == 1) { if (epid == 1) {
err = USB_ERR_NOT_STARTED; err = USB_ERR_NOT_STARTED;
if (dev->dev_ue->ue_request != NULL) if (dev->dev_ue->ue_request != NULL) {
pthread_mutex_unlock(&xdev->mtx);
err = dev->dev_ue->ue_request(dev->dev_instance, xfer); err = dev->dev_ue->ue_request(dev->dev_instance, xfer);
pthread_mutex_lock(&xdev->mtx);
}
setup_trb = NULL; setup_trb = NULL;
} else { } else {
/* handle data transfer */ /* handle data transfer */
@ -3658,21 +3691,24 @@ pci_xhci_write(struct vmctx *ctx,
xdev = dev->arg; xdev = dev->arg;
pthread_mutex_lock(&xdev->mtx);
if (offset < XHCI_CAPLEN) /* read only registers */ if (offset < XHCI_CAPLEN) /* read only registers */
UPRINTF(LWRN, "write RO-CAPs offset %ld\r\n", offset); UPRINTF(LWRN, "write RO-CAPs offset %ld\r\n", offset);
else if (offset < xdev->dboff) else if (offset < xdev->dboff) {
pthread_mutex_lock(&xdev->mtx);
pci_xhci_hostop_write(xdev, offset, value); pci_xhci_hostop_write(xdev, offset, value);
else if (offset < xdev->rtsoff)
pci_xhci_dbregs_write(xdev, offset, value);
else if (offset < xdev->rtsend)
pci_xhci_rtsregs_write(xdev, offset, value);
else if (offset < xdev->regsend)
pci_xhci_excap_write(xdev, offset, value);
else
UPRINTF(LWRN, "write invalid offset %ld\r\n", offset);
pthread_mutex_unlock(&xdev->mtx); pthread_mutex_unlock(&xdev->mtx);
} else if (offset < xdev->rtsoff) {
pci_xhci_async_enqueue(xdev, offset, value);
} else if (offset < xdev->rtsend) {
pthread_mutex_lock(&xdev->mtx);
pci_xhci_rtsregs_write(xdev, offset, value);
pthread_mutex_unlock(&xdev->mtx);
} else if (offset < xdev->regsend) {
pthread_mutex_lock(&xdev->mtx);
pci_xhci_excap_write(xdev, offset, value);
pthread_mutex_unlock(&xdev->mtx);
} else
UPRINTF(LWRN, "write invalid offset %ld\r\n", offset);
} }
static uint64_t static uint64_t
@ -3901,25 +3937,29 @@ pci_xhci_read(struct vmctx *ctx,
uint32_t value; uint32_t value;
xdev = dev->arg; xdev = dev->arg;
if (offset < XHCI_CAPLEN) {
pthread_mutex_lock(&xdev->mtx); pthread_mutex_lock(&xdev->mtx);
if (offset < XHCI_CAPLEN)
value = pci_xhci_hostcap_read(xdev, offset); value = pci_xhci_hostcap_read(xdev, offset);
else if (offset < xdev->dboff) pthread_mutex_unlock(&xdev->mtx);
} else if (offset < xdev->dboff) {
pthread_mutex_lock(&xdev->mtx);
value = pci_xhci_hostop_read(xdev, offset); value = pci_xhci_hostop_read(xdev, offset);
else if (offset < xdev->rtsoff) pthread_mutex_unlock(&xdev->mtx);
} else if (offset < xdev->rtsoff) {
value = pci_xhci_dbregs_read(xdev, offset); value = pci_xhci_dbregs_read(xdev, offset);
else if (offset < xdev->rtsend) } else if (offset < xdev->rtsend) {
pthread_mutex_lock(&xdev->mtx);
value = pci_xhci_rtsregs_read(xdev, offset); value = pci_xhci_rtsregs_read(xdev, offset);
else if (offset < xdev->regsend) pthread_mutex_unlock(&xdev->mtx);
} else if (offset < xdev->regsend) {
pthread_mutex_lock(&xdev->mtx);
value = pci_xhci_excap_read(xdev, offset); value = pci_xhci_excap_read(xdev, offset);
else { pthread_mutex_unlock(&xdev->mtx);
} else {
value = 0; value = 0;
UPRINTF(LDBG, "read invalid offset %ld\r\n", offset); UPRINTF(LDBG, "read invalid offset %ld\r\n", offset);
} }
pthread_mutex_unlock(&xdev->mtx);
switch (size) { switch (size) {
case 1: case 1:
value &= 0xFF; value &= 0xFF;
@ -4005,6 +4045,7 @@ pci_xhci_dev_intr(struct usb_hci *hci, int epctx)
struct xhci_endp_ctx *ep_ctx; struct xhci_endp_ctx *ep_ctx;
int dir_in; int dir_in;
int epid; int epid;
int ret = 0;
dir_in = epctx & 0x80; dir_in = epctx & 0x80;
epid = epctx & ~0x80; epid = epctx & ~0x80;
@ -4018,10 +4059,11 @@ pci_xhci_dev_intr(struct usb_hci *hci, int epctx)
xdev = dev->xdev; xdev = dev->xdev;
/* check if device is ready; OS has to initialise it */ /* check if device is ready; OS has to initialise it */
pthread_mutex_lock(&xdev->mtx);
if (xdev->rtsregs.erstba_p == NULL || if (xdev->rtsregs.erstba_p == NULL ||
(xdev->opregs.usbcmd & XHCI_CMD_RS) == 0 || (xdev->opregs.usbcmd & XHCI_CMD_RS) == 0 ||
dev->dev_ctx == NULL) dev->dev_ctx == NULL)
return 0; goto out;
p = XHCI_PORTREG_PTR(xdev, hci->hci_port); p = XHCI_PORTREG_PTR(xdev, hci->hci_port);
@ -4030,16 +4072,18 @@ pci_xhci_dev_intr(struct usb_hci *hci, int epctx)
p->portsc &= ~XHCI_PS_PLS_MASK; p->portsc &= ~XHCI_PS_PLS_MASK;
p->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_RESUME); p->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_RESUME);
if ((p->portsc & XHCI_PS_PLC) != 0) if ((p->portsc & XHCI_PS_PLC) != 0)
return 0; goto out;
p->portsc |= XHCI_PS_PLC; p->portsc |= XHCI_PS_PLC;
pci_xhci_set_evtrb(&evtrb, hci->hci_port, pci_xhci_set_evtrb(&evtrb, hci->hci_port,
XHCI_TRB_ERROR_SUCCESS, XHCI_TRB_ERROR_SUCCESS,
XHCI_TRB_EVENT_PORT_STS_CHANGE); XHCI_TRB_EVENT_PORT_STS_CHANGE);
if (pci_xhci_insert_event(xdev, &evtrb, 0) != 0) { if (pci_xhci_insert_event(xdev, &evtrb, 0) != 0) {
UPRINTF(LFTL, "Failed to inject port status change event!\r\n"); UPRINTF(LFTL, "Failed to inject port status change event!\r\n");
return -ENAVAIL; ret = -ENAVAIL;
goto out;
} }
} }
@ -4048,14 +4092,15 @@ pci_xhci_dev_intr(struct usb_hci *hci, int epctx)
if ((ep_ctx->dwEpCtx0 & 0x7) == XHCI_ST_EPCTX_DISABLED) { if ((ep_ctx->dwEpCtx0 & 0x7) == XHCI_ST_EPCTX_DISABLED) {
UPRINTF(LWRN, "device interrupt on disabled endpoint %d\r\n", UPRINTF(LWRN, "device interrupt on disabled endpoint %d\r\n",
epid); epid);
return 0; goto out;
} }
UPRINTF(LDBG, "device interrupt on endpoint %d\r\n", epid); UPRINTF(LDBG, "device interrupt on endpoint %d\r\n", epid);
pci_xhci_device_doorbell(xdev, hci->hci_port, epid, 0); pci_xhci_device_doorbell(xdev, hci->hci_port, epid, 0);
return 0; out:
pthread_mutex_unlock(&xdev->mtx);
return ret;
} }
static int static int
@ -4418,6 +4463,55 @@ pci_xhci_isoc_handler(void *arg, uint64_t param)
? "under" : "over", pdata->slot, pdata->epnum); ? "under" : "over", pdata->slot, pdata->epnum);
} }
static void
pci_xhci_async_enqueue(struct pci_xhci_vdev *xdev, uint64_t offset, uint64_t value)
{
struct pci_xhci_async_request_node *request;
request = malloc(sizeof(struct pci_xhci_async_request_node));
if (request == NULL) {
UPRINTF(LFTL, "%s: malloc memory fail\r\n", __func__);
return;
}
request->offset = offset;
request->value = value;
pthread_mutex_lock(&xdev->async_tmx);
if (STAILQ_EMPTY(&xdev->async_head)) {
STAILQ_INSERT_HEAD(&xdev->async_head, request, link);
} else {
STAILQ_INSERT_TAIL(&xdev->async_head, request, link);
}
pthread_cond_signal(&xdev->async_cond);
pthread_mutex_unlock(&xdev->async_tmx);
}
static void *
pci_xhci_ansyc_thread(void *data)
{
struct pci_xhci_vdev *xdev;
struct pci_xhci_async_request_node *request;
xdev = data;
pthread_mutex_lock(&xdev->async_tmx);
while (xdev->async_transfer || !STAILQ_EMPTY(&xdev->async_head)) {
if(STAILQ_EMPTY(&xdev->async_head))
pthread_cond_wait(&xdev->async_cond, &xdev->async_tmx);
if ((request = STAILQ_FIRST(&xdev->async_head)) == NULL) {
continue;
}
pthread_mutex_unlock(&xdev->async_tmx);
pthread_mutex_lock(&xdev->mtx);
pci_xhci_dbregs_write(xdev, request->offset, request->value);
pthread_mutex_unlock(&xdev->mtx);
pthread_mutex_lock(&xdev->async_tmx);
STAILQ_REMOVE_HEAD(&xdev->async_head, link);
free(request);
}
pthread_mutex_unlock(&xdev->async_tmx);
return NULL;
}
static int static int
pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{ {
@ -4548,6 +4642,15 @@ pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
if (error) if (error)
goto done; goto done;
xdev->async_transfer = true;
pthread_cond_init(&xdev->async_cond, NULL);
pthread_mutex_init(&xdev->async_tmx, NULL);
STAILQ_INIT(&xdev->async_head);
error = pthread_create(&xdev->async_thread, NULL, pci_xhci_ansyc_thread,
(void *)xdev);
if (error)
goto done;
xhci_in_use = 1; xhci_in_use = 1;
done: done:
if (error) { if (error) {
@ -4603,6 +4706,14 @@ pci_xhci_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
pthread_join(xdev->vbdp_thread, NULL); pthread_join(xdev->vbdp_thread, NULL);
sem_close(&xdev->vbdp_sem); sem_close(&xdev->vbdp_sem);
pthread_mutex_lock(&xdev->async_tmx);
xdev->async_transfer = false;
pthread_cond_signal(&xdev->async_cond);
pthread_mutex_unlock(&xdev->async_tmx);
pthread_join(xdev->async_thread, NULL);
pthread_cond_destroy(&xdev->async_cond);
pthread_mutex_destroy(&xdev->async_tmx);
pthread_mutex_destroy(&xdev->mtx); pthread_mutex_destroy(&xdev->mtx);
free(xdev); free(xdev);
xhci_in_use = 0; xhci_in_use = 0;