| From 4249d6fbc10fd997abdf8a1ea49c0389a0edf706 Mon Sep 17 00:00:00 2001 |
| From: Linyu Yuan <linyyuan@codeaurora.com> |
| Date: Wed, 16 Jun 2021 19:51:42 +0800 |
| Subject: usb: gadget: eem: fix echo command packet response issue |
| |
| From: Linyu Yuan <linyyuan@codeaurora.com> |
| |
| commit 4249d6fbc10fd997abdf8a1ea49c0389a0edf706 upstream. |
| |
| when receive eem echo command, it will send a response, |
| but queue this response to the usb request which allocate |
| from gadget device endpoint zero, |
| and transmit the request to IN endpoint of eem interface. |
| |
| on dwc3 gadget, it will trigger following warning in function |
| __dwc3_gadget_ep_queue(), |
| |
| if (WARN(req->dep != dep, "request %pK belongs to '%s'\n", |
| &req->request, req->dep->name)) |
| return -EINVAL; |
| |
| fix it by allocating a usb request from IN endpoint of eem interface, |
| and transmit the usb request to same IN endpoint of eem interface. |
| |
| Signed-off-by: Linyu Yuan <linyyuan@codeaurora.com> |
| Cc: stable <stable@vger.kernel.org> |
| Link: https://lore.kernel.org/r/20210616115142.34075-1-linyyuan@codeaurora.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/gadget/function/f_eem.c | 43 ++++++++++++++++++++++++++++++++---- |
| 1 file changed, 39 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/usb/gadget/function/f_eem.c |
| +++ b/drivers/usb/gadget/function/f_eem.c |
| @@ -30,6 +30,11 @@ struct f_eem { |
| u8 ctrl_id; |
| }; |
| |
| +struct in_context { |
| + struct sk_buff *skb; |
| + struct usb_ep *ep; |
| +}; |
| + |
| static inline struct f_eem *func_to_eem(struct usb_function *f) |
| { |
| return container_of(f, struct f_eem, port.func); |
| @@ -320,9 +325,12 @@ fail: |
| |
| static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req) |
| { |
| - struct sk_buff *skb = (struct sk_buff *)req->context; |
| + struct in_context *ctx = req->context; |
| |
| - dev_kfree_skb_any(skb); |
| + dev_kfree_skb_any(ctx->skb); |
| + kfree(req->buf); |
| + usb_ep_free_request(ctx->ep, req); |
| + kfree(ctx); |
| } |
| |
| /* |
| @@ -410,7 +418,9 @@ static int eem_unwrap(struct gether *por |
| * b15: bmType (0 == data, 1 == command) |
| */ |
| if (header & BIT(15)) { |
| - struct usb_request *req = cdev->req; |
| + struct usb_request *req; |
| + struct in_context *ctx; |
| + struct usb_ep *ep; |
| u16 bmEEMCmd; |
| |
| /* EEM command packet format: |
| @@ -439,11 +449,36 @@ static int eem_unwrap(struct gether *por |
| skb_trim(skb2, len); |
| put_unaligned_le16(BIT(15) | BIT(11) | len, |
| skb_push(skb2, 2)); |
| + |
| + ep = port->in_ep; |
| + req = usb_ep_alloc_request(ep, GFP_ATOMIC); |
| + if (!req) { |
| + dev_kfree_skb_any(skb2); |
| + goto next; |
| + } |
| + |
| + req->buf = kmalloc(skb2->len, GFP_KERNEL); |
| + if (!req->buf) { |
| + usb_ep_free_request(ep, req); |
| + dev_kfree_skb_any(skb2); |
| + goto next; |
| + } |
| + |
| + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); |
| + if (!ctx) { |
| + kfree(req->buf); |
| + usb_ep_free_request(ep, req); |
| + dev_kfree_skb_any(skb2); |
| + goto next; |
| + } |
| + ctx->skb = skb2; |
| + ctx->ep = ep; |
| + |
| skb_copy_bits(skb2, 0, req->buf, skb2->len); |
| req->length = skb2->len; |
| req->complete = eem_cmd_complete; |
| req->zero = 1; |
| - req->context = skb2; |
| + req->context = ctx; |
| if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC)) |
| DBG(cdev, "echo response queue fail\n"); |
| break; |