DM USB: introduce enum type usb_block_type

In the process of USB data transfer, there three kinds of data blocks:
a. Non data block, which contains some control information;
b. Partial data block, which contains part of a large data chunk;
c. Full data block, which contains a complete data chunk.

In previous implementation, the differences mentioned above are described
by the usb_block::chained. But the 'chained' is concept in the xHCI area
and should not appear in the USB layer. This patch introduces enum type
usb_block_type to replace the 'chained' field in struct usb_block.

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 11:23:03 +08:00 committed by wenlingz
parent 7445e404a8
commit 236c23e418
4 changed files with 45 additions and 22 deletions

View File

@ -2650,12 +2650,11 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
trbflags = trb->dwTrb3; trbflags = trb->dwTrb3;
UPRINTF(LDBG, "xfer[%d] done?%u:%d trb %x %016lx %x " UPRINTF(LDBG, "xfer[%d] done?%u:%d trb %x %016lx %x "
"(err %d) IOC?%d, chained %d\r\n", "(err %d) IOC?%d, type %d\r\n",
i, xfer->data[i].stat, xfer->data[i].blen, i, xfer->data[i].stat, xfer->data[i].blen,
XHCI_TRB_3_TYPE_GET(trbflags), evtrb.qwTrb0, XHCI_TRB_3_TYPE_GET(trbflags), evtrb.qwTrb0, trbflags,
trbflags, err, err, trb->dwTrb3 & XHCI_TRB_3_IOC_BIT ? 1 : 0,
trb->dwTrb3 & XHCI_TRB_3_IOC_BIT ? 1 : 0, xfer->data[i].type);
xfer->data[i].chained);
if (xfer->data[i].stat < USB_BLOCK_HANDLED) { if (xfer->data[i].stat < USB_BLOCK_HANDLED) {
xfer->head = (int)i; xfer->head = (int)i;
@ -2668,14 +2667,14 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
edtla += xfer->data[i].bdone; edtla += xfer->data[i].bdone;
trb->dwTrb3 = (trb->dwTrb3 & ~0x1) | (xfer->data[i].ccs); trb->dwTrb3 = (trb->dwTrb3 & ~0x1) | (xfer->data[i].ccs);
if (xfer->data[i].chained == 1) { if (xfer->data[i].type == USB_DATA_PART) {
rem_len += xfer->data[i].blen; rem_len += xfer->data[i].blen;
i = (i + 1) % USB_MAX_XFER_BLOCKS; i = (i + 1) % USB_MAX_XFER_BLOCKS;
/* When the chained == 1, this 'continue' will delay /* This 'continue' will delay the IOC behavior which
* the IOC behavior which could decrease the number * could decrease the number of virtual interrupts.
* of virtual interrupts. This could GREATLY improve * This could GREATLY improve the performance especially
* the performance especially under ISOCH scenario. * under ISOCH scenario.
*/ */
continue; continue;
} else } else
@ -2818,6 +2817,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 usb_block *xfer_block; struct usb_block *xfer_block;
struct usb_block *prev_block;
uint64_t val; uint64_t val;
uint32_t trbflags; uint32_t trbflags;
int do_intr, err; int do_intr, err;
@ -2837,6 +2837,7 @@ retry:
do_retry = 0; do_retry = 0;
do_intr = 0; do_intr = 0;
setup_trb = NULL; setup_trb = NULL;
prev_block = NULL;
while (1) { while (1) {
pci_xhci_dump_trb(trb); pci_xhci_dump_trb(trb);
@ -2920,8 +2921,17 @@ retry:
trb->dwTrb2 & 0x1FFFF, (void *)addr, trb->dwTrb2 & 0x1FFFF, (void *)addr,
ccs); ccs);
if (xfer_block && (trb->dwTrb3 & XHCI_TRB_3_CHAIN_BIT)) if (!xfer_block) {
xfer_block->chained = 1; err = XHCI_TRB_ERROR_STALL;
goto errout;
}
if (trb->dwTrb3 & XHCI_TRB_3_CHAIN_BIT)
xfer_block->type = USB_DATA_PART;
else
xfer_block->type = USB_DATA_FULL;
prev_block = xfer_block;
break; break;
case XHCI_TRB_TYPE_STATUS_STAGE: case XHCI_TRB_TYPE_STATUS_STAGE:
@ -2948,6 +2958,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)
prev_block->type = USB_DATA_FULL;
break; break;
default: default:

View File

@ -274,7 +274,8 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
if (d > block->blen) if (d > block->blen)
d = block->blen; d = block->blen;
if (block->buf) { if (block->type == USB_DATA_PART ||
block->type == USB_DATA_FULL) {
if (r->in == TOKEN_IN) { if (r->in == TOKEN_IN) {
memcpy(block->buf, buf + buf_idx, d); memcpy(block->buf, buf + buf_idx, d);
buf_idx += d; buf_idx += d;
@ -292,7 +293,7 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
i++; i++;
} while (block->chained == 1); } while (block->type == USB_DATA_PART);
} }
stall_out: stall_out:
@ -386,14 +387,15 @@ usb_dev_prepare_xfer(struct usb_xfer *xfer, int *count, int *size)
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
continue; continue;
} }
if (block->buf && block->blen > 0) { if (block->type == USB_DATA_PART ||
block->type == USB_DATA_FULL) {
if (!found) { if (!found) {
found = 1; found = 1;
first = idx; first = idx;
} }
c++; c++;
s += block->blen; s += block->blen;
} else if (!block->buf || !block->blen) { } else if (block->type == USB_DATA_NONE) {
/* there are two cases: /* there are two cases:
* 1. LINK trb is in the middle of trbs. * 1. LINK trb is in the middle of trbs.
* 2. LINK trb is a single trb. * 2. LINK trb is a single trb.
@ -801,7 +803,7 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
continue; continue;
} }
if (xfer->data[idx].chained == 1) { if (xfer->data[idx].type == USB_DATA_PART) {
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
continue; continue;
} }
@ -838,7 +840,8 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
if (!dir) { if (!dir) {
for (i = 0, j = 0, buf_idx = 0; j < blk_count; ++i) { for (i = 0, j = 0, buf_idx = 0; j < blk_count; ++i) {
b = &xfer->data[(blk_start + i) % USB_MAX_XFER_BLOCKS]; b = &xfer->data[(blk_start + i) % USB_MAX_XFER_BLOCKS];
if (b->buf) { if (b->type == USB_DATA_FULL ||
b->type == USB_DATA_PART) {
memcpy(&r->buffer[buf_idx], b->buf, b->blen); memcpy(&r->buffer[buf_idx], b->buf, b->blen);
buf_idx += b->blen; buf_idx += b->blen;
j++; j++;
@ -850,13 +853,13 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
for (i = 0, j = 0, idx = blk_start; i < blk_count; ++i) { for (i = 0, j = 0, idx = blk_start; i < blk_count; ++i) {
int len = xfer->data[idx].blen; int len = xfer->data[idx].blen;
if (len <= 0) { if (xfer->data[idx].type == USB_DATA_NONE) {
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
i--; i--;
continue; continue;
} }
if (xfer->data[idx].chained == 1) { if (xfer->data[idx].type == USB_DATA_PART) {
r->trn->iso_packet_desc[j].length += len; r->trn->iso_packet_desc[j].length += len;
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
continue; continue;

View File

@ -116,7 +116,7 @@ usb_block_append(struct usb_xfer *xfer, void *buf, int blen,
xb->ccs = ccs; xb->ccs = ccs;
xb->stat = USB_BLOCK_FREE; xb->stat = USB_BLOCK_FREE;
xb->bdone = 0; xb->bdone = 0;
xb->chained = 0; xb->type = USB_DATA_NONE;
xfer->ndata++; xfer->ndata++;
xfer->tail = (xfer->tail + 1) % USB_MAX_XFER_BLOCKS; xfer->tail = (xfer->tail + 1) % USB_MAX_XFER_BLOCKS;
return xb; return xb;

View File

@ -142,6 +142,12 @@ struct usb_hci {
int hci_port; int hci_port;
}; };
enum usb_block_type {
USB_DATA_NONE,
USB_DATA_PART,
USB_DATA_FULL
};
/* /*
* Each xfer block is mapped to the hci transfer block. * Each xfer block is mapped to the hci transfer block.
* On input into the device handler, blen is set to the lenght of buf. * On input into the device handler, blen is set to the lenght of buf.
@ -155,9 +161,9 @@ struct usb_block {
enum usb_block_stat stat; /* processed status */ enum usb_block_stat stat; /* processed status */
void *hci_data; /* HCI private reference */ void *hci_data; /* HCI private reference */
int ccs; int ccs;
int chained;
uint32_t streamid; uint32_t streamid;
uint64_t trbnext; /* next TRB guest address */ uint64_t trbnext; /* next TRB guest address */
enum usb_block_type type;
}; };
struct usb_xfer { struct usb_xfer {