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

Commit fb83b036 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa: fix race condition between USB connect and modem SSR"

parents ee06631b 5c82c7d3
Loading
Loading
Loading
Loading
+49 −25
Original line number Original line Diff line number Diff line
@@ -375,12 +375,6 @@ struct ipa_mpm_mhi_driver {
	bool init_complete;
	bool init_complete;
	/* General MPM mutex to protect concurrent update of MPM GSI states */
	/* General MPM mutex to protect concurrent update of MPM GSI states */
	struct mutex mutex;
	struct mutex mutex;
	/*
	 * Mutex to protect IPA clock vote/unvote to make sure IPA isn't double
	 * devoted for concurrency scenarios such as SSR and LPM mode CB
	 * concurrency.
	 */
	struct mutex lpm_mutex;
	/*
	/*
	 * Mutex to protect mhi_dev update/ access, for concurrency such as
	 * Mutex to protect mhi_dev update/ access, for concurrency such as
	 * 5G SSR and USB disconnect/connect.
	 * 5G SSR and USB disconnect/connect.
@@ -1357,7 +1351,6 @@ static void ipa_mpm_mhip_shutdown(int mhip_idx)


	ipa_mpm_clean_mhip_chan(mhip_idx, dl_cons_chan);
	ipa_mpm_clean_mhip_chan(mhip_idx, dl_cons_chan);


	mutex_lock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex);
	if (!ipa_mpm_ctx->md[mhip_idx].in_lpm) {
	if (!ipa_mpm_ctx->md[mhip_idx].in_lpm) {
		ipa_mpm_vote_unvote_ipa_clk(CLK_OFF, mhip_idx);
		ipa_mpm_vote_unvote_ipa_clk(CLK_OFF, mhip_idx);
		/* while in modem shutdown scenarios such as SSR, no explicit
		/* while in modem shutdown scenarios such as SSR, no explicit
@@ -1365,10 +1358,8 @@ static void ipa_mpm_mhip_shutdown(int mhip_idx)
		 */
		 */
		ipa_mpm_ctx->md[mhip_idx].in_lpm = true;
		ipa_mpm_ctx->md[mhip_idx].in_lpm = true;
	}
	}
	mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex);
	mutex_lock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
	mutex_lock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
	ipa_mpm_ctx->md[mhip_idx].mhi_dev = NULL;
	ipa_mpm_ctx->md[mhip_idx].mhi_dev = NULL;
	ipa_mpm_ctx->md[mhip_idx].init_complete = false;
	mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
	mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
	IPA_MPM_FUNC_EXIT();
	IPA_MPM_FUNC_EXIT();
}
}
@@ -1399,6 +1390,18 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
		return 0;
		return 0;
	}
	}


	if (!ipa_mpm_ctx->md[probe_id].init_complete) {
		/*
		 * SSR might be in progress, dont have to vote/unvote for
		 * IPA clocks as it will be taken care in remove_cb/subsequent
		 * probe.
		 */
		IPA_MPM_DBG("SSR in progress, return\n");
		mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
		return 0;
	}
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);

	IPA_MPM_ERR("PCIe clock vote/unvote = %d probe_id = %d clk_cnt = %d\n",
	IPA_MPM_ERR("PCIe clock vote/unvote = %d probe_id = %d clk_cnt = %d\n",
		vote, probe_id,
		vote, probe_id,
		atomic_read(&ipa_mpm_ctx->md[probe_id].clk_cnt.pcie_clk_cnt));
		atomic_read(&ipa_mpm_ctx->md[probe_id].clk_cnt.pcie_clk_cnt));
@@ -1409,7 +1412,6 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
		if (result) {
		if (result) {
			IPA_MPM_ERR("mhi_sync_get failed for probe_id %d\n",
			IPA_MPM_ERR("mhi_sync_get failed for probe_id %d\n",
				result, probe_id);
				result, probe_id);
			mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
			return result;
			return result;
		}
		}


@@ -1423,7 +1425,6 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
			IPA_MPM_DBG("probe_id %d PCIE clock already devoted\n",
			IPA_MPM_DBG("probe_id %d PCIE clock already devoted\n",
				probe_id);
				probe_id);
			WARN_ON(1);
			WARN_ON(1);
			mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
			return 0;
			return 0;
		}
		}
		mhi_device_put(ipa_mpm_ctx->md[probe_id].mhi_dev, MHI_VOTE_BUS);
		mhi_device_put(ipa_mpm_ctx->md[probe_id].mhi_dev, MHI_VOTE_BUS);
@@ -1431,8 +1432,6 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
		atomic_dec(&ipa_mpm_ctx->md[probe_id].clk_cnt.pcie_clk_cnt);
		atomic_dec(&ipa_mpm_ctx->md[probe_id].clk_cnt.pcie_clk_cnt);
		atomic_dec(&ipa_mpm_ctx->pcie_clk_total_cnt);
		atomic_dec(&ipa_mpm_ctx->pcie_clk_total_cnt);
	}
	}

	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	return result;
	return result;
}
}


@@ -1482,11 +1481,9 @@ static int ipa_mpm_start_stop_remote_mhip_chan(
		return ret;
		return ret;
	}
	}


	mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	/* For error state, expect modem SSR to recover from error */
	/* For error state, expect modem SSR to recover from error */
	if (ipa_mpm_ctx->md[probe_id].remote_state == MPM_MHIP_REMOTE_ERR) {
	if (ipa_mpm_ctx->md[probe_id].remote_state == MPM_MHIP_REMOTE_ERR) {
		IPA_MPM_ERR("Remote channels in err state for %d\n", probe_id);
		IPA_MPM_ERR("Remote channels in err state for %d\n", probe_id);
		mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
		return -EFAULT;
		return -EFAULT;
	}
	}


@@ -1497,12 +1494,14 @@ static int ipa_mpm_start_stop_remote_mhip_chan(
				probe_id);
				probe_id);
		} else {
		} else {
			ret = mhi_resume_transfer(mhi_dev);
			ret = mhi_resume_transfer(mhi_dev);
			mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
			if (ret)
			if (ret)
				ipa_mpm_ctx->md[probe_id].remote_state =
				ipa_mpm_ctx->md[probe_id].remote_state =
							MPM_MHIP_REMOTE_ERR;
							MPM_MHIP_REMOTE_ERR;
			else
			else
				ipa_mpm_ctx->md[probe_id].remote_state =
				ipa_mpm_ctx->md[probe_id].remote_state =
							MPM_MHIP_REMOTE_START;
							MPM_MHIP_REMOTE_START;
			mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
		}
		}
	} else {
	} else {
		if (ipa_mpm_ctx->md[probe_id].remote_state ==
		if (ipa_mpm_ctx->md[probe_id].remote_state ==
@@ -1511,15 +1510,16 @@ static int ipa_mpm_start_stop_remote_mhip_chan(
					probe_id);
					probe_id);
		} else {
		} else {
			ret = mhi_pause_transfer(mhi_dev);
			ret = mhi_pause_transfer(mhi_dev);
			mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
			if (ret)
			if (ret)
				ipa_mpm_ctx->md[probe_id].remote_state =
				ipa_mpm_ctx->md[probe_id].remote_state =
							MPM_MHIP_REMOTE_ERR;
							MPM_MHIP_REMOTE_ERR;
			else
			else
				ipa_mpm_ctx->md[probe_id].remote_state =
				ipa_mpm_ctx->md[probe_id].remote_state =
							MPM_MHIP_REMOTE_STOP;
							MPM_MHIP_REMOTE_STOP;
			mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
		}
		}
	}
	}
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	return ret;
	return ret;
}
}


@@ -1563,6 +1563,15 @@ static enum mhip_status_type ipa_mpm_start_stop_mhip_chan(
		IPA_MPM_ERR("fail to get EP# for idx %d\n", ipa_ep_idx);
		IPA_MPM_ERR("fail to get EP# for idx %d\n", ipa_ep_idx);
		return MHIP_STATUS_EP_NOT_FOUND;
		return MHIP_STATUS_EP_NOT_FOUND;
	}
	}

	mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	if (!ipa_mpm_ctx->md[probe_id].init_complete) {
		IPA_MPM_ERR("MHIP probe %d not initialized\n", probe_id);
		mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
		return MHIP_STATUS_EP_NOT_READY;
	}
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);

	ep = &ipa3_ctx->ep[ipa_ep_idx];
	ep = &ipa3_ctx->ep[ipa_ep_idx];


	if (mhip_chan == IPA_MPM_MHIP_CHAN_UL) {
	if (mhip_chan == IPA_MPM_MHIP_CHAN_UL) {
@@ -1951,10 +1960,8 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
	ipa_mpm_ctx->md[probe_id].remote_state = MPM_MHIP_REMOTE_STOP;
	ipa_mpm_ctx->md[probe_id].remote_state = MPM_MHIP_REMOTE_STOP;
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	ipa_mpm_vote_unvote_pcie_clk(CLK_ON, probe_id);
	ipa_mpm_vote_unvote_pcie_clk(CLK_ON, probe_id);
	mutex_lock(&ipa_mpm_ctx->md[probe_id].lpm_mutex);
	ipa_mpm_vote_unvote_ipa_clk(CLK_ON, probe_id);
	ipa_mpm_vote_unvote_ipa_clk(CLK_ON, probe_id);
	ipa_mpm_ctx->md[probe_id].in_lpm = false;
	ipa_mpm_ctx->md[probe_id].in_lpm = false;
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].lpm_mutex);
	IPA_MPM_DBG("ul chan = %d, dl_chan = %d\n", ul_prod, dl_cons);
	IPA_MPM_DBG("ul chan = %d, dl_chan = %d\n", ul_prod, dl_cons);


	/*
	/*
@@ -2089,8 +2096,10 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
		 * to MHI driver. remove_cb will be called eventually when
		 * to MHI driver. remove_cb will be called eventually when
		 * Device side comes from where pending cleanup happens.
		 * Device side comes from where pending cleanup happens.
		 */
		 */
		mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
		atomic_inc(&ipa_mpm_ctx->probe_cnt);
		atomic_inc(&ipa_mpm_ctx->probe_cnt);
		ipa_mpm_ctx->md[probe_id].init_complete = true;
		ipa_mpm_ctx->md[probe_id].init_complete = false;
		mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
		IPA_MPM_FUNC_EXIT();
		IPA_MPM_FUNC_EXIT();
		return 0;
		return 0;
	}
	}
@@ -2271,8 +2280,6 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
	}
	}


	atomic_inc(&ipa_mpm_ctx->probe_cnt);
	atomic_inc(&ipa_mpm_ctx->probe_cnt);
	ipa_mpm_ctx->md[probe_id].init_complete = true;

	/* Check if ODL pipe is connected to MHIP DPL pipe before probe */
	/* Check if ODL pipe is connected to MHIP DPL pipe before probe */
	if (probe_id == IPA_MPM_MHIP_CH_ID_2 &&
	if (probe_id == IPA_MPM_MHIP_CH_ID_2 &&
		ipa3_is_odl_connected()) {
		ipa3_is_odl_connected()) {
@@ -2280,7 +2287,9 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
		ret = ipa_mpm_set_dma_mode(IPA_CLIENT_MHI_PRIME_DPL_PROD,
		ret = ipa_mpm_set_dma_mode(IPA_CLIENT_MHI_PRIME_DPL_PROD,
			IPA_CLIENT_USB_DPL_CONS, false);
			IPA_CLIENT_USB_DPL_CONS, false);
	}
	}

	mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	ipa_mpm_ctx->md[probe_id].init_complete = true;
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	IPA_MPM_FUNC_EXIT();
	IPA_MPM_FUNC_EXIT();
	return 0;
	return 0;


@@ -2349,6 +2358,11 @@ static void ipa_mpm_mhi_remove_cb(struct mhi_device *mhi_dev)
	}
	}


	IPA_MPM_DBG("remove_cb for mhip_idx = %d", mhip_idx);
	IPA_MPM_DBG("remove_cb for mhip_idx = %d", mhip_idx);

	mutex_lock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
	ipa_mpm_ctx->md[mhip_idx].init_complete = false;
	mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);

	ipa_mpm_mhip_shutdown(mhip_idx);
	ipa_mpm_mhip_shutdown(mhip_idx);


	atomic_dec(&ipa_mpm_ctx->probe_cnt);
	atomic_dec(&ipa_mpm_ctx->probe_cnt);
@@ -2387,7 +2401,19 @@ static void ipa_mpm_mhi_status_cb(struct mhi_device *mhi_dev,
		return;
		return;
	}
	}


	mutex_lock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex);
	mutex_lock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
	if (!ipa_mpm_ctx->md[mhip_idx].init_complete) {
		/*
		 * SSR might be in progress, dont have to vote/unvote for
		 * IPA clocks as it will be taken care in remove_cb/subsequent
		 * probe.
		 */
		IPA_MPM_DBG("SSR in progress, return\n");
		mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
		return;
	}
	mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);

	switch (mhi_cb) {
	switch (mhi_cb) {
	case MHI_CB_IDLE:
	case MHI_CB_IDLE:
		break;
		break;
@@ -2424,7 +2450,6 @@ static void ipa_mpm_mhi_status_cb(struct mhi_device *mhi_dev,
		IPA_MPM_ERR("unexpected event %d\n", mhi_cb);
		IPA_MPM_ERR("unexpected event %d\n", mhi_cb);
		break;
		break;
	}
	}
	mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex);
}
}


static void ipa_mpm_mhip_map_prot(enum ipa_usb_teth_prot prot,
static void ipa_mpm_mhip_map_prot(enum ipa_usb_teth_prot prot,
@@ -2778,7 +2803,6 @@ static int ipa_mpm_probe(struct platform_device *pdev)
	for (i = 0; i < IPA_MPM_MHIP_CH_ID_MAX; i++) {
	for (i = 0; i < IPA_MPM_MHIP_CH_ID_MAX; i++) {
		mutex_init(&ipa_mpm_ctx->md[i].mutex);
		mutex_init(&ipa_mpm_ctx->md[i].mutex);
		mutex_init(&ipa_mpm_ctx->md[i].mhi_mutex);
		mutex_init(&ipa_mpm_ctx->md[i].mhi_mutex);
		mutex_init(&ipa_mpm_ctx->md[i].lpm_mutex);
	}
	}


	ipa_mpm_ctx->dev_info.pdev = pdev;
	ipa_mpm_ctx->dev_info.pdev = pdev;