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
This commit is contained in:
parent
ca3f1187f1
commit
f12c6c2913
@ -2016,8 +2016,8 @@ ehci_setup_standard_chain(struct usb_xfer *xfer, ehci_qh_t **qh_last)
|
||||
|
||||
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, struct usb_xfer *xfer)
|
||||
|
||||
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 *xfer)
|
||||
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 *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 *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 *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_xfer *xfer)
|
||||
*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));
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -665,7 +665,7 @@ usb_config_parse(struct usb_device *udev, uint8_t iface_index, uint8_t cmd)
|
||||
/* 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.
|
||||
|
@ -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,22 +1183,156 @@ usb_intr_schedule_adjust(struct usb_device *udev, int16_t len, uint8_t slot)
|
||||
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
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -942,10 +942,18 @@ usbd_transfer_setup(struct usb_device *udev,
|
||||
* 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 *udev,
|
||||
*/
|
||||
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 **pxfer, uint16_t n_setup)
|
||||
* 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);
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user