DM USB: introduce struct xhci_block for xHCI emulation

In the struct usb_block, there are some fields such as 'ccs',
'streamid', which should not be seen in the USB layer. This
patch intruduces new struct xhci_block to include the variables
for xHCI emulation.

Tracked-On: #3628
Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Xiaoguang Wu 2019-09-09 16:14:30 +08:00 committed by wenlingz
parent 0110465416
commit 8949a5802a
3 changed files with 96 additions and 43 deletions

View File

@ -291,6 +291,12 @@ struct pci_xhci_excap {
void *data; void *data;
}; };
struct xhci_block {
uint32_t ccs;
uint64_t trb_addr;
uint32_t streamid;
};
static DEFINE_EXCP_PROT(u2_prot, static DEFINE_EXCP_PROT(u2_prot,
0x08, 0x08,
2, 2,
@ -465,6 +471,7 @@ static int pci_xhci_parse_tablet(struct pci_xhci_vdev *xdev, char *opts);
static int pci_xhci_parse_log_level(struct pci_xhci_vdev *xdev, char *opts); static int pci_xhci_parse_log_level(struct pci_xhci_vdev *xdev, char *opts);
static int pci_xhci_parse_extcap(struct pci_xhci_vdev *xdev, char *opts); 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 usb_xfer *xfer);
#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[] = {
@ -1060,11 +1067,7 @@ pci_xhci_dev_destroy(struct pci_xhci_dev_emu *de)
for (i = 1; i < XHCI_MAX_ENDPOINTS; i++) { for (i = 1; i < XHCI_MAX_ENDPOINTS; i++) {
vdep = &de->eps[i]; vdep = &de->eps[i];
if (vdep->ep_xfer) { if (vdep->ep_xfer) {
if (vdep->ep_xfer->ureq) { pci_xhci_free_usb_xfer(vdep->ep_xfer);
free(vdep->ep_xfer->ureq);
vdep->ep_xfer->ureq = NULL;
}
free(vdep->ep_xfer);
vdep->ep_xfer = NULL; vdep->ep_xfer = NULL;
} }
} }
@ -1536,6 +1539,53 @@ pci_xhci_deassert_interrupt(struct pci_xhci_vdev *xdev)
pci_lintr_assert(xdev->dev); pci_lintr_assert(xdev->dev);
} }
static struct usb_xfer *
pci_xhci_alloc_usb_xfer(struct pci_xhci_dev_emu *dev, int epid)
{
int i;
struct usb_xfer *xfer;
xfer = calloc(1, sizeof(struct usb_xfer));
if (!xfer)
return NULL;
for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) {
xfer->data[i].hcb = calloc(1, sizeof(struct xhci_block));
if (!xfer->data[i].hcb)
goto fail;
}
xfer->dev = (void *)dev;
xfer->epid = epid;
return xfer;
fail:
for (; i >= 0; i--)
free(xfer->data[i].hcb);
free(xfer);
return NULL;
}
static void
pci_xhci_free_usb_xfer(struct usb_xfer *xfer)
{
int i;
if (!xfer)
return;
for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) {
free(xfer->data[i].hcb);
xfer->data[i].hcb = NULL;
}
if (xfer->ureq) {
free(xfer->ureq);
xfer->ureq = NULL;
}
free(xfer);
}
static int static int
pci_xhci_init_ep(struct pci_xhci_dev_emu *dev, int epid) pci_xhci_init_ep(struct pci_xhci_dev_emu *dev, int epid)
{ {
@ -1594,12 +1644,8 @@ pci_xhci_init_ep(struct pci_xhci_dev_emu *dev, int epid)
} }
if (devep->ep_xfer == NULL) { if (devep->ep_xfer == NULL) {
devep->ep_xfer = calloc(1, sizeof(struct usb_xfer)); devep->ep_xfer = pci_xhci_alloc_usb_xfer(dev, epid);
if (devep->ep_xfer) { if (!devep->ep_xfer)
devep->ep_xfer->dev = (void *)dev;
devep->ep_xfer->epid = epid;
devep->ep_xfer->magic = USB_DROPPED_XFER_MAGIC;
} else
goto errout; goto errout;
} }
@ -1630,8 +1676,7 @@ pci_xhci_disable_ep(struct pci_xhci_dev_emu *dev, int epid)
free(devep->ep_sctx_trbs); free(devep->ep_sctx_trbs);
if (devep->ep_xfer != NULL) { if (devep->ep_xfer != NULL) {
memset(devep->ep_xfer, 0, sizeof(*devep->ep_xfer)); pci_xhci_free_usb_xfer(devep->ep_xfer);
free(devep->ep_xfer);
devep->ep_xfer = NULL; devep->ep_xfer = NULL;
} }
@ -2606,6 +2651,7 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
struct xhci_dev_ctx *dev_ctx; struct xhci_dev_ctx *dev_ctx;
struct xhci_endp_ctx *ep_ctx; struct xhci_endp_ctx *ep_ctx;
struct xhci_trb *trb; struct xhci_trb *trb;
struct xhci_block *hcb;
struct xhci_trb evtrb; struct xhci_trb evtrb;
uint32_t trbflags; uint32_t trbflags;
uint32_t edtla; uint32_t edtla;
@ -2645,7 +2691,8 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
/* go through list of TRBs and insert event(s) */ /* go through list of TRBs and insert event(s) */
for (i = (uint32_t)xfer->head; xfer->ndata > 0; ) { for (i = (uint32_t)xfer->head; xfer->ndata > 0; ) {
evtrb.qwTrb0 = (uint64_t)xfer->data[i].hci_data; hcb = xfer->data[i].hcb;
evtrb.qwTrb0 = hcb->trb_addr;
trb = XHCI_GADDR(xdev, evtrb.qwTrb0); trb = XHCI_GADDR(xdev, evtrb.qwTrb0);
trbflags = trb->dwTrb3; trbflags = trb->dwTrb3;
@ -2666,7 +2713,7 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
xfer->head = index_inc(xfer->head, USB_MAX_XFER_BLOCKS); xfer->head = index_inc(xfer->head, USB_MAX_XFER_BLOCKS);
edtla += xfer->data[i].bdone; edtla += xfer->data[i].bdone;
trb->dwTrb3 = (trb->dwTrb3 & ~0x1) | (xfer->data[i].ccs); trb->dwTrb3 = (trb->dwTrb3 & ~0x1) | (hcb->ccs);
if (xfer->data[i].type == USB_DATA_PART) { if (xfer->data[i].type == USB_DATA_PART) {
rem_len += xfer->data[i].blen; rem_len += xfer->data[i].blen;
i = index_inc(i, USB_MAX_XFER_BLOCKS); i = index_inc(i, USB_MAX_XFER_BLOCKS);
@ -2794,7 +2841,8 @@ pci_xhci_try_usb_xfer(struct pci_xhci_vdev *xdev,
if (err == XHCI_TRB_ERROR_SUCCESS && do_intr) if (err == XHCI_TRB_ERROR_SUCCESS && do_intr)
pci_xhci_assert_interrupt(xdev); pci_xhci_assert_interrupt(xdev);
memset(xfer, 0, sizeof(*xfer)); pci_xhci_free_usb_xfer(devep->ep_xfer);
devep->ep_xfer = NULL;
} }
} }
@ -2816,6 +2864,7 @@ pci_xhci_handle_transfer(struct pci_xhci_vdev *xdev,
{ {
struct xhci_trb *setup_trb; struct xhci_trb *setup_trb;
struct usb_xfer *xfer; struct usb_xfer *xfer;
struct xhci_block hcb;
struct usb_block *xfer_block; struct usb_block *xfer_block;
struct usb_block *prev_block; struct usb_block *prev_block;
uint64_t val; uint64_t val;
@ -2855,13 +2904,19 @@ retry:
xfer_block = NULL; xfer_block = NULL;
hcb.ccs = ccs;
hcb.trb_addr = addr;
hcb.streamid = streamid;
switch (XHCI_TRB_3_TYPE_GET(trbflags)) { switch (XHCI_TRB_3_TYPE_GET(trbflags)) {
case XHCI_TRB_TYPE_LINK: case XHCI_TRB_TYPE_LINK:
if (trb->dwTrb3 & XHCI_TRB_3_TC_BIT) if (trb->dwTrb3 & XHCI_TRB_3_TC_BIT) {
ccs ^= 0x1; ccs ^= 0x1;
hcb.ccs = ccs;
}
xfer_block = usb_block_append(xfer, NULL, 0, xfer_block = usb_block_append(xfer, NULL, 0, &hcb,
(void *)addr, ccs); sizeof(hcb));
if (!xfer_block) { if (!xfer_block) {
err = XHCI_TRB_ERROR_STALL; err = XHCI_TRB_ERROR_STALL;
goto errout; goto errout;
@ -2889,8 +2944,8 @@ retry:
memcpy(xfer->ureq, &val, memcpy(xfer->ureq, &val,
sizeof(struct usb_device_request)); sizeof(struct usb_device_request));
xfer_block = usb_block_append(xfer, NULL, 0, xfer_block = usb_block_append(xfer, NULL, 0, &hcb,
(void *)addr, ccs); sizeof(hcb));
if (!xfer_block) { if (!xfer_block) {
free(xfer->ureq); free(xfer->ureq);
xfer->ureq = NULL; xfer->ureq = NULL;
@ -2918,8 +2973,8 @@ retry:
(void *)(trbflags & XHCI_TRB_3_IDT_BIT ? (void *)(trbflags & XHCI_TRB_3_IDT_BIT ?
&trb->qwTrb0 : &trb->qwTrb0 :
XHCI_GADDR(xdev, trb->qwTrb0)), XHCI_GADDR(xdev, trb->qwTrb0)),
trb->dwTrb2 & 0x1FFFF, (void *)addr, trb->dwTrb2 & 0x1FFFF, &hcb,
ccs); sizeof(hcb));
if (!xfer_block) { if (!xfer_block) {
err = XHCI_TRB_ERROR_STALL; err = XHCI_TRB_ERROR_STALL;
@ -2935,13 +2990,13 @@ retry:
break; break;
case XHCI_TRB_TYPE_STATUS_STAGE: case XHCI_TRB_TYPE_STATUS_STAGE:
xfer_block = usb_block_append(xfer, NULL, 0, xfer_block = usb_block_append(xfer, NULL, 0, &hcb,
(void *)addr, ccs); sizeof(hcb));
break; break;
case XHCI_TRB_TYPE_NOOP: case XHCI_TRB_TYPE_NOOP:
xfer_block = usb_block_append(xfer, NULL, 0, xfer_block = usb_block_append(xfer, NULL, 0, &hcb,
(void *)addr, ccs); sizeof(hcb));
if (!xfer_block) { if (!xfer_block) {
err = XHCI_TRB_ERROR_STALL; err = XHCI_TRB_ERROR_STALL;
goto errout; goto errout;
@ -2950,8 +3005,8 @@ retry:
break; break;
case XHCI_TRB_TYPE_EVENT_DATA: case XHCI_TRB_TYPE_EVENT_DATA:
xfer_block = usb_block_append(xfer, NULL, 0, xfer_block = usb_block_append(xfer, NULL, 0, &hcb,
(void *)addr, ccs); sizeof(hcb));
if (!xfer_block) { if (!xfer_block) {
err = XHCI_TRB_ERROR_TRB; err = XHCI_TRB_ERROR_TRB;
goto errout; goto errout;
@ -2959,8 +3014,10 @@ retry:
if ((epid > 1) && (trbflags & XHCI_TRB_3_IOC_BIT)) if ((epid > 1) && (trbflags & XHCI_TRB_3_IOC_BIT))
xfer_block->stat = USB_BLOCK_HANDLED; xfer_block->stat = USB_BLOCK_HANDLED;
if (prev_block && prev_block->type == USB_DATA_PART) if (prev_block && prev_block->type == USB_DATA_PART) {
prev_block->type = USB_DATA_FULL; prev_block->type = USB_DATA_FULL;
prev_block = NULL;
}
break; break;
@ -2977,16 +3034,13 @@ retry:
UPRINTF(LDBG, "next trb: 0x%lx\r\n", (uint64_t)trb); UPRINTF(LDBG, "next trb: 0x%lx\r\n", (uint64_t)trb);
if (xfer_block) { if (xfer_block) {
xfer_block->trbnext = addr;
xfer_block->streamid = streamid;
/* FIXME: /* FIXME:
* should add some code to process the scenario in * should add some code to process the scenario in
* which endpoint stop command is comming in the * which endpoint stop command is comming in the
* middle of many data transfers. * middle of many data transfers.
*/ */
pci_xhci_update_ep_ring(xdev, dev, devep, ep_ctx, pci_xhci_update_ep_ring(xdev, dev, devep, ep_ctx,
xfer_block->streamid, streamid, addr, ccs);
xfer_block->trbnext, xfer_block->ccs);
} }
if (is_isoch == true || XHCI_TRB_3_TYPE_GET(trbflags) == if (is_isoch == true || XHCI_TRB_3_TYPE_GET(trbflags) ==

View File

@ -101,19 +101,21 @@ usb_emu_finddev(char *name)
} }
struct usb_block * struct usb_block *
usb_block_append(struct usb_xfer *xfer, void *buf, int blen, usb_block_append(struct usb_xfer *xfer, void *buf, int blen, void *hcb,
void *hci_data, int ccs) int hcb_len)
{ {
struct usb_block *xb; struct usb_block *xb;
if (xfer->ndata >= USB_MAX_XFER_BLOCKS) if (xfer->ndata >= USB_MAX_XFER_BLOCKS)
return NULL; return NULL;
if (hcb == NULL)
return NULL;
xb = &xfer->data[xfer->tail]; xb = &xfer->data[xfer->tail];
xb->buf = buf; xb->buf = buf;
xb->blen = blen; xb->blen = blen;
xb->hci_data = hci_data; memcpy(xb->hcb, hcb, hcb_len);
xb->ccs = ccs;
xb->stat = USB_BLOCK_FREE; xb->stat = USB_BLOCK_FREE;
xb->bdone = 0; xb->bdone = 0;
xb->type = USB_DATA_NONE; xb->type = USB_DATA_NONE;

View File

@ -159,11 +159,8 @@ struct usb_block {
int blen; /* in:len(buf), out:len(remaining) */ int blen; /* in:len(buf), out:len(remaining) */
int bdone; /* bytes transferred */ int bdone; /* bytes transferred */
enum usb_block_stat stat; /* processed status */ enum usb_block_stat stat; /* processed status */
void *hci_data; /* HCI private reference */
int ccs;
uint32_t streamid;
uint64_t trbnext; /* next TRB guest address */
enum usb_block_type type; enum usb_block_type type;
void *hcb; /* host controller block */
}; };
struct usb_xfer { struct usb_xfer {
@ -253,7 +250,7 @@ struct usb_devemu *usb_emu_finddev(char *name);
int usb_native_is_bus_existed(uint8_t bus_num); int usb_native_is_bus_existed(uint8_t bus_num);
int usb_native_is_port_existed(uint8_t bus_num, uint8_t port_num); int usb_native_is_port_existed(uint8_t bus_num, uint8_t port_num);
struct usb_block *usb_block_append(struct usb_xfer *xfer, void *buf, int blen, struct usb_block *usb_block_append(struct usb_xfer *xfer, void *buf, int blen,
void *hci_data, int ccs); void *hcb, int hcb_len);
int usb_get_hub_port_num(struct usb_devpath *path); int usb_get_hub_port_num(struct usb_devpath *path);
char *usb_dev_path(struct usb_devpath *path); char *usb_dev_path(struct usb_devpath *path);
bool usb_dev_path_cmp(struct usb_devpath *p1, struct usb_devpath *p2); bool usb_dev_path_cmp(struct usb_devpath *p1, struct usb_devpath *p2);