From owner-p4-projects@FreeBSD.ORG Tue Sep 2 19:49:35 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id B3D7A106567D; Tue, 2 Sep 2008 19:49:35 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 76E8D1065673 for ; Tue, 2 Sep 2008 19:49:35 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 644678FC19 for ; Tue, 2 Sep 2008 19:49:35 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.2/8.14.2) with ESMTP id m82JnZLH031028 for ; Tue, 2 Sep 2008 19:49:35 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.2/8.14.1/Submit) id m82JnZBC031022 for perforce@freebsd.org; Tue, 2 Sep 2008 19:49:35 GMT (envelope-from hselasky@FreeBSD.org) Date: Tue, 2 Sep 2008 19:49:35 GMT Message-Id: <200809021949.m82JnZBC031022@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 149076 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Sep 2008 19:49:36 -0000 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;