From 98b639fc503e16cffa902d3ab89b29b9b5dcbf57 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 1 Oct 2017 06:19:36 -0700 Subject: usb: emul: Remove maxpacketsize in usb_emul_setup_device() This parameter is never used. Signed-off-by: Bin Meng --- include/usb.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/usb.h b/include/usb.h index 0ddc0822b41..1563c9abf3c 100644 --- a/include/usb.h +++ b/include/usb.h @@ -976,7 +976,6 @@ int usb_get_max_xfer_size(struct usb_device *dev, size_t *size); * the USB emulation uclass about the features of the emulator. * * @dev: Emulation device - * @maxpacketsize: Maximum packet size (e.g. PACKET_SIZE_64) * @strings: List of USB string descriptors, terminated by a NULL * entry * @desc_list: List of points or USB descriptors, terminated by NULL. @@ -984,8 +983,8 @@ int usb_get_max_xfer_size(struct usb_device *dev, size_t *size); * and others follow on after that. * @return 0 if OK, -ENOSYS if not implemented, other -ve on error */ -int usb_emul_setup_device(struct udevice *dev, int maxpacketsize, - struct usb_string *strings, void **desc_list); +int usb_emul_setup_device(struct udevice *dev, struct usb_string *strings, + void **desc_list); /** * usb_emul_control() - Send a control packet to an emulator -- cgit v1.3.1 From 8d36c6874173918612495b8e5925a7000ed8058e Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 1 Oct 2017 06:19:37 -0700 Subject: usb: Fix comments of usb_emul_find_for_dev() There is no such a parameter called 'bus'. Signed-off-by: Bin Meng --- include/usb.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/usb.h b/include/usb.h index 1563c9abf3c..3d517316e5b 100644 --- a/include/usb.h +++ b/include/usb.h @@ -1035,7 +1035,6 @@ int usb_emul_find(struct udevice *bus, ulong pipe, struct udevice **emulp); /** * usb_emul_find_for_dev() - Find an emulator for a particular device * - * @bus: USB bus (controller) * @dev: USB device to check * @emulp: Returns pointer to emulator, or NULL if not found * @return 0 if found, -ve on error -- cgit v1.3.1 From 84aa8536f0197e439832f56cc7b554af488fc3c8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 1 Oct 2017 06:19:39 -0700 Subject: usb: sandbox: Fix emulator device select logic in usb_emul_find_devnum() Current emulator select logic in usb_emul_find_devnum() is to test the USB address. The USB address of the device being enumerated is initialized to zero at the beginning of the enumeration process in usb_setup_device(). At this point, the saved USB address in the platform data has not been assigned to any valid USB address either. This means: the logic will select an emulator device according to its sequence of declaring order in the device tree. Take test.dts for example, flash-stick@0 will be selected before flash-stick@1. But unfortunately such logic is wrong. In fact USB devices show up in a random order during the enumeration which means usb_emul_find_devnum() may be called on port 3 for keyb@3 before on port 0 for flash-stick@0. To fix this, we introduce a new emulator uclass specific platdata to store the USB device's port number on its parent hub, and update the logic to test the port number instead. Signed-off-by: Bin Meng --- drivers/usb/emul/sandbox_hub.c | 2 ++ drivers/usb/emul/usb-emul-uclass.c | 42 +++++++++++++++++++++++++++++++++----- drivers/usb/host/usb-sandbox.c | 6 +++--- include/usb.h | 18 ++++++++++++++-- 4 files changed, 58 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/usb/emul/sandbox_hub.c b/drivers/usb/emul/sandbox_hub.c index 9ed700036e0..8ed7a0f4345 100644 --- a/drivers/usb/emul/sandbox_hub.c +++ b/drivers/usb/emul/sandbox_hub.c @@ -280,8 +280,10 @@ static int sandbox_hub_bind(struct udevice *dev) static int sandbox_child_post_bind(struct udevice *dev) { struct sandbox_hub_platdata *plat = dev_get_parent_platdata(dev); + struct usb_emul_platdata *emul = dev_get_uclass_platdata(dev); plat->port = dev_read_u32_default(dev, "reg", -1); + emul->port1 = plat->port + 1; return 0; } diff --git a/drivers/usb/emul/usb-emul-uclass.c b/drivers/usb/emul/usb-emul-uclass.c index e4a267bf00a..1203eb2f11a 100644 --- a/drivers/usb/emul/usb-emul-uclass.c +++ b/drivers/usb/emul/usb-emul-uclass.c @@ -107,7 +107,7 @@ static int usb_emul_get_descriptor(struct usb_dev_platdata *plat, int value, return upto ? upto : length ? -EIO : 0; } -static int usb_emul_find_devnum(int devnum, struct udevice **emulp) +static int usb_emul_find_devnum(int devnum, int port1, struct udevice **emulp) { struct udevice *dev; struct uclass *uc; @@ -120,7 +120,37 @@ static int usb_emul_find_devnum(int devnum, struct udevice **emulp) uclass_foreach_dev(dev, uc) { struct usb_dev_platdata *udev = dev_get_parent_platdata(dev); - if (udev->devnum == devnum) { + /* + * devnum is initialzied to zero at the beginning of the + * enumeration process in usb_setup_device(). At this + * point, udev->devnum has not been assigned to any valid + * USB address either, so we can't rely on the comparison + * result between udev->devnum and devnum to select an + * emulator device. + */ + if (!devnum) { + struct usb_emul_platdata *plat; + + /* + * If the parent is sandbox USB controller, we are + * the root hub. And there is only one root hub + * in the system. + */ + if (device_get_uclass_id(dev->parent) == UCLASS_USB) { + debug("%s: Found emulator '%s'\n", + __func__, dev->name); + *emulp = dev; + return 0; + } + + plat = dev_get_uclass_platdata(dev); + if (plat->port1 == port1) { + debug("%s: Found emulator '%s', port %d\n", + __func__, dev->name, port1); + *emulp = dev; + return 0; + } + } else if (udev->devnum == devnum) { debug("%s: Found emulator '%s', addr %d\n", __func__, dev->name, udev->devnum); *emulp = dev; @@ -132,18 +162,19 @@ static int usb_emul_find_devnum(int devnum, struct udevice **emulp) return -ENOENT; } -int usb_emul_find(struct udevice *bus, ulong pipe, struct udevice **emulp) +int usb_emul_find(struct udevice *bus, ulong pipe, int port1, + struct udevice **emulp) { int devnum = usb_pipedevice(pipe); - return usb_emul_find_devnum(devnum, emulp); + return usb_emul_find_devnum(devnum, port1, emulp); } int usb_emul_find_for_dev(struct udevice *dev, struct udevice **emulp) { struct usb_dev_platdata *udev = dev_get_parent_platdata(dev); - return usb_emul_find_devnum(udev->devnum, emulp); + return usb_emul_find_devnum(udev->devnum, 0, emulp); } int usb_emul_control(struct udevice *emul, struct usb_device *udev, @@ -276,6 +307,7 @@ UCLASS_DRIVER(usb_emul) = { .id = UCLASS_USB_EMUL, .name = "usb_emul", .post_bind = dm_scan_fdt_dev, + .per_device_platdata_auto_alloc_size = sizeof(struct usb_emul_platdata), .per_child_auto_alloc_size = sizeof(struct usb_device), .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata), }; diff --git a/drivers/usb/host/usb-sandbox.c b/drivers/usb/host/usb-sandbox.c index f85d36ba429..15055b351a5 100644 --- a/drivers/usb/host/usb-sandbox.c +++ b/drivers/usb/host/usb-sandbox.c @@ -50,7 +50,7 @@ static int sandbox_submit_control(struct udevice *bus, /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, setup, emul); if (ret) return ret; @@ -83,7 +83,7 @@ static int sandbox_submit_bulk(struct udevice *bus, struct usb_device *udev, /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, NULL, emul); if (ret) return ret; @@ -109,7 +109,7 @@ static int sandbox_submit_int(struct udevice *bus, struct usb_device *udev, /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, NULL, emul); if (ret) return ret; diff --git a/include/usb.h b/include/usb.h index 3d517316e5b..63eddddc914 100644 --- a/include/usb.h +++ b/include/usb.h @@ -652,6 +652,18 @@ struct usb_bus_priv { bool companion; }; +/** + * struct usb_emul_platdata - platform data about the USB emulator + * + * Given a USB emulator (UCLASS_USB_EMUL) 'dev', this is + * dev_get_uclass_platdata(dev). + * + * @port1: USB emulator device port number on the parent hub + */ +struct usb_emul_platdata { + int port1; /* Port number (numbered from 1) */ +}; + /** * struct dm_usb_ops - USB controller operations * @@ -1023,14 +1035,16 @@ int usb_emul_int(struct udevice *emul, struct usb_device *udev, /** * usb_emul_find() - Find an emulator for a particular device * - * Check @pipe to find a device number on bus @bus and return it. + * Check @pipe and @port1 to find a device number on bus @bus and return it. * * @bus: USB bus (controller) * @pipe: Describes pipe being used, and includes the device number + * @port1: Describes port number on the parent hub * @emulp: Returns pointer to emulator, or NULL if not found * @return 0 if found, -ve on error */ -int usb_emul_find(struct udevice *bus, ulong pipe, struct udevice **emulp); +int usb_emul_find(struct udevice *bus, ulong pipe, int port1, + struct udevice **emulp); /** * usb_emul_find_for_dev() - Find an emulator for a particular device -- cgit v1.3.1 From 848436a48d21447fc78bef67a4cbf11392536de2 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 1 Oct 2017 06:19:40 -0700 Subject: usb: emul: Expose find_descriptor() as a public API This can be useful outside of the sandbox usb emulation uclass driver. Expose it as a public API with a proper prefix (usb_emul_). Signed-off-by: Bin Meng --- drivers/usb/emul/usb-emul-uclass.c | 5 ++--- include/usb.h | 11 +++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/usb/emul/usb-emul-uclass.c b/drivers/usb/emul/usb-emul-uclass.c index 1203eb2f11a..359d0da07e6 100644 --- a/drivers/usb/emul/usb-emul-uclass.c +++ b/drivers/usb/emul/usb-emul-uclass.c @@ -52,7 +52,7 @@ static int usb_emul_get_string(struct usb_string *strings, int index, return -EINVAL; } -static struct usb_generic_descriptor **find_descriptor( +struct usb_generic_descriptor **usb_emul_find_descriptor( struct usb_generic_descriptor **ptr, int type, int index) { debug("%s: type=%x, index=%d\n", __func__, type, index); @@ -91,8 +91,7 @@ static int usb_emul_get_descriptor(struct usb_dev_platdata *plat, int value, length); } - ptr = find_descriptor((struct usb_generic_descriptor **)plat->desc_list, - type, index); + ptr = usb_emul_find_descriptor(plat->desc_list, type, index); if (!ptr) { debug("%s: Could not find descriptor type %d, index %d\n", __func__, type, index); diff --git a/include/usb.h b/include/usb.h index 63eddddc914..37665146359 100644 --- a/include/usb.h +++ b/include/usb.h @@ -1055,6 +1055,17 @@ int usb_emul_find(struct udevice *bus, ulong pipe, int port1, */ int usb_emul_find_for_dev(struct udevice *dev, struct udevice **emulp); +/** + * usb_emul_find_descriptor() - Find a USB descriptor of a particular device + * + * @ptr: a pointer to a list of USB descriptor pointers + * @type: type of USB descriptor to find + * @index: if @type is USB_DT_CONFIG, this is the configuration value + * @return a pointer to the USB descriptor found, NULL if not found + */ +struct usb_generic_descriptor **usb_emul_find_descriptor( + struct usb_generic_descriptor **ptr, int type, int index); + /** * usb_emul_reset() - Reset all emulators ready for use * -- cgit v1.3.1 From ad56e4b684a97565cdce15c28df1ccff9032d594 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 1 Oct 2017 06:19:44 -0700 Subject: dm: usb: emul: Drop usb_emul_reset() With the root hub unbinding in usb_stop(), there is no need to do a Sandbox-specific reset operation. usb_emul_reset() is no longer used anywhere, drop it. Signed-off-by: Bin Meng --- drivers/usb/emul/usb-emul-uclass.c | 8 -------- drivers/usb/host/usb-uclass.c | 11 ----------- include/usb.h | 8 -------- 3 files changed, 27 deletions(-) (limited to 'include') diff --git a/drivers/usb/emul/usb-emul-uclass.c b/drivers/usb/emul/usb-emul-uclass.c index 359d0da07e6..fbe11f31353 100644 --- a/drivers/usb/emul/usb-emul-uclass.c +++ b/drivers/usb/emul/usb-emul-uclass.c @@ -294,14 +294,6 @@ int usb_emul_setup_device(struct udevice *dev, struct usb_string *strings, return 0; } -void usb_emul_reset(struct udevice *dev) -{ - struct usb_dev_platdata *plat = dev_get_parent_platdata(dev); - - plat->devnum = 0; - plat->configno = 0; -} - UCLASS_DRIVER(usb_emul) = { .id = UCLASS_USB_EMUL, .name = "usb_emul", diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index bfc0556d7d6..4e40f4bc3d2 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -194,17 +194,6 @@ int usb_stop(void) } } -#ifdef CONFIG_SANDBOX - struct udevice *dev; - - /* Reset all enulation devices */ - ret = uclass_get(UCLASS_USB_EMUL, &uc); - if (ret) - return ret; - - uclass_foreach_dev(dev, uc) - usb_emul_reset(dev); -#endif #ifdef CONFIG_USB_STORAGE usb_stor_reset(); #endif diff --git a/include/usb.h b/include/usb.h index 37665146359..57a7d8d0ea3 100644 --- a/include/usb.h +++ b/include/usb.h @@ -1066,14 +1066,6 @@ int usb_emul_find_for_dev(struct udevice *dev, struct udevice **emulp); struct usb_generic_descriptor **usb_emul_find_descriptor( struct usb_generic_descriptor **ptr, int type, int index); -/** - * usb_emul_reset() - Reset all emulators ready for use - * - * Clear out any address information in the emulators and make then ready for - * a new USB scan - */ -void usb_emul_reset(struct udevice *dev); - /** * usb_show_tree() - show the USB device tree * -- cgit v1.3.1 From f51966bf7afe44151756e9a2432705bb56bc2007 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 18 Sep 2017 06:40:47 -0700 Subject: usb: xhci: Honor endpoint's interval USB endpoint reports the period between consecutive requests to send or receive data as bInverval in its endpoint descriptor. So far this is ignored by xHCI driver and the 'Interval' field in xHC's endpoint context is always programmed to zero which means 1ms for low speed or full speed , or 125us for high speed or super speed. We should honor the interval by getting it from endpoint descriptor. Signed-off-by: Bin Meng --- drivers/usb/host/xhci.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 5 +- include/linux/usb/ch9.h | 20 +++++ 3 files changed, 218 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index ec82fa664e1..8aed4283edb 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -257,6 +257,172 @@ static unsigned int xhci_get_ep_index(struct usb_endpoint_descriptor *desc) return index; } +/* + * Convert bInterval expressed in microframes (in 1-255 range) to exponent of + * microframes, rounded down to nearest power of 2. + */ +static unsigned int xhci_microframes_to_exponent(unsigned int desc_interval, + unsigned int min_exponent, + unsigned int max_exponent) +{ + unsigned int interval; + + interval = fls(desc_interval) - 1; + interval = clamp_val(interval, min_exponent, max_exponent); + if ((1 << interval) != desc_interval) + debug("rounding interval to %d microframes, "\ + "ep desc says %d microframes\n", + 1 << interval, desc_interval); + + return interval; +} + +static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + if (endpt_desc->bInterval == 0) + return 0; + + return xhci_microframes_to_exponent(endpt_desc->bInterval, 0, 15); +} + +static unsigned int xhci_parse_frame_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + return xhci_microframes_to_exponent(endpt_desc->bInterval * 8, 3, 10); +} + +/* + * Convert interval expressed as 2^(bInterval - 1) == interval into + * straight exponent value 2^n == interval. + */ +static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + unsigned int interval; + + interval = clamp_val(endpt_desc->bInterval, 1, 16) - 1; + if (interval != endpt_desc->bInterval - 1) + debug("ep %#x - rounding interval to %d %sframes\n", + endpt_desc->bEndpointAddress, 1 << interval, + udev->speed == USB_SPEED_FULL ? "" : "micro"); + + if (udev->speed == USB_SPEED_FULL) { + /* + * Full speed isoc endpoints specify interval in frames, + * not microframes. We are using microframes everywhere, + * so adjust accordingly. + */ + interval += 3; /* 1 frame = 2^3 uframes */ + } + + return interval; +} + +/* + * Return the polling or NAK interval. + * + * The polling interval is expressed in "microframes". If xHCI's Interval field + * is set to N, it will service the endpoint every 2^(Interval)*125us. + * + * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval + * is set to 0. + */ +static unsigned int xhci_get_endpoint_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + unsigned int interval = 0; + + switch (udev->speed) { + case USB_SPEED_HIGH: + /* Max NAK rate */ + if (usb_endpoint_xfer_control(endpt_desc) || + usb_endpoint_xfer_bulk(endpt_desc)) { + interval = xhci_parse_microframe_interval(udev, + endpt_desc); + break; + } + /* Fall through - SS and HS isoc/int have same decoding */ + + case USB_SPEED_SUPER: + if (usb_endpoint_xfer_int(endpt_desc) || + usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_exponent_interval(udev, + endpt_desc); + } + break; + + case USB_SPEED_FULL: + if (usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_exponent_interval(udev, + endpt_desc); + break; + } + /* + * Fall through for interrupt endpoint interval decoding + * since it uses the same rules as low speed interrupt + * endpoints. + */ + + case USB_SPEED_LOW: + if (usb_endpoint_xfer_int(endpt_desc) || + usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_frame_interval(udev, endpt_desc); + } + break; + + default: + BUG(); + } + + return interval; +} + +/* + * The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps. + * High speed endpoint descriptors can define "the number of additional + * transaction opportunities per microframe", but that goes in the Max Burst + * endpoint context field. + */ +static u32 xhci_get_endpoint_mult(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc, + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc) +{ + if (udev->speed < USB_SPEED_SUPER || + !usb_endpoint_xfer_isoc(endpt_desc)) + return 0; + + return ss_ep_comp_desc->bmAttributes; +} + +/* + * Return the maximum endpoint service interval time (ESIT) payload. + * Basically, this is the maxpacket size, multiplied by the burst size + * and mult size. + */ +static u32 xhci_get_max_esit_payload(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc, + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc) +{ + int max_burst; + int max_packet; + + /* Only applies for interrupt or isochronous endpoints */ + if (usb_endpoint_xfer_control(endpt_desc) || + usb_endpoint_xfer_bulk(endpt_desc)) + return 0; + + /* SuperSpeed Isoc ep with less than 48k per esit */ + if (udev->speed >= USB_SPEED_SUPER) + return le16_to_cpu(ss_ep_comp_desc->wBytesPerInterval); + + max_packet = usb_endpoint_maxp(endpt_desc); + max_burst = usb_endpoint_maxp_mult(endpt_desc); + + /* A 0 in max burst means 1 transfer per ESIT */ + return max_packet * max_burst; +} + /** * Issue a configure endpoint command or evaluate context command * and wait for it to finish. @@ -324,6 +490,10 @@ static int xhci_set_configuration(struct usb_device *udev) int slot_id = udev->slot_id; struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; struct usb_interface *ifdesc; + u32 max_esit_payload; + unsigned int interval; + unsigned int mult; + unsigned int avg_trb_len; out_ctx = virt_dev->out_ctx; in_ctx = virt_dev->in_ctx; @@ -357,10 +527,26 @@ static int xhci_set_configuration(struct usb_device *udev) /* filling up ep contexts */ for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) { struct usb_endpoint_descriptor *endpt_desc = NULL; + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc = NULL; endpt_desc = &ifdesc->ep_desc[cur_ep]; + ss_ep_comp_desc = &ifdesc->ss_ep_comp_desc[cur_ep]; trb_64 = 0; + /* + * Get values to fill the endpoint context, mostly from ep + * descriptor. The average TRB buffer lengt for bulk endpoints + * is unclear as we have no clue on scatter gather list entry + * size. For Isoc and Int, set it to max available. + * See xHCI 1.1 spec 4.14.1.1 for details. + */ + max_esit_payload = xhci_get_max_esit_payload(udev, endpt_desc, + ss_ep_comp_desc); + interval = xhci_get_endpoint_interval(udev, endpt_desc); + mult = xhci_get_endpoint_mult(udev, endpt_desc, + ss_ep_comp_desc); + avg_trb_len = max_esit_payload; + ep_index = xhci_get_ep_index(endpt_desc); ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index); @@ -372,6 +558,11 @@ static int xhci_set_configuration(struct usb_device *udev) /*NOTE: ep_desc[0] actually represents EP1 and so on */ dir = (((endpt_desc->bEndpointAddress) & (0x80)) >> 7); ep_type = (((endpt_desc->bmAttributes) & (0x3)) | (dir << 2)); + + ep_ctx[ep_index]->ep_info = + cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) | + EP_INTERVAL(interval) | EP_MULT(mult)); + ep_ctx[ep_index]->ep_info2 = cpu_to_le32(ep_type << EP_TYPE_SHIFT); ep_ctx[ep_index]->ep_info2 |= @@ -386,6 +577,10 @@ static int xhci_set_configuration(struct usb_device *udev) virt_dev->eps[ep_index].ring->enqueue; ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 | virt_dev->eps[ep_index].ring->cycle_state); + + ep_ctx[ep_index]->tx_info = + cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) | + EP_AVG_TRB_LENGTH(avg_trb_len)); } return xhci_configure_endpoints(udev, false); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3377450fcad..ba5f650144f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -663,8 +663,9 @@ struct xhci_ep_ctx { #define GET_MAX_PACKET(p) ((p) & 0x7ff) /* tx_info bitmasks */ -#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff) -#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16) +#define EP_AVG_TRB_LENGTH(p) ((p) & 0xffff) +#define EP_MAX_ESIT_PAYLOAD_LO(p) (((p) & 0xffff) << 16) +#define EP_MAX_ESIT_PAYLOAD_HI(p) ((((p) >> 16) & 0xff) << 24) #define CTX_TO_MAX_ESIT_PAYLOAD(p) (((p) >> 16) & 0xffff) /* deq bitmasks */ diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index 0ad4782a36e..264c9712a33 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -418,6 +418,12 @@ struct __packed usb_class_report_descriptor { #define USB_ENDPOINT_XFER_INT 3 #define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 +#define USB_ENDPOINT_MAXP_MASK 0x07ff +#define USB_EP_MAXP_MULT_SHIFT 11 +#define USB_EP_MAXP_MULT_MASK (3 << USB_EP_MAXP_MULT_SHIFT) +#define USB_EP_MAXP_MULT(m) \ + (((m) & USB_EP_MAXP_MULT_MASK) >> USB_EP_MAXP_MULT_SHIFT) + /* The USB 3.0 spec redefines bits 5:4 of bmAttributes as interrupt ep type. */ #define USB_ENDPOINT_INTRTYPE 0x30 #define USB_ENDPOINT_INTR_PERIODIC (0 << 4) @@ -625,6 +631,20 @@ static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd) return __le16_to_cpu(get_unaligned(&epd->wMaxPacketSize)); } +/** + * usb_endpoint_maxp_mult - get endpoint's transactional opportunities + * @epd: endpoint to be checked + * + * Return @epd's wMaxPacketSize[12:11] + 1 + */ +static inline int +usb_endpoint_maxp_mult(const struct usb_endpoint_descriptor *epd) +{ + int maxp = __le16_to_cpu(epd->wMaxPacketSize); + + return USB_EP_MAXP_MULT(maxp) + 1; +} + static inline int usb_endpoint_interrupt_type( const struct usb_endpoint_descriptor *epd) { -- cgit v1.3.1