Merge "USB: gadget: u_data_ipa: Handle usb requests allocation/free correctly"
This commit is contained in:
commit
9bb2912be3
1 changed files with 157 additions and 55 deletions
|
@ -93,12 +93,17 @@ static void ipa_data_endless_complete(struct usb_ep *ep,
|
|||
*/
|
||||
static void ipa_data_start_endless_xfer(struct ipa_data_ch_info *port, bool in)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status;
|
||||
|
||||
if (!port->port_usb) {
|
||||
pr_err("%s(): port_usb is NULL.\n", __func__);
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
if (!port->port_usb || (in && !port->tx_req)
|
||||
|| (!in && !port->rx_req)) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
pr_err("%s(): port_usb/req is NULL.\n", __func__);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
||||
if (in) {
|
||||
pr_debug("%s: enqueue endless TX_REQ(IN)\n", __func__);
|
||||
|
@ -125,12 +130,17 @@ static void ipa_data_start_endless_xfer(struct ipa_data_ch_info *port, bool in)
|
|||
*/
|
||||
static void ipa_data_stop_endless_xfer(struct ipa_data_ch_info *port, bool in)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status;
|
||||
|
||||
if (!port->port_usb) {
|
||||
pr_err("%s(): port_usb is NULL.\n", __func__);
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
if (!port->port_usb || (in && !port->tx_req)
|
||||
|| (!in && !port->rx_req)) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
pr_err("%s(): port_usb/req is NULL.\n", __func__);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
||||
if (in) {
|
||||
pr_debug("%s: dequeue endless TX_REQ(IN)\n", __func__);
|
||||
|
@ -253,6 +263,8 @@ static void ipa_data_disconnect_work(struct work_struct *w)
|
|||
usb_bam_free_fifos(port->usb_bam_type,
|
||||
port->src_connection_idx);
|
||||
|
||||
if (port->func_type == USB_IPA_FUNC_RMNET)
|
||||
teth_bridge_disconnect(port->ipa_params.src_client);
|
||||
/*
|
||||
* Decrement usage count which was incremented
|
||||
* upon cable connect or cable disconnect in suspended state.
|
||||
|
@ -313,6 +325,11 @@ void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func)
|
|||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
usb_ep_disable(port->port_usb->in);
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
if (port->tx_req) {
|
||||
usb_ep_free_request(port->port_usb->in,
|
||||
port->tx_req);
|
||||
port->tx_req = NULL;
|
||||
}
|
||||
port->port_usb->in->endless = false;
|
||||
}
|
||||
|
||||
|
@ -321,6 +338,11 @@ void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func)
|
|||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
usb_ep_disable(port->port_usb->out);
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
if (port->rx_req) {
|
||||
usb_ep_free_request(port->port_usb->out,
|
||||
port->rx_req);
|
||||
port->rx_req = NULL;
|
||||
}
|
||||
port->port_usb->out->endless = false;
|
||||
}
|
||||
|
||||
|
@ -367,6 +389,8 @@ static void ipa_data_connect_work(struct work_struct *w)
|
|||
connect_w);
|
||||
struct gadget_ipa_port *gport;
|
||||
struct usb_gadget *gadget = NULL;
|
||||
struct teth_bridge_connect_params connect_params;
|
||||
struct teth_bridge_init_params teth_bridge_params;
|
||||
u32 sps_params;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
@ -407,34 +431,7 @@ static void ipa_data_connect_work(struct work_struct *w)
|
|||
gport->ipa_consumer_ep = -1;
|
||||
gport->ipa_producer_ep = -1;
|
||||
|
||||
if (gport->out) {
|
||||
port->rx_req = usb_ep_alloc_request(gport->out, GFP_ATOMIC);
|
||||
if (!port->rx_req) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
pr_err("%s: failed to allocate rx_req\n", __func__);
|
||||
return;
|
||||
}
|
||||
port->rx_req->context = port;
|
||||
port->rx_req->complete = ipa_data_endless_complete;
|
||||
port->rx_req->length = 0;
|
||||
port->rx_req->no_interrupt = 1;
|
||||
}
|
||||
|
||||
if (gport->in) {
|
||||
port->tx_req = usb_ep_alloc_request(gport->in, GFP_ATOMIC);
|
||||
if (!port->tx_req) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
pr_err("%s: failed to allocate tx_req\n", __func__);
|
||||
goto free_rx_req;
|
||||
}
|
||||
port->tx_req->context = port;
|
||||
port->tx_req->complete = ipa_data_endless_complete;
|
||||
port->tx_req->length = 0;
|
||||
port->tx_req->no_interrupt = 1;
|
||||
}
|
||||
|
||||
port->is_connected = true;
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
||||
/* update IPA Parameteres here. */
|
||||
port->ipa_params.usb_connection_speed = gadget->speed;
|
||||
|
@ -445,11 +442,12 @@ static void ipa_data_connect_work(struct work_struct *w)
|
|||
port->ipa_params.cons_clnt_hdl = -1;
|
||||
port->ipa_params.prod_clnt_hdl = -1;
|
||||
|
||||
|
||||
if (gport->out) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
usb_bam_alloc_fifos(port->usb_bam_type,
|
||||
port->src_connection_idx);
|
||||
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
sps_params = MSM_SPS_MODE | MSM_DISABLE_WB
|
||||
| MSM_PRODUCER | port->src_pipe_idx;
|
||||
port->rx_req->length = 32*1024;
|
||||
|
@ -460,15 +458,18 @@ static void ipa_data_connect_work(struct work_struct *w)
|
|||
ret = msm_ep_config(gport->out, port->rx_req);
|
||||
if (ret) {
|
||||
pr_err("msm_ep_config() failed for OUT EP\n");
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
usb_bam_free_fifos(port->usb_bam_type,
|
||||
port->src_connection_idx);
|
||||
goto free_rx_tx_req;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (gport->in) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
usb_bam_alloc_fifos(port->usb_bam_type,
|
||||
port->dst_connection_idx);
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
sps_params = MSM_SPS_MODE | MSM_DISABLE_WB |
|
||||
port->dst_pipe_idx;
|
||||
port->tx_req->length = 32*1024;
|
||||
|
@ -478,10 +479,21 @@ static void ipa_data_connect_work(struct work_struct *w)
|
|||
ret = msm_ep_config(gport->in, port->tx_req);
|
||||
if (ret) {
|
||||
pr_err("msm_ep_config() failed for IN EP\n");
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
goto unconfig_msm_ep_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (port->func_type == USB_IPA_FUNC_RMNET) {
|
||||
teth_bridge_params.client = port->ipa_params.src_client;
|
||||
ret = teth_bridge_init(&teth_bridge_params);
|
||||
if (ret) {
|
||||
pr_err("%s:teth_bridge_init() failed\n", __func__);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
goto unconfig_msm_ep_in;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform below operations for Tx from Device (OUT transfer)
|
||||
* 1. Connect with pipe of USB BAM with IPA BAM pipe
|
||||
|
@ -498,17 +510,35 @@ static void ipa_data_connect_work(struct work_struct *w)
|
|||
port->ipa_params.priv = rndis_qc_get_ipa_priv();
|
||||
port->ipa_params.skip_ep_cfg =
|
||||
rndis_qc_get_skip_ep_config();
|
||||
} else if (port->func_type == USB_IPA_FUNC_RMNET) {
|
||||
port->ipa_params.notify =
|
||||
teth_bridge_params.usb_notify_cb;
|
||||
port->ipa_params.priv =
|
||||
teth_bridge_params.private_data;
|
||||
port->ipa_params.reset_pipe_after_lpm =
|
||||
msm_dwc3_reset_ep_after_lpm(gadget);
|
||||
port->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
|
||||
port->ipa_params.skip_ep_cfg =
|
||||
teth_bridge_params.skip_ep_cfg;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
ret = usb_bam_connect_ipa(port->usb_bam_type,
|
||||
&port->ipa_params);
|
||||
if (ret) {
|
||||
pr_err("usb_bam_connect_ipa out failed err:%d\n", ret);
|
||||
goto unconfig_msm_ep_in;
|
||||
goto disconnect_usb_bam_ipa_out;
|
||||
}
|
||||
|
||||
gport->ipa_consumer_ep = port->ipa_params.ipa_cons_ep_idx;
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
is_ipa_disconnected = false;
|
||||
/* check if USB cable is disconnected or not */
|
||||
if (!port->port_usb) {
|
||||
pr_debug("%s:%d: cable is disconnected.\n",
|
||||
__func__, __LINE__);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
goto disconnect_usb_bam_ipa_out;
|
||||
}
|
||||
gport->ipa_consumer_ep = port->ipa_params.ipa_cons_ep_idx;
|
||||
}
|
||||
|
||||
if (gport->in) {
|
||||
|
@ -520,22 +550,41 @@ static void ipa_data_connect_work(struct work_struct *w)
|
|||
port->ipa_params.priv = rndis_qc_get_ipa_priv();
|
||||
port->ipa_params.skip_ep_cfg =
|
||||
rndis_qc_get_skip_ep_config();
|
||||
} else if (port->func_type == USB_IPA_FUNC_RMNET) {
|
||||
port->ipa_params.notify =
|
||||
teth_bridge_params.usb_notify_cb;
|
||||
port->ipa_params.priv =
|
||||
teth_bridge_params.private_data;
|
||||
port->ipa_params.reset_pipe_after_lpm =
|
||||
msm_dwc3_reset_ep_after_lpm(gadget);
|
||||
port->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
|
||||
port->ipa_params.skip_ep_cfg =
|
||||
teth_bridge_params.skip_ep_cfg;
|
||||
}
|
||||
|
||||
if (port->func_type == USB_IPA_FUNC_DPL)
|
||||
port->ipa_params.dst_client = IPA_CLIENT_USB_DPL_CONS;
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
ret = usb_bam_connect_ipa(port->usb_bam_type,
|
||||
&port->ipa_params);
|
||||
if (ret) {
|
||||
pr_err("usb_bam_connect_ipa IN failed err:%d\n", ret);
|
||||
goto disconnect_usb_bam_ipa_out;
|
||||
}
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
/* check if USB cable is disconnected or not */
|
||||
if (!port->port_usb) {
|
||||
pr_debug("%s:%d: cable is disconnected.\n",
|
||||
__func__, __LINE__);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
goto disconnect_usb_bam_ipa_out;
|
||||
}
|
||||
|
||||
gport->ipa_producer_ep = port->ipa_params.ipa_prod_ep_idx;
|
||||
is_ipa_disconnected = false;
|
||||
}
|
||||
|
||||
/* For DPL need to update_ipa_pipes to qti */
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
if (port->func_type == USB_IPA_FUNC_RNDIS) {
|
||||
rndis_data->prod_clnt_hdl =
|
||||
port->ipa_params.prod_clnt_hdl;
|
||||
|
@ -563,11 +612,28 @@ static void ipa_data_connect_work(struct work_struct *w)
|
|||
return;
|
||||
}
|
||||
atomic_set(&port->pipe_connect_notified, 1);
|
||||
} else {
|
||||
/* For RmNet and DPL need to update_ipa_pipes to qti */
|
||||
enum qti_port_type qti_port_type = port->func_type ==
|
||||
USB_IPA_FUNC_RMNET ? QTI_PORT_RMNET : QTI_PORT_DPL;
|
||||
gqti_ctrl_update_ipa_pipes(port->port_usb, qti_port_type,
|
||||
gport->ipa_producer_ep, gport->ipa_consumer_ep);
|
||||
}
|
||||
|
||||
if (port->func_type == USB_IPA_FUNC_RMNET) {
|
||||
gqti_ctrl_update_ipa_pipes(port->port_usb, QTI_PORT_RMNET,
|
||||
gport->ipa_producer_ep, gport->ipa_consumer_ep);
|
||||
connect_params.ipa_usb_pipe_hdl =
|
||||
port->ipa_params.prod_clnt_hdl;
|
||||
connect_params.usb_ipa_pipe_hdl =
|
||||
port->ipa_params.cons_clnt_hdl;
|
||||
connect_params.tethering_mode =
|
||||
TETH_TETHERING_MODE_RMNET;
|
||||
connect_params.client_type =
|
||||
port->ipa_params.src_client;
|
||||
ret = teth_bridge_connect(&connect_params);
|
||||
if (ret) {
|
||||
pr_err("%s:teth_bridge_connect() failed\n", __func__);
|
||||
goto disconnect_usb_bam_ipa_out;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("ipa_producer_ep:%d ipa_consumer_ep:%d\n",
|
||||
|
@ -598,26 +664,27 @@ disconnect_usb_bam_ipa_out:
|
|||
is_ipa_disconnected = true;
|
||||
}
|
||||
unconfig_msm_ep_in:
|
||||
if (gport->in)
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
/* check if USB cable is disconnected or not */
|
||||
if (port->port_usb && gport->in)
|
||||
msm_ep_unconfig(port->port_usb->in);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
unconfig_msm_ep_out:
|
||||
if (gport->in)
|
||||
usb_bam_free_fifos(port->usb_bam_type,
|
||||
port->dst_connection_idx);
|
||||
if (gport->out) {
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
/* check if USB cable is disconnected or not */
|
||||
if (port->port_usb && gport->out) {
|
||||
msm_ep_unconfig(port->port_usb->out);
|
||||
usb_bam_free_fifos(port->usb_bam_type,
|
||||
port->src_connection_idx);
|
||||
}
|
||||
free_rx_tx_req:
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
out:
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
port->is_connected = false;
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
if (gport->in && port->tx_req)
|
||||
usb_ep_free_request(gport->in, port->tx_req);
|
||||
free_rx_req:
|
||||
if (gport->out && port->rx_req)
|
||||
usb_ep_free_request(gport->out, port->rx_req);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -658,6 +725,31 @@ int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
|
|||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
port->port_usb = gp;
|
||||
port->gadget = gp->cdev->gadget;
|
||||
|
||||
if (gp->out) {
|
||||
port->rx_req = usb_ep_alloc_request(gp->out, GFP_ATOMIC);
|
||||
if (!port->rx_req) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
pr_err("%s: failed to allocate rx_req\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
port->rx_req->context = port;
|
||||
port->rx_req->complete = ipa_data_endless_complete;
|
||||
port->rx_req->length = 0;
|
||||
port->rx_req->no_interrupt = 1;
|
||||
}
|
||||
|
||||
if (gp->in) {
|
||||
port->tx_req = usb_ep_alloc_request(gp->in, GFP_ATOMIC);
|
||||
if (!port->tx_req) {
|
||||
pr_err("%s: failed to allocate tx_req\n", __func__);
|
||||
goto free_rx_req;
|
||||
}
|
||||
port->tx_req->context = port;
|
||||
port->tx_req->complete = ipa_data_endless_complete;
|
||||
port->tx_req->length = 0;
|
||||
port->tx_req->no_interrupt = 1;
|
||||
}
|
||||
port->src_connection_idx = src_connection_idx;
|
||||
port->dst_connection_idx = dst_connection_idx;
|
||||
port->usb_bam_type = usb_bam_get_bam_type(gp->cdev->gadget->name);
|
||||
|
@ -679,6 +771,8 @@ int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
|
|||
if (ret) {
|
||||
pr_err("usb_ep_enable failed eptype:IN ep:%p",
|
||||
port->port_usb->in);
|
||||
usb_ep_free_request(port->port_usb->in, port->tx_req);
|
||||
port->tx_req = NULL;
|
||||
port->port_usb->in->endless = false;
|
||||
goto err_usb_in;
|
||||
}
|
||||
|
@ -690,21 +784,18 @@ int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
|
|||
if (ret) {
|
||||
pr_err("usb_ep_enable failed eptype:OUT ep:%p",
|
||||
port->port_usb->out);
|
||||
usb_ep_free_request(port->port_usb->out, port->rx_req);
|
||||
port->rx_req = NULL;
|
||||
port->port_usb->out->endless = false;
|
||||
goto err_usb_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!port->port_usb->out && !port->port_usb->in) {
|
||||
pr_err("%s(): No USB endpoint enabled.\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto err_usb_in;
|
||||
}
|
||||
|
||||
/* Wait for host to enable flow_control */
|
||||
if (port->func_type == USB_IPA_FUNC_RNDIS) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
ret = 0;
|
||||
goto err_usb_in;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -720,9 +811,20 @@ int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
|
|||
return ret;
|
||||
|
||||
err_usb_out:
|
||||
if (port->port_usb->in)
|
||||
if (port->port_usb->in) {
|
||||
usb_ep_disable(port->port_usb->in);
|
||||
port->port_usb->in->endless = false;
|
||||
}
|
||||
err_usb_in:
|
||||
if (gp->in && port->tx_req) {
|
||||
usb_ep_free_request(gp->in, port->tx_req);
|
||||
port->tx_req = NULL;
|
||||
}
|
||||
free_rx_req:
|
||||
if (gp->out && port->rx_req) {
|
||||
usb_ep_free_request(gp->out, port->rx_req);
|
||||
port->rx_req = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
err:
|
||||
pr_debug("%s(): failed with error:%d\n", __func__, ret);
|
||||
|
|
Loading…
Add table
Reference in a new issue