Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 021ff6f7 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa: Fix to handle flow control during USB disconnect"

parents 3c904bfa c2f19de2
Loading
Loading
Loading
Loading
+21 −15
Original line number Diff line number Diff line
@@ -294,23 +294,25 @@ void ipa_flow_control(enum ipa_client_type ipa_client,
	/* Check if ep is valid. */
	ep_idx = ipa2_get_ep_mapping(ipa_client);
	if (ep_idx == -1) {
		IPAERR("Invalid IPA client\n");
		IPADBG("Invalid IPA client\n");
		return;
	}

	ep = &ipa_ctx->ep[ep_idx];
	if (!ep->valid) {
		IPAERR("EP not valid.\n");
	if (!ep->valid || (ep->client != IPA_CLIENT_USB_PROD)) {
		IPADBG("EP not valid/Not applicable for client.\n");
		return;
	}

	spin_lock(&ipa_ctx->disconnect_lock);
	/* Check if the QMAP_ID matches. */
	if (ep->cfg.meta.qmap_id != qmap_id) {
		IPADBG("Flow control indication not for the same flow: %u %u\n",
		IPADBG("Flow control ind not for same flow: %u %u\n",
			ep->cfg.meta.qmap_id, qmap_id);
		spin_unlock(&ipa_ctx->disconnect_lock);
		return;
	}

	if (!ep->disconnect_in_progress) {
		if (enable) {
			IPADBG("Enabling Flow\n");
			ep_ctrl.ipa_ep_delay = false;
@@ -322,6 +324,10 @@ void ipa_flow_control(enum ipa_client_type ipa_client,
		}
		ep_ctrl.ipa_ep_suspend = false;
		ipa2_cfg_ep_ctrl(ep_idx, &ep_ctrl);
	} else {
		IPADBG("EP disconnect is in progress\n");
	}
	spin_unlock(&ipa_ctx->disconnect_lock);
}

static void ipa_wan_msg_free_cb(void *buff, u32 len, u32 type)
@@ -2274,7 +2280,7 @@ static int ipa_setup_apps_pipes(void)
	 * thread may nullify it - e.g. on EP disconnect.
	 * This lock intended to protect the access to the source EP call-back
	 */
	spin_lock_init(&ipa_ctx->lan_rx_clnt_notify_lock);
	spin_lock_init(&ipa_ctx->disconnect_lock);
	if (ipa2_setup_sys_pipe(&sys_in, &ipa_ctx->clnt_hdl_data_in)) {
		IPAERR(":setup sys pipe failed.\n");
		result = -EPERM;
+14 −2
Original line number Diff line number Diff line
@@ -530,6 +530,7 @@ int ipa2_disconnect(u32 clnt_hdl)
	unsigned long peer_bam;
	unsigned long base;
	struct iommu_domain *smmu_domain;
	struct ipa_ep_cfg_ctrl ep_ctrl = {0};

	if (unlikely(!ipa_ctx)) {
		IPAERR("IPA driver was not initialized\n");
@@ -547,6 +548,11 @@ int ipa2_disconnect(u32 clnt_hdl)
	if (!ep->keep_ipa_awake)
		ipa_inc_client_enable_clks();

	/* Set Disconnect in Progress flag. */
	spin_lock(&ipa_ctx->disconnect_lock);
	ep->disconnect_in_progress = true;
	spin_unlock(&ipa_ctx->disconnect_lock);

	/* Notify uc to stop monitoring holb on USB BAM Producer pipe. */
	if (IPA_CLIENT_IS_USB_CONS(ep->client)) {
		ipa_uc_monitor_holb(ep->client, false);
@@ -630,9 +636,15 @@ int ipa2_disconnect(u32 clnt_hdl)

	ipa_delete_dflt_flt_rules(clnt_hdl);

	spin_lock(&ipa_ctx->lan_rx_clnt_notify_lock);
	spin_lock(&ipa_ctx->disconnect_lock);
	/* If flow is enabled/disabled at this point, we restore the ep state.*/
	if (ep->client == IPA_CLIENT_USB_PROD) {
		ep_ctrl.ipa_ep_delay = false;
		ep_ctrl.ipa_ep_suspend = false;
		ipa2_cfg_ep_ctrl(clnt_hdl, &ep_ctrl);
	}
	memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
	spin_unlock(&ipa_ctx->lan_rx_clnt_notify_lock);
	spin_unlock(&ipa_ctx->disconnect_lock);

	ipa_dec_client_disable_clks();

+3 −3
Original line number Diff line number Diff line
@@ -2372,13 +2372,13 @@ static int ipa_rx_pyld_hdlr(struct sk_buff *rx_skb, struct ipa_sys_context *sys)
		src_pipe = WLAN_PROD_TX_EP;

	ep = &ipa_ctx->ep[src_pipe];
	spin_lock(&ipa_ctx->lan_rx_clnt_notify_lock);
	spin_lock(&ipa_ctx->disconnect_lock);
	if (unlikely(src_pipe >= ipa_ctx->ipa_num_pipes ||
		!ep->valid || !ep->client_notify)) {
		IPAERR("drop pipe=%d ep_valid=%d client_notify=%p\n",
		  src_pipe, ep->valid, ep->client_notify);
		dev_kfree_skb_any(rx_skb);
		spin_unlock(&ipa_ctx->lan_rx_clnt_notify_lock);
		spin_unlock(&ipa_ctx->disconnect_lock);
		return 0;
	}

@@ -2397,7 +2397,7 @@ static int ipa_rx_pyld_hdlr(struct sk_buff *rx_skb, struct ipa_sys_context *sys)
	skb_pull(rx_skb, pull_len);
	ep->client_notify(ep->priv, IPA_RECEIVE,
			(unsigned long)(rx_skb));
	spin_unlock(&ipa_ctx->lan_rx_clnt_notify_lock);
	spin_unlock(&ipa_ctx->disconnect_lock);
	return 0;
}

+4 −2
Original line number Diff line number Diff line
@@ -504,6 +504,7 @@ struct ipa_wlan_comm_memb {
 *                          descriptors replenish function to be called to
 *                          avoid the RX pipe to run out of descriptors
 *                          and cause HOLB.
 * @disconnect_in_progress: Indicates client disconnect in progress.
 */
struct ipa_ep_context {
	int valid;
@@ -532,6 +533,7 @@ struct ipa_ep_context {
	struct ipa_wlan_stats wstats;
	u32 wdi_state;
	u32 rx_replenish_threshold;
	bool disconnect_in_progress;
	/* sys MUST be the last element of this struct */
	struct ipa_sys_context *sys;
};
@@ -1126,7 +1128,7 @@ struct ipacm_client_info {
 * @tag_process_before_gating: indicates whether to start tag process before
 *  gating IPA clocks
 * @sps_pm: sps power management related information
 * @lan_rx_clnt_notify_lock: protects LAN_CONS packet receive notification CB
 * @disconnect_lock: protects LAN_CONS packet receive notification CB
 * @pipe_mem_pool: pipe memory pool
 * @dma_pool: special purpose DMA pool
 * @ipa_active_clients: structure for reference counting connected IPA clients
@@ -1206,7 +1208,7 @@ struct ipa_context {
	u32 clnt_hdl_cmd;
	u32 clnt_hdl_data_in;
	u32 clnt_hdl_data_out;
	spinlock_t lan_rx_clnt_notify_lock;
	spinlock_t disconnect_lock;
	u8 a5_pipe_index;
	struct list_head intf_list;
	struct list_head msg_list;
+21 −15
Original line number Diff line number Diff line
@@ -293,23 +293,25 @@ void ipa3_flow_control(enum ipa_client_type ipa_client,
	/* Check if ep is valid. */
	ep_idx = ipa3_get_ep_mapping(ipa_client);
	if (ep_idx == -1) {
		IPAERR("Invalid IPA client\n");
		IPADBG("Invalid IPA client\n");
		return;
	}

	ep = &ipa3_ctx->ep[ep_idx];
	if (!ep->valid) {
		IPAERR("EP not valid.\n");
	if (!ep->valid || (ep->client != IPA_CLIENT_USB_PROD)) {
		IPADBG("EP not valid/Not applicable for client.\n");
		return;
	}

	spin_lock(&ipa3_ctx->disconnect_lock);
	/* Check if the QMAP_ID matches. */
	if (ep->cfg.meta.qmap_id != qmap_id) {
		IPADBG("Flow control indication not for the same flow: %u %u\n",
		IPADBG("Flow control ind not for same flow: %u %u\n",
			ep->cfg.meta.qmap_id, qmap_id);
		spin_unlock(&ipa3_ctx->disconnect_lock);
		return;
	}

	if (!ep->disconnect_in_progress) {
		if (enable) {
			IPADBG("Enabling Flow\n");
			ep_ctrl.ipa_ep_delay = false;
@@ -321,6 +323,10 @@ void ipa3_flow_control(enum ipa_client_type ipa_client,
		}
		ep_ctrl.ipa_ep_suspend = false;
		ipa3_cfg_ep_ctrl(ep_idx, &ep_ctrl);
	} else {
		IPADBG("EP disconnect is in progress\n");
	}
	spin_unlock(&ipa3_ctx->disconnect_lock);
}

static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type)
@@ -2453,7 +2459,7 @@ static int ipa3_setup_apps_pipes(void)
	 * thread may nullify it - e.g. on EP disconnect.
	 * This lock intended to protect the access to the source EP call-back
	 */
	spin_lock_init(&ipa3_ctx->lan_rx_clnt_notify_lock);
	spin_lock_init(&ipa3_ctx->disconnect_lock);
	if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_data_in)) {
		IPAERR(":setup sys pipe failed.\n");
		result = -EPERM;
Loading