From owner-svn-src-all@FreeBSD.ORG Sun Nov 22 21:16:44 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id EE3D310656A6; Sun, 22 Nov 2009 21:16:43 +0000 (UTC) (envelope-from thompsa@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id DCD1D8FC1D; Sun, 22 Nov 2009 21:16:43 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id nAMLGh1v029737; Sun, 22 Nov 2009 21:16:43 GMT (envelope-from thompsa@svn.freebsd.org) Received: (from thompsa@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id nAMLGhej029729; Sun, 22 Nov 2009 21:16:43 GMT (envelope-from thompsa@svn.freebsd.org) Message-Id: <200911222116.nAMLGhej029729@svn.freebsd.org> From: Andrew Thompson Date: Sun, 22 Nov 2009 21:16:43 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r199672 - in head/sys/dev/usb: . controller X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 22 Nov 2009 21:16:44 -0000 Author: thompsa Date: Sun Nov 22 21:16:43 2009 New Revision: 199672 URL: http://svn.freebsd.org/changeset/base/199672 Log: Improve High Speed slot allocation mechanism by moving the computation to the endpoint rather than per xfer and provide functions around get/free of resources. Submitted by: Hans Petter Selasky Modified: head/sys/dev/usb/controller/ehci.c head/sys/dev/usb/usb_core.h head/sys/dev/usb/usb_device.c head/sys/dev/usb/usb_hub.c head/sys/dev/usb/usb_hub.h head/sys/dev/usb/usb_transfer.c head/sys/dev/usb/usbdi.h Modified: head/sys/dev/usb/controller/ehci.c ============================================================================== --- head/sys/dev/usb/controller/ehci.c Sun Nov 22 21:16:30 2009 (r199671) +++ head/sys/dev/usb/controller/ehci.c Sun Nov 22 21:16:43 2009 (r199672) @@ -2016,8 +2016,8 @@ ehci_setup_standard_chain(struct usb_xfe qh_endphub = (EHCI_QH_SET_MULT(xfer->max_packet_count & 3) | - EHCI_QH_SET_CMASK(xfer->usb_cmask) | - EHCI_QH_SET_SMASK(xfer->usb_smask) | + EHCI_QH_SET_CMASK(xfer->endpoint->usb_cmask) | + EHCI_QH_SET_SMASK(xfer->endpoint->usb_smask) | EHCI_QH_SET_HUBA(xfer->xroot->udev->hs_hub_addr) | EHCI_QH_SET_PORT(xfer->xroot->udev->hs_port_no)); @@ -2162,7 +2162,7 @@ ehci_isoc_hs_done(ehci_softc_t *sc, stru DPRINTFN(2, "status=0x%08x, len=%u\n", status, len); - if (xfer->usb_smask & (1 << td_no)) { + if (xfer->endpoint->usb_smask & (1 << td_no)) { if (*plen >= len) { /* @@ -2348,22 +2348,8 @@ ehci_device_intr_open(struct usb_xfer *x uint16_t best; uint16_t bit; uint16_t x; - uint8_t slot; - /* Allocate a microframe slot first: */ - - slot = usb_intr_schedule_adjust - (xfer->xroot->udev, xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX); - - if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) { - xfer->usb_uframe = slot; - xfer->usb_smask = (1 << slot) & 0xFF; - xfer->usb_cmask = 0; - } else { - xfer->usb_uframe = slot; - xfer->usb_smask = (1 << slot) & 0x3F; - xfer->usb_cmask = (-(4 << slot)) & 0xFE; - } + usb_hs_bandwidth_alloc(xfer); /* * Find the best QH position corresponding to the given interval: @@ -2399,12 +2385,12 @@ ehci_device_intr_close(struct usb_xfer * { ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - usb_intr_schedule_adjust(xfer->xroot->udev, - -(xfer->max_frame_size), xfer->usb_uframe); - sc->sc_intr_stat[xfer->qh_pos]--; ehci_device_done(xfer, USB_ERR_CANCELLED); + + /* bandwidth must be freed after device done */ + usb_hs_bandwidth_free(xfer); } static void @@ -2726,28 +2712,8 @@ ehci_device_isoc_hs_open(struct usb_xfer ehci_itd_t *td; uint32_t temp; uint8_t ds; - uint8_t slot; - - slot = usb_intr_schedule_adjust(xfer->xroot->udev, xfer->max_frame_size, - USB_HS_MICRO_FRAMES_MAX); - xfer->usb_uframe = slot; - xfer->usb_cmask = 0; - - switch (usbd_xfer_get_fps_shift(xfer)) { - case 0: - xfer->usb_smask = 0xFF; - break; - case 1: - xfer->usb_smask = 0x55 << (slot & 1); - break; - case 2: - xfer->usb_smask = 0x11 << (slot & 3); - break; - default: - xfer->usb_smask = 0x01 << (slot & 7); - break; - } + usb_hs_bandwidth_alloc(xfer); /* initialize all TD's */ @@ -2791,11 +2757,10 @@ ehci_device_isoc_hs_open(struct usb_xfer static void ehci_device_isoc_hs_close(struct usb_xfer *xfer) { - - usb_intr_schedule_adjust(xfer->xroot->udev, - -(xfer->max_frame_size), xfer->usb_uframe); - ehci_device_done(xfer, USB_ERR_CANCELLED); + + /* bandwidth must be freed after device done */ + usb_hs_bandwidth_free(xfer); } static void @@ -2905,7 +2870,7 @@ ehci_device_isoc_hs_enter(struct usb_xfe *plen = xfer->max_frame_size; } - if (xfer->usb_smask & (1 << td_no)) { + if (xfer->endpoint->usb_smask & (1 << td_no)) { status = (EHCI_ITD_SET_LEN(*plen) | EHCI_ITD_ACTIVE | EHCI_ITD_SET_PG(0)); Modified: head/sys/dev/usb/usb_core.h ============================================================================== --- head/sys/dev/usb/usb_core.h Sun Nov 22 21:16:30 2009 (r199671) +++ head/sys/dev/usb/usb_core.h Sun Nov 22 21:16:43 2009 (r199672) @@ -161,9 +161,6 @@ struct usb_xfer { uint8_t address; /* physical USB address */ uint8_t endpointno; /* physical USB endpoint */ uint8_t max_packet_count; - uint8_t usb_smask; - uint8_t usb_cmask; - uint8_t usb_uframe; uint8_t usb_state; uint8_t fps_shift; /* down shift of FPS, 0..3 */ Modified: head/sys/dev/usb/usb_device.c ============================================================================== --- head/sys/dev/usb/usb_device.c Sun Nov 22 21:16:30 2009 (r199671) +++ head/sys/dev/usb/usb_device.c Sun Nov 22 21:16:43 2009 (r199672) @@ -665,7 +665,7 @@ usb_config_parse(struct usb_device *udev /* look for matching endpoints */ if ((iface_index == USB_IFACE_INDEX_ANY) || (iface_index == ep->iface_index)) { - if (ep->refcount != 0) { + if (ep->refcount_alloc != 0) { /* * This typically indicates a * more serious error. Modified: head/sys/dev/usb/usb_hub.c ============================================================================== --- head/sys/dev/usb/usb_hub.c Sun Nov 22 21:16:30 2009 (r199671) +++ head/sys/dev/usb/usb_hub.c Sun Nov 22 21:16:43 2009 (r199672) @@ -1106,43 +1106,62 @@ done: * The best Transaction Translation slot for an interrupt endpoint. *------------------------------------------------------------------------*/ static uint8_t -usb_intr_find_best_slot(usb_size_t *ptr, uint8_t start, uint8_t end) +usb_intr_find_best_slot(usb_size_t *ptr, uint8_t start, + uint8_t end, uint8_t mask) { - usb_size_t max = 0 - 1; + usb_size_t min = 0 - 1; + usb_size_t sum; uint8_t x; uint8_t y; + uint8_t z; y = 0; /* find the last slot with lesser used bandwidth */ for (x = start; x < end; x++) { - if (max >= ptr[x]) { - max = ptr[x]; + + sum = 0; + + /* compute sum of bandwidth */ + for (z = x; z < end; z++) { + if (mask & (1U << (z - x))) + sum += ptr[z]; + } + + /* check if the current multi-slot is more optimal */ + if (min >= sum) { + min = sum; y = x; } + + /* check if the mask is about to be shifted out */ + if (mask & (1U << (end - 1 - x))) + break; } return (y); } /*------------------------------------------------------------------------* - * usb_intr_schedule_adjust + * usb_hs_bandwidth_adjust * * This function will update the bandwith usage for the microframe * having index "slot" by "len" bytes. "len" can be negative. If the * "slot" argument is greater or equal to "USB_HS_MICRO_FRAMES_MAX" * the "slot" argument will be replaced by the slot having least used - * bandwidth. + * bandwidth. The "mask" argument is used for multi-slot allocations. * * Returns: - * The slot on which the bandwidth update was done. + * The slot in which the bandwidth update was done: 0..7 *------------------------------------------------------------------------*/ -uint8_t -usb_intr_schedule_adjust(struct usb_device *udev, int16_t len, uint8_t slot) +static uint8_t +usb_hs_bandwidth_adjust(struct usb_device *udev, int16_t len, + uint8_t slot, uint8_t mask) { struct usb_bus *bus = udev->bus; struct usb_hub *hub; enum usb_dev_speed speed; + uint8_t x; USB_BUS_LOCK_ASSERT(bus, MA_OWNED); @@ -1164,23 +1183,157 @@ usb_intr_schedule_adjust(struct usb_devi hub = udev->parent_hs_hub->hub; if (slot >= USB_HS_MICRO_FRAMES_MAX) { slot = usb_intr_find_best_slot(hub->uframe_usage, - USB_FS_ISOC_UFRAME_MAX, 6); + USB_FS_ISOC_UFRAME_MAX, 6, mask); + } + for (x = slot; x < 8; x++) { + if (mask & (1U << (x - slot))) { + hub->uframe_usage[x] += len; + bus->uframe_usage[x] += len; + } } - hub->uframe_usage[slot] += len; - bus->uframe_usage[slot] += len; break; default: if (slot >= USB_HS_MICRO_FRAMES_MAX) { slot = usb_intr_find_best_slot(bus->uframe_usage, 0, - USB_HS_MICRO_FRAMES_MAX); + USB_HS_MICRO_FRAMES_MAX, mask); + } + for (x = slot; x < 8; x++) { + if (mask & (1U << (x - slot))) { + bus->uframe_usage[x] += len; + } } - bus->uframe_usage[slot] += len; break; } return (slot); } /*------------------------------------------------------------------------* + * usb_hs_bandwidth_alloc + * + * This function is a wrapper function for "usb_hs_bandwidth_adjust()". + *------------------------------------------------------------------------*/ +void +usb_hs_bandwidth_alloc(struct usb_xfer *xfer) +{ + struct usb_device *udev; + uint8_t slot; + uint8_t mask; + uint8_t speed; + + udev = xfer->xroot->udev; + + if (udev->flags.usb_mode != USB_MODE_HOST) + return; /* not supported */ + + xfer->endpoint->refcount_bw++; + if (xfer->endpoint->refcount_bw != 1) + return; /* already allocated */ + + speed = usbd_get_speed(udev); + + switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) { + case UE_INTERRUPT: + /* allocate a microframe slot */ + + mask = 0x01; + slot = usb_hs_bandwidth_adjust(udev, + xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX, mask); + + xfer->endpoint->usb_uframe = slot; + xfer->endpoint->usb_smask = mask << slot; + + if ((speed != USB_SPEED_FULL) && + (speed != USB_SPEED_LOW)) { + xfer->endpoint->usb_cmask = 0x00 ; + } else { + xfer->endpoint->usb_cmask = (-(0x04 << slot)) & 0xFE; + } + break; + + case UE_ISOCHRONOUS: + switch (usbd_xfer_get_fps_shift(xfer)) { + case 0: + mask = 0xFF; + break; + case 1: + mask = 0x55; + break; + case 2: + mask = 0x11; + break; + default: + mask = 0x01; + break; + } + + /* allocate a microframe multi-slot */ + + slot = usb_hs_bandwidth_adjust(udev, + xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX, mask); + + xfer->endpoint->usb_uframe = slot; + xfer->endpoint->usb_cmask = 0; + xfer->endpoint->usb_smask = mask << slot; + break; + + default: + xfer->endpoint->usb_uframe = 0; + xfer->endpoint->usb_cmask = 0; + xfer->endpoint->usb_smask = 0; + break; + } + + DPRINTFN(11, "slot=%d, mask=0x%02x\n", + xfer->endpoint->usb_uframe, + xfer->endpoint->usb_smask >> xfer->endpoint->usb_uframe); +} + +/*------------------------------------------------------------------------* + * usb_hs_bandwidth_free + * + * This function is a wrapper function for "usb_hs_bandwidth_adjust()". + *------------------------------------------------------------------------*/ +void +usb_hs_bandwidth_free(struct usb_xfer *xfer) +{ + struct usb_device *udev; + uint8_t slot; + uint8_t mask; + + udev = xfer->xroot->udev; + + if (udev->flags.usb_mode != USB_MODE_HOST) + return; /* not supported */ + + xfer->endpoint->refcount_bw--; + if (xfer->endpoint->refcount_bw != 0) + return; /* still allocated */ + + switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) { + case UE_INTERRUPT: + case UE_ISOCHRONOUS: + + slot = xfer->endpoint->usb_uframe; + mask = xfer->endpoint->usb_smask; + + /* free microframe slot(s): */ + usb_hs_bandwidth_adjust(udev, + -xfer->max_frame_size, slot, mask >> slot); + + DPRINTFN(11, "slot=%d, mask=0x%02x\n", + slot, mask >> slot); + + xfer->endpoint->usb_uframe = 0; + xfer->endpoint->usb_cmask = 0; + xfer->endpoint->usb_smask = 0; + break; + + default: + break; + } +} + +/*------------------------------------------------------------------------* * usbd_fs_isoc_schedule_init_sub * * This function initialises an USB FULL speed isochronous schedule Modified: head/sys/dev/usb/usb_hub.h ============================================================================== --- head/sys/dev/usb/usb_hub.h Sun Nov 22 21:16:30 2009 (r199671) +++ head/sys/dev/usb/usb_hub.h Sun Nov 22 21:16:43 2009 (r199672) @@ -66,8 +66,8 @@ struct usb_hub { /* function prototypes */ -uint8_t usb_intr_schedule_adjust(struct usb_device *udev, int16_t len, - uint8_t slot); +void usb_hs_bandwidth_alloc(struct usb_xfer *xfer); +void usb_hs_bandwidth_free(struct usb_xfer *xfer); void usbd_fs_isoc_schedule_init_all(struct usb_fs_isoc_schedule *fss); void usb_bus_port_set_device(struct usb_bus *bus, struct usb_port *up, struct usb_device *udev, uint8_t device_index); Modified: head/sys/dev/usb/usb_transfer.c ============================================================================== --- head/sys/dev/usb/usb_transfer.c Sun Nov 22 21:16:30 2009 (r199671) +++ head/sys/dev/usb/usb_transfer.c Sun Nov 22 21:16:43 2009 (r199672) @@ -942,10 +942,18 @@ usbd_transfer_setup(struct usb_device *u * configuration and alternate setting * when USB transfers are in use on * the given interface. Search the USB - * code for "endpoint->refcount" if you + * code for "endpoint->refcount_alloc" if you * want more information. */ - xfer->endpoint->refcount++; + USB_BUS_LOCK(info->bus); + if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX) + parm.err = USB_ERR_INVAL; + + xfer->endpoint->refcount_alloc++; + + if (xfer->endpoint->refcount_alloc == 0) + panic("usbd_transfer_setup(): Refcount wrapped to zero\n"); + USB_BUS_UNLOCK(info->bus); /* * Whenever we set ppxfer[] then we @@ -960,6 +968,10 @@ usbd_transfer_setup(struct usb_device *u */ ppxfer[n] = xfer; } + + /* check for error */ + if (parm.err) + goto done; } if (buf || parm.err) { @@ -1179,7 +1191,9 @@ usbd_transfer_unsetup(struct usb_xfer ** * NOTE: default endpoint does not have an * interface, even if endpoint->iface_index == 0 */ - xfer->endpoint->refcount--; + USB_BUS_LOCK(info->bus); + xfer->endpoint->refcount_alloc--; + USB_BUS_UNLOCK(info->bus); usb_callout_drain(&xfer->timeout_handle); Modified: head/sys/dev/usb/usbdi.h ============================================================================== --- head/sys/dev/usb/usbdi.h Sun Nov 22 21:16:30 2009 (r199671) +++ head/sys/dev/usb/usbdi.h Sun Nov 22 21:16:43 2009 (r199672) @@ -130,13 +130,22 @@ struct usb_endpoint { struct usb_pipe_methods *methods; /* set by HC driver */ uint16_t isoc_next; - uint16_t refcount; uint8_t toggle_next:1; /* next data toggle value */ uint8_t is_stalled:1; /* set if endpoint is stalled */ uint8_t is_synced:1; /* set if we a synchronised */ uint8_t unused:5; uint8_t iface_index; /* not used by "default endpoint" */ + + uint8_t refcount_alloc; /* allocation refcount */ + uint8_t refcount_bw; /* bandwidth refcount */ +#define USB_EP_REF_MAX 0x3f + + /* High-Speed resource allocation (valid if "refcount_bw" > 0) */ + + uint8_t usb_smask; /* USB start mask */ + uint8_t usb_cmask; /* USB complete mask */ + uint8_t usb_uframe; /* USB microframe */ }; /*