Date: Tue, 2 Sep 2008 19:49:35 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 149076 for review Message-ID: <200809021949.m82JnZBC031022@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=149076 Change 149076 by hselasky@hselasky_laptop001 on 2008/09/02 19:49:33 Optimisation: Extend "usb2_do_request_flags" functionality so that it can operate on a userland data pointer. This make USB requests from userland quicker, hence there is no more need to allocate a separate buffer for temporarily storing the data. Affected files ... .. //depot/projects/usb/src/sys/dev/usb2/core/usb2_busdma.c#5 edit .. //depot/projects/usb/src/sys/dev/usb2/core/usb2_busdma.h#3 edit .. //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.c#22 edit .. //depot/projects/usb/src/sys/dev/usb2/core/usb2_request.c#16 edit .. //depot/projects/usb/src/sys/dev/usb2/core/usb2_transfer.c#24 edit .. //depot/projects/usb/src/sys/dev/usb2/include/usb2_ioctl.h#13 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_busdma.c#5 (text+ko) ==== @@ -135,6 +135,38 @@ } /*------------------------------------------------------------------------* + * usb2_copy_in_user - copy directly to DMA-able memory from userland + * + * Return values: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +int +usb2_copy_in_user(struct usb2_page_cache *cache, uint32_t offset, + const void *ptr, uint32_t len) +{ + struct usb2_page_search buf_res; + int error; + + while (len != 0) { + + usb2_get_page(cache, offset, &buf_res); + + if (buf_res.length > len) { + buf_res.length = len; + } + error = copyin(ptr, buf_res.buffer, buf_res.length); + if (error) + return (error); + + offset += buf_res.length; + len -= buf_res.length; + ptr = USB_ADD_BYTES(ptr, buf_res.length); + } + return (0); /* success */ +} + +/*------------------------------------------------------------------------* * usb2_m_copy_in - copy a mbuf chain directly into DMA-able memory *------------------------------------------------------------------------*/ struct usb2_m_copy_in_arg { @@ -225,6 +257,38 @@ } /*------------------------------------------------------------------------* + * usb2_copy_out_user - copy directly from DMA-able memory to userland + * + * Return values: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +int +usb2_copy_out_user(struct usb2_page_cache *cache, uint32_t offset, + void *ptr, uint32_t len) +{ + struct usb2_page_search res; + int error; + + while (len != 0) { + + usb2_get_page(cache, offset, &res); + + if (res.length > len) { + res.length = len; + } + error = copyout(res.buffer, ptr, res.length); + if (error) + return (error); + + offset += res.length; + len -= res.length; + ptr = USB_ADD_BYTES(ptr, res.length); + } + return (0); /* success */ +} + +/*------------------------------------------------------------------------* * usb2_bzero - zero DMA-able memory *------------------------------------------------------------------------*/ void ==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_busdma.h#3 (text+ko) ==== @@ -154,7 +154,9 @@ void usb2_bdma_work_loop(struct usb2_xfer_queue *pq); void usb2_bzero(struct usb2_page_cache *cache, uint32_t offset, uint32_t len); void usb2_copy_in(struct usb2_page_cache *cache, uint32_t offset, const void *ptr, uint32_t len); +int usb2_copy_in_user(struct usb2_page_cache *cache, uint32_t offset, const void *ptr, uint32_t len); void usb2_copy_out(struct usb2_page_cache *cache, uint32_t offset, void *ptr, uint32_t len); +int usb2_copy_out_user(struct usb2_page_cache *cache, uint32_t offset, void *ptr, uint32_t len); void usb2_dma_tag_setup(struct usb2_dma_parent_tag *udpt, struct usb2_dma_tag *udt, bus_dma_tag_t dmat, struct mtx *mtx, usb2_dma_callback_t *func, struct usb2_xfer_root *info, uint8_t ndmabits, uint8_t nudt); void usb2_dma_tag_unsetup(struct usb2_dma_parent_tag *udpt); void usb2_get_page(struct usb2_page_cache *pc, uint32_t offset, struct usb2_page_search *res); ==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.c#22 (text+ko) ==== @@ -901,8 +901,6 @@ int error; uint16_t len; uint16_t actlen; - uint8_t isread; - void *data = NULL; if (f->flag_no_uref) { /* control endpoint only */ @@ -912,44 +910,24 @@ return (EPERM); } len = UGETW(ur->ucr_request.wLength); - isread = (ur->ucr_request.bmRequestType & UT_READ) ? 1 : 0; + /* check if "ucr_data" is valid */ if (len != 0) { if (ur->ucr_data == NULL) { - return (EINVAL); - } - data = malloc(len, M_USBDEV, M_WAITOK); - if (data == NULL) { - error = ENOMEM; - goto done; - } - if (!(ur->ucr_request.bmRequestType & UT_READ)) { - error = copyin(ur->ucr_data, data, len); - if (error) { - goto done; - } + return (EFAULT); } } + /* do the USB request */ error = usb2_do_request_flags - (f->udev, NULL, &ur->ucr_request, data, - (ur->ucr_flags & USB_SHORT_XFER_OK), &actlen, + (f->udev, NULL, &ur->ucr_request, ur->ucr_data, + (ur->ucr_flags & USB_SHORT_XFER_OK) | + USB_USER_DATA_PTR, &actlen, USB_DEFAULT_TIMEOUT); ur->ucr_actlen = actlen; if (error) { error = EIO; - goto done; - } - if ((len != 0) && (ur->ucr_request.bmRequestType & UT_READ)) { - error = copyout(data, ur->ucr_data, len); - if (error) { - goto done; - } - } -done: - if (data) { - free(data, M_USBDEV); } return (error); } ==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_request.c#16 (text+ko) ==== @@ -206,6 +206,9 @@ * at a later point in time. This is tunable by the "hw.usb.ss_delay" * sysctl. This flag is mostly useful for debugging. * + * o USB_USER_DATA_PTR: treat the "data" pointer like a userland + * pointer. + * * "actlen" - if non-NULL the actual transfer length will be stored in * the 16-bit unsigned integer pointed to by "actlen". This * information is mostly useful when the "USB_SHORT_XFER_OK" flag is @@ -232,12 +235,12 @@ { struct usb2_xfer *xfer; const void *desc; + int err = 0; uint32_t start_ticks; uint32_t delta_ticks; uint32_t max_ticks; uint16_t length; uint16_t temp; - usb2_error_t err = 0; if (timeout < 50) { /* timeout is too small */ @@ -276,7 +279,13 @@ *actlen = length; } if (length > 0) { - bcopy(desc, data, length); + if (flags & USB_USER_DATA_PTR) { + if (copyout(desc, data, length)) { + return (USB_ERR_INVAL); + } + } else { + bcopy(desc, data, length); + } } return (0); /* success */ } @@ -332,7 +341,18 @@ if (temp > 0) { if (!(req->bmRequestType & UT_READ)) { - usb2_copy_in(xfer->frbuffers + 1, 0, data, temp); + if (flags & USB_USER_DATA_PTR) { + mtx_unlock(xfer->priv_mtx); + err = usb2_copy_in_user(xfer->frbuffers + 1, + 0, data, temp); + mtx_lock(xfer->priv_mtx); + if (err) { + err = USB_ERR_INVAL; + break; + } + } else { + usb2_copy_in(xfer->frbuffers + 1, 0, data, temp); + } } xfer->nframes = 2; } else { @@ -392,7 +412,19 @@ } if (temp > 0) { if (req->bmRequestType & UT_READ) { - usb2_copy_out(xfer->frbuffers + 1, 0, data, temp); + if (flags & USB_USER_DATA_PTR) { + mtx_unlock(xfer->priv_mtx); + err = usb2_copy_out_user(xfer->frbuffers + 1, + 0, data, temp); + mtx_lock(xfer->priv_mtx); + if (err) { + err = USB_ERR_INVAL; + break; + } + } else { + usb2_copy_out(xfer->frbuffers + 1, + 0, data, temp); + } } } /* @@ -421,6 +453,13 @@ } } + if (err) { + /* + * Make sure that the control endpoint is no longer + * blocked in case of a non-transfer related error: + */ + usb2_transfer_stop(xfer); + } mtx_unlock(xfer->priv_mtx); done: @@ -429,7 +468,7 @@ if (mtx) { mtx_lock(mtx); } - return (err); + return ((usb2_error_t)err); } /*------------------------------------------------------------------------* ==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_transfer.c#24 (text+ko) ==== @@ -1496,6 +1496,8 @@ void usb2_transfer_stop(struct usb2_xfer *xfer) { + struct usb2_pipe *pipe; + if (xfer == NULL) { /* transfer is gone */ return; @@ -1527,6 +1529,10 @@ if (xfer->flags_int.can_cancel_immed && (!xfer->flags_int.did_close)) { DPRINTF("close\n"); + /* + * The following will lead to an USB_ERR_CANCELLED + * error code being passed to the USB callback. + */ (xfer->pipe->methods->close) (xfer); /* only close once */ xfer->flags_int.did_close = 1; @@ -1543,6 +1549,20 @@ * Any additional DMA delay is done by * "usb2_transfer_unsetup()". */ + + /* + * Special case. Check if we need to restart a blocked + * pipe. + */ + pipe = xfer->pipe; + + /* + * If the current USB transfer is completing we need + * to start the next one: + */ + if (pipe->pipe_q.curr == xfer) { + usb2_command_wrapper(&pipe->pipe_q, NULL); + } } mtx_unlock(xfer->usb2_mtx); ==== //depot/projects/usb/src/sys/dev/usb2/include/usb2_ioctl.h#13 (text+ko) ==== @@ -45,6 +45,7 @@ #define USB_USE_POLLING 0x0001 /* internal flag */ #define USB_SHORT_XFER_OK 0x0004 /* allow short reads */ #define USB_DELAY_STATUS_STAGE 0x0010 /* insert delay before STATUS stage */ +#define USB_USER_DATA_PTR 0x0020 /* internal flag */ uint16_t ucr_actlen; /* actual length transferred */ uint8_t ucr_addr; /* zero - currently not used */ struct usb2_device_request ucr_request;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200809021949.m82JnZBC031022>