From 9490c68a6ff98b1624b48d348a17301af7ea5968 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Tue, 11 Jun 2019 19:26:35 +0530 Subject: [PATCH] usb: f_gsi: Don't enable IPA data path if connect channel fails ipa_connect_channels can return failure if gsi prepare trbs fail or start xfer fails. But currently driver is not checking for the failure and goes ahead to enable IPA data path. This leads the controller to access faulty addresses which cause kernel panic. Fix this by checking the failure returned from ipa_connect_channels. Also cleanup the error handling path. Change-Id: Ia1e8e17381e12231d8d78224ba3b07081f143212 Signed-off-by: Pratham Pratap --- drivers/usb/gadget/function/f_gsi.c | 45 +++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 24d9bdec1f5c..d33993b96c82 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -496,7 +496,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) if (ret) { log_event_err("%s: GSI_EP_OP_STARTXFER failed: %d\n", __func__, ret); - return ret; + goto free_trb_ep_in; } d_port->in_xfer_rsc_index = usb_gsi_ep_op(d_port->in_ep, NULL, @@ -546,7 +546,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) if (ret) { log_event_err("%s: GSI_EP_OP_PREPARE_TRBS failed: %d\n", __func__, ret); - return ret; + goto end_xfer_ep_in; } ret = usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, @@ -554,7 +554,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) if (ret) { log_event_err("%s: GSI_EP_OP_STARTXFER failed: %d\n", __func__, ret); - return ret; + goto free_trb_ep_out; } d_port->out_xfer_rsc_index = @@ -632,7 +632,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) conn_params); if (ret) { log_event_err("%s: IPA connect failed %d", __func__, ret); - return ret; + goto end_xfer_ep_out; } log_event_dbg("%s: xdci_connect done", __func__); @@ -660,6 +660,23 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) d_port->out_request.db_reg_phs_addr_msb = ipa_out_channel_out_params.db_reg_phs_addr_msb; } + + return ret; + +end_xfer_ep_out: + if (d_port->out_ep) + usb_gsi_ep_op(d_port->out_ep, NULL, + GSI_EP_OP_ENDXFER); +free_trb_ep_out: + if (d_port->out_ep) + usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, + GSI_EP_OP_FREE_TRBS); +end_xfer_ep_in: + usb_gsi_ep_op(d_port->in_ep, NULL, + GSI_EP_OP_ENDXFER); +free_trb_ep_in: + usb_gsi_ep_op(d_port->in_ep, &d_port->in_request, + GSI_EP_OP_FREE_TRBS); return ret; } @@ -907,7 +924,16 @@ static void ipa_work_handler(struct work_struct *w) break; } - ipa_connect_channels(d_port); + ret = ipa_connect_channels(d_port); + if (ret) { + log_event_err("%s: ipa_connect_channels failed\n", + __func__); + ipa_data_path_disable(d_port); + usb_gadget_autopm_put_async(d_port->gadget); + d_port->sm_state = STATE_INITIALIZED; + break; + } + d_port->sm_state = STATE_WAIT_FOR_IPA_RDY; log_event_dbg("%s: ST_INIT_EVT_SET_ALT", __func__); @@ -1046,7 +1072,14 @@ static void ipa_work_handler(struct work_struct *w) log_event_dbg("%s: get = %d", __func__, atomic_read(&gad_dev->power.usage_count)); - ipa_connect_channels(d_port); + ret = ipa_connect_channels(d_port); + if (ret) { + log_event_err("%s: ipa_connect_channels failed\n", + __func__); + usb_gadget_autopm_put_async(d_port->gadget); + break; + } + ipa_data_path_enable(d_port); d_port->sm_state = STATE_CONNECTED; log_event_dbg("%s: ST_HOST_NRDY_EVT_HRDY_", __func__);