DM USB: dynamically allocate block count for struct usb_xfer
The block count of the struct usb_xfer is hard coded by the macro USB_MAX_XFER_BLOCKS (1024), it wastes memory if 1024 blocks are allocated for low speed transfer such as control transfer or interrupt transfer. This patch introduces a new method to allocate different number of blocks according to different endpoint type. 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:
parent
f1b142e6e0
commit
06781b37e9
|
@ -1554,19 +1554,66 @@ pci_xhci_deassert_interrupt(struct pci_xhci_vdev *xdev)
|
|||
static struct usb_xfer *
|
||||
pci_xhci_alloc_usb_xfer(struct pci_xhci_dev_emu *dev, int epid)
|
||||
{
|
||||
int i;
|
||||
struct usb_xfer *xfer;
|
||||
struct xhci_dev_ctx *dev_ctx;
|
||||
struct xhci_endp_ctx *ep_ctx;
|
||||
int dir, max_blk_cnt, i = 0;
|
||||
uint8_t type;
|
||||
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
dev_ctx = dev->dev_ctx;
|
||||
ep_ctx = &dev_ctx->ctx_ep[epid];
|
||||
type = XHCI_EPCTX_1_EPTYPE_GET(ep_ctx->dwEpCtx1);
|
||||
|
||||
/* TODO:
|
||||
* The following code is still not perfect, due to fixed values are
|
||||
* not flexible and the overflow risk is still existed. Will try to
|
||||
* find a dynamic way could work both for Linux and Windows.
|
||||
*/
|
||||
switch (type) {
|
||||
case XHCI_EPTYPE_CTRL:
|
||||
case XHCI_EPTYPE_INT_IN:
|
||||
case XHCI_EPTYPE_INT_OUT:
|
||||
max_blk_cnt = 128;
|
||||
break;
|
||||
case XHCI_EPTYPE_BULK_IN:
|
||||
case XHCI_EPTYPE_BULK_OUT:
|
||||
max_blk_cnt = 1024;
|
||||
break;
|
||||
case XHCI_EPTYPE_ISOC_IN:
|
||||
case XHCI_EPTYPE_ISOC_OUT:
|
||||
max_blk_cnt = 2048;
|
||||
break;
|
||||
default:
|
||||
UPRINTF(LFTL, "err: unexpected epid %d type %d dir %d\r\n",
|
||||
epid, type, dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xfer = calloc(1, sizeof(struct usb_xfer));
|
||||
if (!xfer)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) {
|
||||
xfer->reqs = calloc(max_blk_cnt, sizeof(struct usb_dev_req *));
|
||||
if (!xfer->reqs)
|
||||
goto fail;
|
||||
|
||||
xfer->data = calloc(max_blk_cnt, sizeof(struct usb_block));
|
||||
if (!xfer->data)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < max_blk_cnt; ++i) {
|
||||
xfer->data[i].hcb = calloc(1, sizeof(struct xhci_block));
|
||||
if (!xfer->data[i].hcb)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
UPRINTF(LINF, "allocate %d blocks for epid %d type %d dir %d\r\n",
|
||||
max_blk_cnt, epid, type, dir);
|
||||
|
||||
xfer->max_blk_cnt = max_blk_cnt;
|
||||
xfer->dev = (void *)dev;
|
||||
xfer->epid = epid;
|
||||
return xfer;
|
||||
|
@ -1574,6 +1621,9 @@ pci_xhci_alloc_usb_xfer(struct pci_xhci_dev_emu *dev, int epid)
|
|||
fail:
|
||||
for (; i >= 0; i--)
|
||||
free(xfer->data[i].hcb);
|
||||
|
||||
free(xfer->data);
|
||||
free(xfer->reqs);
|
||||
free(xfer);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1586,15 +1636,12 @@ pci_xhci_free_usb_xfer(struct usb_xfer *xfer)
|
|||
if (!xfer)
|
||||
return;
|
||||
|
||||
for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) {
|
||||
for (i = 0; i < xfer->max_blk_cnt; i++)
|
||||
free(xfer->data[i].hcb);
|
||||
xfer->data[i].hcb = NULL;
|
||||
}
|
||||
|
||||
if (xfer->ureq) {
|
||||
free(xfer->ureq);
|
||||
xfer->ureq = NULL;
|
||||
}
|
||||
free(xfer->data);
|
||||
free(xfer->reqs);
|
||||
free(xfer->ureq);
|
||||
free(xfer);
|
||||
}
|
||||
|
||||
|
@ -2292,8 +2339,8 @@ pci_xhci_cmd_reset_ep(struct pci_xhci_vdev *xdev,
|
|||
pthread_mutex_lock(&devep->mtx);
|
||||
|
||||
xfer = devep->ep_xfer;
|
||||
for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) {
|
||||
r = xfer->requests[i];
|
||||
for (i = 0; i < xfer->max_blk_cnt; ++i) {
|
||||
r = xfer->reqs[i];
|
||||
if (r && r->trn)
|
||||
/* let usb_dev_comp_req to free the memory */
|
||||
libusb_cancel_transfer(r->trn);
|
||||
|
@ -2744,13 +2791,13 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
|
|||
|
||||
xfer->data[i].stat = USB_BLOCK_FREE;
|
||||
xfer->ndata--;
|
||||
xfer->head = index_inc(xfer->head, USB_MAX_XFER_BLOCKS);
|
||||
xfer->head = index_inc(xfer->head, xfer->max_blk_cnt);
|
||||
edtla += xfer->data[i].bdone;
|
||||
|
||||
trb->dwTrb3 = (trb->dwTrb3 & ~0x1) | (hcb->ccs);
|
||||
if (xfer->data[i].type == USB_DATA_PART) {
|
||||
rem_len += xfer->data[i].blen;
|
||||
i = index_inc(i, USB_MAX_XFER_BLOCKS);
|
||||
i = index_inc(i, xfer->max_blk_cnt);
|
||||
|
||||
/* This 'continue' will delay the IOC behavior which
|
||||
* could decrease the number of virtual interrupts.
|
||||
|
@ -2769,7 +2816,7 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
|
|||
!((err == XHCI_TRB_ERROR_SHORT_PKT) &&
|
||||
(trb->dwTrb3 & XHCI_TRB_3_ISP_BIT))) {
|
||||
|
||||
i = index_inc(i, USB_MAX_XFER_BLOCKS);
|
||||
i = index_inc(i, xfer->max_blk_cnt);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2794,7 +2841,7 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer,
|
|||
if (err != XHCI_TRB_ERROR_SUCCESS)
|
||||
break;
|
||||
|
||||
i = index_inc(i, USB_MAX_XFER_BLOCKS);
|
||||
i = index_inc(i, xfer->max_blk_cnt);
|
||||
rem_len = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -336,7 +336,7 @@ umouse_request(void *scarg, struct usb_xfer *xfer)
|
|||
}
|
||||
|
||||
xfer->data[idx].stat = USB_BLOCK_HANDLED;
|
||||
idx = index_inc(idx, USB_MAX_XFER_BLOCKS);
|
||||
idx = index_inc(idx, xfer->max_blk_cnt);
|
||||
}
|
||||
|
||||
err = USB_ERR_NORMAL_COMPLETION;
|
||||
|
@ -716,7 +716,7 @@ umouse_data_handler(void *scarg, struct usb_xfer *xfer, int dir,
|
|||
|
||||
data->stat = USB_BLOCK_HANDLED;
|
||||
data = NULL;
|
||||
idx = index_inc(idx, USB_MAX_XFER_BLOCKS);
|
||||
idx = index_inc(idx, xfer->max_blk_cnt);
|
||||
}
|
||||
if (!data)
|
||||
goto done;
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#define LOG_TAG "USBPM: "
|
||||
|
||||
static struct usb_dev_sys_ctx_info g_ctx;
|
||||
static uint8_t usb_dev_get_ep_type(struct usb_dev *udev, int pid, int epnum);
|
||||
static uint16_t usb_dev_get_ep_maxp(struct usb_dev *udev, int pid, int epnum);
|
||||
|
||||
static bool
|
||||
|
@ -246,8 +245,8 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
|
|||
idx = r->blk_head;
|
||||
buf_idx = 0;
|
||||
done = trn->actual_length;
|
||||
while (index_valid(r->blk_head, r->blk_tail, USB_MAX_XFER_BLOCKS, idx))
|
||||
{
|
||||
|
||||
while (index_valid(r->blk_head, r->blk_tail, xfer->max_blk_cnt, idx)) {
|
||||
if (trn->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
|
||||
buf_idx = 0;
|
||||
buf = libusb_get_iso_packet_buffer_simple(trn, i);
|
||||
|
@ -281,7 +280,7 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
|
|||
block->blen -= d;
|
||||
block->bdone = d;
|
||||
block->stat = USB_BLOCK_HANDLED;
|
||||
idx = index_inc(idx, USB_MAX_XFER_BLOCKS);
|
||||
idx = index_inc(idx, xfer->max_blk_cnt);
|
||||
|
||||
} while (block->type == USB_DATA_PART);
|
||||
}
|
||||
|
@ -290,10 +289,10 @@ stall_out:
|
|||
if (is_stalled) {
|
||||
idx = r->blk_head;
|
||||
while (index_valid(r->blk_head, r->blk_tail,
|
||||
USB_MAX_XFER_BLOCKS, idx)) {
|
||||
xfer->max_blk_cnt, idx)) {
|
||||
block = &xfer->data[idx];
|
||||
block->stat = USB_BLOCK_HANDLED;
|
||||
idx = index_inc(idx, USB_MAX_XFER_BLOCKS);
|
||||
idx = index_inc(idx, xfer->max_blk_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,7 +312,7 @@ cancel_out:
|
|||
if (r && r->buffer)
|
||||
free(r->buffer);
|
||||
|
||||
xfer->requests[r->blk_head] = NULL;
|
||||
xfer->reqs[r->blk_head] = NULL;
|
||||
free(r);
|
||||
free_transfer:
|
||||
libusb_free_transfer(trn);
|
||||
|
@ -368,11 +367,11 @@ usb_dev_prepare_xfer(struct usb_xfer *xfer, int *head, int *tail)
|
|||
idx = xfer->head;
|
||||
first = -1;
|
||||
size = 0;
|
||||
if (idx < 0 || idx >= USB_MAX_XFER_BLOCKS)
|
||||
if (idx < 0 || idx >= xfer->max_blk_cnt)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < xfer->ndata;
|
||||
i++, idx = index_inc(idx, USB_MAX_XFER_BLOCKS)) {
|
||||
i++, idx = index_inc(idx, xfer->max_blk_cnt)) {
|
||||
block = &xfer->data[idx];
|
||||
if (block->stat == USB_BLOCK_HANDLED ||
|
||||
block->stat == USB_BLOCK_HANDLING)
|
||||
|
@ -701,7 +700,7 @@ usb_dev_prepare_ctrl_xfer(struct usb_xfer *xfer)
|
|||
|
||||
idx = xfer->head;
|
||||
|
||||
if (idx < 0 || idx >= USB_MAX_XFER_BLOCKS)
|
||||
if (idx < 0 || idx >= xfer->max_blk_cnt)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < xfer->ndata; i++) {
|
||||
|
@ -714,7 +713,7 @@ usb_dev_prepare_ctrl_xfer(struct usb_xfer *xfer)
|
|||
ret = blk;
|
||||
|
||||
blk->stat = USB_BLOCK_HANDLED;
|
||||
idx = index_inc(idx, USB_MAX_XFER_BLOCKS);
|
||||
idx = index_inc(idx, xfer->max_blk_cnt);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -776,8 +775,8 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
|
|||
UPRINTF(LDBG, "iso maxp %u framelen %d\r\n", maxp, framelen);
|
||||
|
||||
for (idx = head;
|
||||
index_valid(head, tail, USB_MAX_XFER_BLOCKS, idx);
|
||||
idx = index_inc(idx, USB_MAX_XFER_BLOCKS)) {
|
||||
index_valid(head, tail, xfer->max_blk_cnt, idx);
|
||||
idx = index_inc(idx, xfer->max_blk_cnt)) {
|
||||
|
||||
if (xfer->data[idx].blen > framelen)
|
||||
UPRINTF(LFTL, "err framelen %d\r\n", framelen);
|
||||
|
@ -804,7 +803,7 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
|
|||
r->buf_size = size;
|
||||
r->blk_head = head;
|
||||
r->blk_tail = tail;
|
||||
xfer->requests[head] = r;
|
||||
xfer->reqs[head] = r;
|
||||
UPRINTF(LDBG, "%s: %d-%s: explen %d ep%d-xfr [%d-%d %d] rq-%d "
|
||||
"[%d-%d %d] dir %s type %s\r\n", __func__,
|
||||
info->path.bus, usb_dev_path(&info->path), size, epctx,
|
||||
|
@ -814,8 +813,8 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
|
|||
|
||||
if (!dir) {
|
||||
for (idx = head, buf_idx = 0;
|
||||
index_valid(head, tail, USB_MAX_XFER_BLOCKS, idx);
|
||||
idx = index_inc(idx, USB_MAX_XFER_BLOCKS)) {
|
||||
index_valid(head, tail, xfer->max_blk_cnt, idx);
|
||||
idx = index_inc(idx, xfer->max_blk_cnt)) {
|
||||
b = &xfer->data[idx];
|
||||
if (b->type == USB_DATA_PART ||
|
||||
b->type == USB_DATA_FULL) {
|
||||
|
@ -827,8 +826,8 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
|
|||
|
||||
if (type == USB_ENDPOINT_ISOC) {
|
||||
for (i = 0, idx = head;
|
||||
index_valid(head, tail, USB_MAX_XFER_BLOCKS, idx);
|
||||
idx = index_inc(idx, USB_MAX_XFER_BLOCKS)) {
|
||||
index_valid(head, tail, xfer->max_blk_cnt, idx);
|
||||
idx = index_inc(idx, xfer->max_blk_cnt)) {
|
||||
int len = xfer->data[idx].blen;
|
||||
|
||||
if (xfer->data[idx].type == USB_DATA_NONE) {
|
||||
|
|
|
@ -106,7 +106,7 @@ usb_block_append(struct usb_xfer *xfer, void *buf, int blen, void *hcb,
|
|||
{
|
||||
struct usb_block *xb;
|
||||
|
||||
if (xfer->ndata >= USB_MAX_XFER_BLOCKS)
|
||||
if (xfer->ndata >= xfer->max_blk_cnt)
|
||||
return NULL;
|
||||
|
||||
if (hcb == NULL)
|
||||
|
@ -120,7 +120,7 @@ usb_block_append(struct usb_xfer *xfer, void *buf, int blen, void *hcb,
|
|||
xb->bdone = 0;
|
||||
xb->type = USB_DATA_NONE;
|
||||
xfer->ndata++;
|
||||
xfer->tail = index_inc(xfer->tail, USB_MAX_XFER_BLOCKS);
|
||||
xfer->tail = index_inc(xfer->tail, xfer->max_blk_cnt);
|
||||
return xb;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,6 @@
|
|||
* By default, the native xhci driver use two segments which contain 2 * 256
|
||||
* trbs, so 1024 is enough currently.
|
||||
*/
|
||||
#define USB_MAX_XFER_BLOCKS 1024
|
||||
|
||||
#define USB_XFER_OUT 0
|
||||
#define USB_XFER_IN 1
|
||||
|
||||
|
@ -164,9 +162,8 @@ struct usb_block {
|
|||
};
|
||||
|
||||
struct usb_xfer {
|
||||
uint64_t magic;
|
||||
struct usb_block data[USB_MAX_XFER_BLOCKS];
|
||||
struct usb_dev_req *requests[USB_MAX_XFER_BLOCKS];
|
||||
struct usb_block *data;
|
||||
struct usb_dev_req **reqs;
|
||||
struct usb_device_request *ureq; /* setup ctl request */
|
||||
int ndata; /* # of data items */
|
||||
int head;
|
||||
|
@ -174,6 +171,7 @@ struct usb_xfer {
|
|||
void *dev; /* struct pci_xhci_dev_emu *dev */
|
||||
int epid; /* related endpoint id */
|
||||
int pid; /* token id */
|
||||
int max_blk_cnt;
|
||||
int status;
|
||||
};
|
||||
|
||||
|
|
|
@ -190,6 +190,15 @@ struct xhci_endp_ctx {
|
|||
volatile uint32_t dwEpCtx7;
|
||||
};
|
||||
|
||||
#define XHCI_EPTYPE_INVALID 0
|
||||
#define XHCI_EPTYPE_ISOC_OUT 1
|
||||
#define XHCI_EPTYPE_BULK_OUT 2
|
||||
#define XHCI_EPTYPE_INT_OUT 3
|
||||
#define XHCI_EPTYPE_CTRL 4
|
||||
#define XHCI_EPTYPE_ISOC_IN 5
|
||||
#define XHCI_EPTYPE_BULK_IN 6
|
||||
#define XHCI_EPTYPE_INT_IN 7
|
||||
|
||||
struct xhci_input_ctx {
|
||||
#define XHCI_INCTX_NON_CTRL_MASK 0xFFFFFFFCU
|
||||
volatile uint32_t dwInCtx0;
|
||||
|
|
Loading…
Reference in New Issue