From 17c684fdcd6152b7e504656b1711e24508c32f6e Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Fri, 8 May 2020 17:12:53 +0200 Subject: [PATCH 1/5] ch9getstatus/ep0_prime_status, fixes RND-28770 USB driver added the same req twice to the same list. This cause a endless loop while in IRQ context. Fix by importing code from mv_udc_core.c, its sister driver. Signed-off-by: Joakim Tjernlund --- drivers/usb/gadget/udc/fsl_udc_core.c | 56 ++++++++++----------------- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 367697144cda..2546bc28f42a 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1266,7 +1266,7 @@ static void ep0stall(struct fsl_udc *udc) } /* Prime a status phase for ep0 */ -static int ep0_prime_status(struct fsl_udc *udc, int direction) +static int ep0_prime_status(struct fsl_udc *udc, int direction, u16 status, bool empty) { struct fsl_req *req = udc->status_req; struct fsl_ep *ep; @@ -1281,8 +1281,14 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) if (udc->ep0_state != DATA_STATE_XMIT) udc->ep0_state = WAIT_FOR_OUT_STATUS; + /* fill in the reqest structure */ + if (empty == false) { + *((u16 *) req->req.buf) = cpu_to_le16(status); + req->req.length = 2; + } else + req->req.length = 0; + req->ep = ep; - req->req.length = 0; req->req.status = -EINPROGRESS; req->req.actual = 0; req->req.complete = fsl_noop_complete; @@ -1292,14 +1298,19 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) if (ret) return ret; + ret = -ENOMEM; if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0) fsl_queue_td(ep, req); else - return -ENOMEM; + goto out; list_add_tail(&req->queue, &ep->queue); return 0; +out: + usb_gadget_unmap_request(&udc->gadget, &req->req, ep_is_in(ep)); + + return ret; } static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) @@ -1320,7 +1331,7 @@ static void ch9setaddress(struct fsl_udc *udc, u16 value, u16 index, u16 length) /* Update usb state */ udc->usb_state = USB_STATE_ADDRESS; /* Status phase */ - if (ep0_prime_status(udc, EP_DIR_IN)) + if (ep0_prime_status(udc, EP_DIR_IN, 0, true)) ep0stall(udc); } @@ -1331,9 +1342,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, u16 index, u16 length) { u16 tmp = 0; /* Status, cpu endian */ - struct fsl_req *req; struct fsl_ep *ep; - int ret; ep = &udc->eps[0]; @@ -1358,33 +1367,10 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, << USB_ENDPOINT_HALT; } - udc->ep0_dir = USB_DIR_IN; - /* Borrow the per device status_req */ - req = udc->status_req; - /* Fill in the reqest structure */ - *((u16 *) req->req.buf) = cpu_to_le16(tmp); - - req->ep = ep; - req->req.length = 2; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = fsl_noop_complete; - req->dtd_count = 0; - - ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); - if (ret) - goto stall; - - /* prime the data phase */ - if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0)) - fsl_queue_td(ep, req); - else /* no mem */ - goto stall; - - list_add_tail(&req->queue, &ep->queue); - udc->ep0_state = DATA_STATE_XMIT; - if (ep0_prime_status(udc, EP_DIR_OUT)) + if (ep0_prime_status(udc, EP_DIR_OUT, tmp, false)) ep0stall(udc); + else + udc->ep0_state = DATA_STATE_XMIT; return; stall: @@ -1465,7 +1451,7 @@ __acquires(udc->lock) break; if (rc == 0) { - if (ep0_prime_status(udc, EP_DIR_IN)) + if (ep0_prime_status(udc, EP_DIR_IN, 0, true)) ep0stall(udc); } if (ptc) { @@ -1501,7 +1487,7 @@ __acquires(udc->lock) * See 2.0 Spec chapter 8.5.3.3 for detail. */ if (udc->ep0_state == DATA_STATE_XMIT) - if (ep0_prime_status(udc, EP_DIR_OUT)) + if (ep0_prime_status(udc, EP_DIR_OUT, 0, true)) ep0stall(udc); } else { @@ -1537,7 +1523,7 @@ static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0, break; case DATA_STATE_RECV: /* send status phase */ - if (ep0_prime_status(udc, EP_DIR_IN)) + if (ep0_prime_status(udc, EP_DIR_IN, 0, true)) ep0stall(udc); break; case WAIT_FOR_OUT_STATUS: -- 2.32.0