@@ -27,6 +27,12 @@
#define TPG_INSTANCES 1
+/*
+ * Timeout value in msecs passed as an argument to usb_ep_queue_timeout() for
+ * stream capable endpoints
+ */
+#define STREAM_TIMEOUT_MS 50
+
struct tpg_instance {
struct usb_function_instance *func_inst;
struct usbg_tpg *tpg;
@@ -575,7 +581,8 @@ static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
ret = uasp_prepare_r_request(cmd);
if (ret)
goto cleanup;
- ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ ret = usb_ep_queue_timeout(fu->ep_in, stream->req_in,
+ GFP_ATOMIC, STREAM_TIMEOUT_MS);
if (ret)
pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
break;
@@ -584,15 +591,16 @@ static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
ret = usbg_prepare_w_request(cmd, stream->req_out);
if (ret)
goto cleanup;
- ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ ret = usb_ep_queue_timeout(fu->ep_out, stream->req_out,
+ GFP_ATOMIC, STREAM_TIMEOUT_MS);
if (ret)
pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
break;
case UASP_SEND_STATUS:
uasp_prepare_status(cmd);
- ret = usb_ep_queue(fu->ep_status, stream->req_status,
- GFP_ATOMIC);
+ ret = usb_ep_queue_timeout(fu->ep_status, stream->req_status,
+ GFP_ATOMIC, STREAM_TIMEOUT_MS);
if (ret)
pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
break;
@@ -622,7 +630,8 @@ static int uasp_send_status_response(struct usbg_cmd *cmd)
stream->req_status->context = cmd;
cmd->fu = fu;
uasp_prepare_status(cmd);
- return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
+ return usb_ep_queue_timeout(fu->ep_status, stream->req_status,
+ GFP_ATOMIC, STREAM_TIMEOUT_MS);
}
static int uasp_send_read_response(struct usbg_cmd *cmd)
@@ -640,7 +649,8 @@ static int uasp_send_read_response(struct usbg_cmd *cmd)
ret = uasp_prepare_r_request(cmd);
if (ret)
goto out;
- ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ ret = usb_ep_queue_timeout(fu->ep_in, stream->req_in,
+ GFP_ATOMIC, STREAM_TIMEOUT_MS);
if (ret) {
pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
kfree(cmd->data_buf);
@@ -686,7 +696,8 @@ static int uasp_send_write_request(struct usbg_cmd *cmd)
ret = usbg_prepare_w_request(cmd, stream->req_out);
if (ret)
goto cleanup;
- ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ ret = usb_ep_queue_timeout(fu->ep_out, stream->req_out,
+ GFP_ATOMIC, STREAM_TIMEOUT_MS);
if (ret)
pr_err("%s(%d)\n", __func__, __LINE__);
When stream transfers are enabled for an endpoint, there can be a condition where the gadget controller waits for the host to issue prime transaction and the host controller waits for the gadget to issue ERDY. This condition could create a deadlock. To avoid such potential deadlocks, use usb_ep_queue_timeout() instead of usb_ep_queue() for stream capable endpoints. The usb_ep_queue_timeout(), after queuing any request starts the timer with STREAM_TIMEOUT_MS timeout value for the stream capable endpoints. The gadget controller driver is expected to stop the timer for every request if a valid stream event is found. If no stream event is found, the timer expires after the STREAM_TIMEOUT_MS value and a callback function registered by udc/core.c is called, which handles the deadlock situation by dequeuing and requeuing the request. This kind of behaviour is observed in dwc3 controller and expected to be generic issue with other controllers supporting bulk streams. Signed-off-by: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> --- Changes in v7: 1. This patch is newly added in this series --- drivers/usb/gadget/function/f_tcm.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)