[{"id":1773270,"web_url":"http://patchwork.ozlabs.org/comment/1773270/","msgid":"<5eaaecae-e597-d760-1f1f-0c5d890db940@denx.de>","list_archive_url":null,"date":"2017-09-22T05:06:42","subject":"Re: [U-Boot] [PATCH 11/14] usb: xhci: Honor endpoint's interval","submitter":{"id":13,"url":"http://patchwork.ozlabs.org/api/people/13/","name":"Stefan Roese","email":"sr@denx.de"},"content":"On 18.09.2017 15:40, Bin Meng wrote:\n> USB endpoint reports the period between consecutive requests to send\n> or receive data as bInverval in its endpoint descriptor. So far this\n> is ignored by xHCI driver and the 'Interval' field in xHC's endpoint\n> context is always programmed to zero which means 1ms for low speed\n> or full speed , or 125us for high speed or super speed. We should\n> honor the interval by getting it from endpoint descriptor.\n> \n> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>\n> ---\n> \n>   drivers/usb/host/xhci.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++\n>   drivers/usb/host/xhci.h |   5 +-\n>   include/linux/usb/ch9.h |  20 +++++\n>   3 files changed, 218 insertions(+), 2 deletions(-)\n> \n> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c\n> index ec82fa6..8aed428 100644\n> --- a/drivers/usb/host/xhci.c\n> +++ b/drivers/usb/host/xhci.c\n> @@ -257,6 +257,172 @@ static unsigned int xhci_get_ep_index(struct usb_endpoint_descriptor *desc)\n>   \treturn index;\n>   }\n>   \n> +/*\n> + * Convert bInterval expressed in microframes (in 1-255 range) to exponent of\n> + * microframes, rounded down to nearest power of 2.\n> + */\n> +static unsigned int xhci_microframes_to_exponent(unsigned int desc_interval,\n> +\t\t\t\t\t\t unsigned int min_exponent,\n> +\t\t\t\t\t\t unsigned int max_exponent)\n> +{\n> +\tunsigned int interval;\n> +\n> +\tinterval = fls(desc_interval) - 1;\n> +\tinterval = clamp_val(interval, min_exponent, max_exponent);\n> +\tif ((1 << interval) != desc_interval)\n> +\t\tdebug(\"rounding interval to %d microframes, \"\\\n> +\t\t      \"ep desc says %d microframes\\n\",\n> +\t\t      1 << interval, desc_interval);\n> +\n> +\treturn interval;\n> +}\n> +\n> +static unsigned int xhci_parse_microframe_interval(struct usb_device *udev,\n> +\tstruct usb_endpoint_descriptor *endpt_desc)\n> +{\n> +\tif (endpt_desc->bInterval == 0)\n> +\t\treturn 0;\n> +\n> +\treturn xhci_microframes_to_exponent(endpt_desc->bInterval, 0, 15);\n> +}\n> +\n> +static unsigned int xhci_parse_frame_interval(struct usb_device *udev,\n> +\tstruct usb_endpoint_descriptor *endpt_desc)\n> +{\n> +\treturn xhci_microframes_to_exponent(endpt_desc->bInterval * 8, 3, 10);\n> +}\n> +\n> +/*\n> + * Convert interval expressed as 2^(bInterval - 1) == interval into\n> + * straight exponent value 2^n == interval.\n> + */\n> +static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,\n> +\tstruct usb_endpoint_descriptor *endpt_desc)\n> +{\n> +\tunsigned int interval;\n> +\n> +\tinterval = clamp_val(endpt_desc->bInterval, 1, 16) - 1;\n> +\tif (interval != endpt_desc->bInterval - 1)\n> +\t\tdebug(\"ep %#x - rounding interval to %d %sframes\\n\",\n> +\t\t      endpt_desc->bEndpointAddress, 1 << interval,\n> +\t\t      udev->speed == USB_SPEED_FULL ? \"\" : \"micro\");\n> +\n> +\tif (udev->speed == USB_SPEED_FULL) {\n> +\t\t/*\n> +\t\t * Full speed isoc endpoints specify interval in frames,\n> +\t\t * not microframes. We are using microframes everywhere,\n> +\t\t * so adjust accordingly.\n> +\t\t */\n> +\t\tinterval += 3;\t/* 1 frame = 2^3 uframes */\n> +\t}\n> +\n> +\treturn interval;\n> +}\n> +\n> +/*\n> + * Return the polling or NAK interval.\n> + *\n> + * The polling interval is expressed in \"microframes\". If xHCI's Interval field\n> + * is set to N, it will service the endpoint every 2^(Interval)*125us.\n> + *\n> + * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval\n> + * is set to 0.\n> + */\n> +static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,\n> +\tstruct usb_endpoint_descriptor *endpt_desc)\n> +{\n> +\tunsigned int interval = 0;\n> +\n> +\tswitch (udev->speed) {\n> +\tcase USB_SPEED_HIGH:\n> +\t\t/* Max NAK rate */\n> +\t\tif (usb_endpoint_xfer_control(endpt_desc) ||\n> +\t\t    usb_endpoint_xfer_bulk(endpt_desc)) {\n> +\t\t\tinterval = xhci_parse_microframe_interval(udev,\n> +\t\t\t\t\t\t\t\t  endpt_desc);\n> +\t\t\tbreak;\n> +\t\t}\n> +\t\t/* Fall through - SS and HS isoc/int have same decoding */\n> +\n> +\tcase USB_SPEED_SUPER:\n> +\t\tif (usb_endpoint_xfer_int(endpt_desc) ||\n> +\t\t    usb_endpoint_xfer_isoc(endpt_desc)) {\n> +\t\t\tinterval = xhci_parse_exponent_interval(udev,\n> +\t\t\t\t\t\t\t\tendpt_desc);\n> +\t\t}\n> +\t\tbreak;\n> +\n> +\tcase USB_SPEED_FULL:\n> +\t\tif (usb_endpoint_xfer_isoc(endpt_desc)) {\n> +\t\t\tinterval = xhci_parse_exponent_interval(udev,\n> +\t\t\t\t\t\t\t\tendpt_desc);\n> +\t\t\tbreak;\n> +\t\t}\n> +\t\t/*\n> +\t\t * Fall through for interrupt endpoint interval decoding\n> +\t\t * since it uses the same rules as low speed interrupt\n> +\t\t * endpoints.\n> +\t\t */\n> +\n> +\tcase USB_SPEED_LOW:\n> +\t\tif (usb_endpoint_xfer_int(endpt_desc) ||\n> +\t\t    usb_endpoint_xfer_isoc(endpt_desc)) {\n> +\t\t\tinterval = xhci_parse_frame_interval(udev, endpt_desc);\n> +\t\t}\n> +\t\tbreak;\n> +\n> +\tdefault:\n> +\t\tBUG();\n> +\t}\n> +\n> +\treturn interval;\n> +}\n> +\n> +/*\n> + * The \"Mult\" field in the endpoint context is only set for SuperSpeed isoc eps.\n> + * High speed endpoint descriptors can define \"the number of additional\n> + * transaction opportunities per microframe\", but that goes in the Max Burst\n> + * endpoint context field.\n> + */\n> +static u32 xhci_get_endpoint_mult(struct usb_device *udev,\n> +\tstruct usb_endpoint_descriptor *endpt_desc,\n> +\tstruct usb_ss_ep_comp_descriptor *ss_ep_comp_desc)\n> +{\n> +\tif (udev->speed < USB_SPEED_SUPER ||\n> +\t    !usb_endpoint_xfer_isoc(endpt_desc))\n> +\t\treturn 0;\n> +\n> +\treturn ss_ep_comp_desc->bmAttributes;\n> +}\n> +\n> +/*\n> + * Return the maximum endpoint service interval time (ESIT) payload.\n> + * Basically, this is the maxpacket size, multiplied by the burst size\n> + * and mult size.\n> + */\n> +static u32 xhci_get_max_esit_payload(struct usb_device *udev,\n> +\tstruct usb_endpoint_descriptor *endpt_desc,\n> +\tstruct usb_ss_ep_comp_descriptor *ss_ep_comp_desc)\n> +{\n> +\tint max_burst;\n> +\tint max_packet;\n> +\n> +\t/* Only applies for interrupt or isochronous endpoints */\n> +\tif (usb_endpoint_xfer_control(endpt_desc) ||\n> +\t    usb_endpoint_xfer_bulk(endpt_desc))\n> +\t\treturn 0;\n> +\n> +\t/* SuperSpeed Isoc ep with less than 48k per esit */\n> +\tif (udev->speed >= USB_SPEED_SUPER)\n> +\t\treturn le16_to_cpu(ss_ep_comp_desc->wBytesPerInterval);\n> +\n> +\tmax_packet = usb_endpoint_maxp(endpt_desc);\n> +\tmax_burst = usb_endpoint_maxp_mult(endpt_desc);\n> +\n> +\t/* A 0 in max burst means 1 transfer per ESIT */\n> +\treturn max_packet * max_burst;\n> +}\n> +\n>   /**\n>    * Issue a configure endpoint command or evaluate context command\n>    * and wait for it to finish.\n> @@ -324,6 +490,10 @@ static int xhci_set_configuration(struct usb_device *udev)\n>   \tint slot_id = udev->slot_id;\n>   \tstruct xhci_virt_device *virt_dev = ctrl->devs[slot_id];\n>   \tstruct usb_interface *ifdesc;\n> +\tu32 max_esit_payload;\n> +\tunsigned int interval;\n> +\tunsigned int mult;\n> +\tunsigned int avg_trb_len;\n>   \n>   \tout_ctx = virt_dev->out_ctx;\n>   \tin_ctx = virt_dev->in_ctx;\n> @@ -357,10 +527,26 @@ static int xhci_set_configuration(struct usb_device *udev)\n>   \t/* filling up ep contexts */\n>   \tfor (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) {\n>   \t\tstruct usb_endpoint_descriptor *endpt_desc = NULL;\n> +\t\tstruct usb_ss_ep_comp_descriptor *ss_ep_comp_desc = NULL;\n>   \n>   \t\tendpt_desc = &ifdesc->ep_desc[cur_ep];\n> +\t\tss_ep_comp_desc = &ifdesc->ss_ep_comp_desc[cur_ep];\n>   \t\ttrb_64 = 0;\n>   \n> +\t\t/*\n> +\t\t * Get values to fill the endpoint context, mostly from ep\n> +\t\t * descriptor. The average TRB buffer lengt for bulk endpoints\n> +\t\t * is unclear as we have no clue on scatter gather list entry\n> +\t\t * size. For Isoc and Int, set it to max available.\n> +\t\t * See xHCI 1.1 spec 4.14.1.1 for details.\n> +\t\t */\n> +\t\tmax_esit_payload = xhci_get_max_esit_payload(udev, endpt_desc,\n> +\t\t\t\t\t\t\t     ss_ep_comp_desc);\n> +\t\tinterval = xhci_get_endpoint_interval(udev, endpt_desc);\n> +\t\tmult = xhci_get_endpoint_mult(udev, endpt_desc,\n> +\t\t\t\t\t      ss_ep_comp_desc);\n> +\t\tavg_trb_len = max_esit_payload;\n> +\n>   \t\tep_index = xhci_get_ep_index(endpt_desc);\n>   \t\tep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);\n>   \n> @@ -372,6 +558,11 @@ static int xhci_set_configuration(struct usb_device *udev)\n>   \t\t/*NOTE: ep_desc[0] actually represents EP1 and so on */\n>   \t\tdir = (((endpt_desc->bEndpointAddress) & (0x80)) >> 7);\n>   \t\tep_type = (((endpt_desc->bmAttributes) & (0x3)) | (dir << 2));\n> +\n> +\t\tep_ctx[ep_index]->ep_info =\n> +\t\t\tcpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |\n> +\t\t\tEP_INTERVAL(interval) | EP_MULT(mult));\n> +\n>   \t\tep_ctx[ep_index]->ep_info2 =\n>   \t\t\tcpu_to_le32(ep_type << EP_TYPE_SHIFT);\n>   \t\tep_ctx[ep_index]->ep_info2 |=\n> @@ -386,6 +577,10 @@ static int xhci_set_configuration(struct usb_device *udev)\n>   \t\t\t\tvirt_dev->eps[ep_index].ring->enqueue;\n>   \t\tep_ctx[ep_index]->deq = cpu_to_le64(trb_64 |\n>   \t\t\t\tvirt_dev->eps[ep_index].ring->cycle_state);\n> +\n> +\t\tep_ctx[ep_index]->tx_info =\n> +\t\t\tcpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |\n> +\t\t\tEP_AVG_TRB_LENGTH(avg_trb_len));\n>   \t}\n>   \n>   \treturn xhci_configure_endpoints(udev, false);\n> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h\n> index a497d9d..6deefbf 100644\n> --- a/drivers/usb/host/xhci.h\n> +++ b/drivers/usb/host/xhci.h\n> @@ -663,8 +663,9 @@ struct xhci_ep_ctx {\n>   #define GET_MAX_PACKET(p)\t((p) & 0x7ff)\n>   \n>   /* tx_info bitmasks */\n> -#define AVG_TRB_LENGTH_FOR_EP(p)\t((p) & 0xffff)\n> -#define MAX_ESIT_PAYLOAD_FOR_EP(p)\t(((p) & 0xffff) << 16)\n> +#define EP_AVG_TRB_LENGTH(p)\t\t((p) & 0xffff)\n> +#define EP_MAX_ESIT_PAYLOAD_LO(p)\t(((p) & 0xffff) << 16)\n> +#define EP_MAX_ESIT_PAYLOAD_HI(p)\t((((p) >> 16) & 0xff) << 24)\n>   #define CTX_TO_MAX_ESIT_PAYLOAD(p)\t(((p) >> 16) & 0xffff)\n>   \n>   /* deq bitmasks */\n> diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h\n> index 0ad4782..264c971 100644\n> --- a/include/linux/usb/ch9.h\n> +++ b/include/linux/usb/ch9.h\n> @@ -418,6 +418,12 @@ struct __packed usb_class_report_descriptor {\n>   #define USB_ENDPOINT_XFER_INT\t\t3\n>   #define USB_ENDPOINT_MAX_ADJUSTABLE\t0x80\n>   \n> +#define USB_ENDPOINT_MAXP_MASK\t\t0x07ff\n> +#define USB_EP_MAXP_MULT_SHIFT\t\t11\n> +#define USB_EP_MAXP_MULT_MASK\t\t(3 << USB_EP_MAXP_MULT_SHIFT)\n> +#define USB_EP_MAXP_MULT(m)\t\t\\\n> +\t(((m) & USB_EP_MAXP_MULT_MASK) >> USB_EP_MAXP_MULT_SHIFT)\n> +\n>   /* The USB 3.0 spec redefines bits 5:4 of bmAttributes as interrupt ep type. */\n>   #define USB_ENDPOINT_INTRTYPE\t\t0x30\n>   #define USB_ENDPOINT_INTR_PERIODIC\t(0 << 4)\n> @@ -625,6 +631,20 @@ static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)\n>   \treturn __le16_to_cpu(get_unaligned(&epd->wMaxPacketSize));\n>   }\n>   \n> +/**\n> + * usb_endpoint_maxp_mult - get endpoint's transactional opportunities\n> + * @epd: endpoint to be checked\n> + *\n> + * Return @epd's wMaxPacketSize[12:11] + 1\n> + */\n> +static inline int\n> +usb_endpoint_maxp_mult(const struct usb_endpoint_descriptor *epd)\n> +{\n> +\tint maxp = __le16_to_cpu(epd->wMaxPacketSize);\n> +\n> +\treturn USB_EP_MAXP_MULT(maxp) + 1;\n> +}\n> +\n>   static inline int usb_endpoint_interrupt_type(\n>   \t\tconst struct usb_endpoint_descriptor *epd)\n>   {\n> \n\nReviewed-by: Stefan Roese <sr@denx.de>\nTested-by: Stefan Roese <sr@denx.de>\n\nThanks,\nStefan","headers":{"Return-Path":"<u-boot-bounces@lists.denx.de>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":"ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.denx.de\n\t(client-ip=81.169.180.215; helo=lists.denx.de;\n\tenvelope-from=u-boot-bounces@lists.denx.de;\n\treceiver=<UNKNOWN>)","Received":["from lists.denx.de (dione.denx.de [81.169.180.215])\n\tby ozlabs.org (Postfix) with ESMTP id 3xz1g25gCdz9sPm\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 22 Sep 2017 15:06:54 +1000 (AEST)","by lists.denx.de (Postfix, from userid 105)\n\tid 853FFC21F49; Fri, 22 Sep 2017 05:06:52 +0000 (UTC)","from lists.denx.de (localhost [IPv6:::1])\n\tby lists.denx.de (Postfix) with ESMTP id CC3B6C21C62;\n\tFri, 22 Sep 2017 05:06:47 +0000 (UTC)","by lists.denx.de (Postfix, from userid 105)\n\tid B3AF1C21C29; Fri, 22 Sep 2017 05:06:45 +0000 (UTC)","from mx1.mailbox.org (mx1.mailbox.org [80.241.60.212])\n\tby lists.denx.de (Postfix) with ESMTPS id 68C77C21C26\n\tfor <u-boot@lists.denx.de>; Fri, 22 Sep 2017 05:06:45 +0000 (UTC)","from smtp1.mailbox.org (smtp1.mailbox.org [80.241.60.240])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby mx1.mailbox.org (Postfix) with ESMTPS id 4502545ADA;\n\tFri, 22 Sep 2017 07:06:45 +0200 (CEST)","from smtp1.mailbox.org ([80.241.60.240])\n\tby spamfilter02.heinlein-hosting.de (spamfilter02.heinlein-hosting.de\n\t[80.241.56.116]) (amavisd-new, port 10030)\n\twith ESMTP id FerxSgDuH61R; Fri, 22 Sep 2017 07:06:43 +0200 (CEST)"],"X-Spam-Checker-Version":"SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de","X-Spam-Level":"","X-Spam-Status":"No, score=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW\n\tautolearn=unavailable autolearn_force=no version=3.4.0","X-Virus-Scanned":"amavisd-new at heinlein-support.de","To":"Bin Meng <bmeng.cn@gmail.com>, Marek Vasut <marex@denx.de>,\n\tU-Boot Mailing List <u-boot@lists.denx.de>","References":"<1505742050-5697-1-git-send-email-bmeng.cn@gmail.com>\n\t<1505742050-5697-12-git-send-email-bmeng.cn@gmail.com>","From":"Stefan Roese <sr@denx.de>","Message-ID":"<5eaaecae-e597-d760-1f1f-0c5d890db940@denx.de>","Date":"Fri, 22 Sep 2017 07:06:42 +0200","MIME-Version":"1.0","In-Reply-To":"<1505742050-5697-12-git-send-email-bmeng.cn@gmail.com>","Content-Language":"en-US","Subject":"Re: [U-Boot] [PATCH 11/14] usb: xhci: Honor endpoint's interval","X-BeenThere":"u-boot@lists.denx.de","X-Mailman-Version":"2.1.18","Precedence":"list","List-Id":"U-Boot discussion <u-boot.lists.denx.de>","List-Unsubscribe":"<https://lists.denx.de/options/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=unsubscribe>","List-Archive":"<http://lists.denx.de/pipermail/u-boot/>","List-Post":"<mailto:u-boot@lists.denx.de>","List-Help":"<mailto:u-boot-request@lists.denx.de?subject=help>","List-Subscribe":"<https://lists.denx.de/listinfo/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=subscribe>","Content-Transfer-Encoding":"base64","Content-Type":"text/plain; charset=\"utf-8\"; Format=\"flowed\"","Errors-To":"u-boot-bounces@lists.denx.de","Sender":"\"U-Boot\" <u-boot-bounces@lists.denx.de>"}}]