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

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

Merge "msm: ipa: stop/start IPA Device MHIP channels for tethering usecases"

parents 867a2e04 d7440535
Loading
Loading
Loading
Loading
+204 −56
Original line number Diff line number Diff line
@@ -317,6 +317,12 @@ enum ipa_mpm_gsi_state {
	GSI_STOPPED,
};

enum ipa_mpm_remote_state {
	MPM_MHIP_REMOTE_STOP,
	MPM_MHIP_REMOTE_START,
	MPM_MHIP_REMOTE_ERR,
};

struct ipa_mpm_channel {
	struct ipa_mpm_channel_props chan_props;
	struct ipa_mpm_event_props evt_props;
@@ -382,6 +388,7 @@ struct ipa_mpm_mhi_driver {
	struct mutex mhi_mutex;
	bool in_lpm;
	struct ipa_mpm_clk_cnt_type clk_cnt;
	enum ipa_mpm_remote_state remote_state;
};

struct ipa_mpm_context {
@@ -1440,6 +1447,59 @@ static void ipa_mpm_vote_unvote_ipa_clk(enum ipa_mpm_clk_vote_type vote,
	}
}

static int ipa_mpm_start_stop_remote_mhip_chan(
	int probe_id,
	enum ipa_mpm_start_stop_type start_stop)
{
	int ret = 0;
	struct mhi_device *mhi_dev = ipa_mpm_ctx->md[probe_id].mhi_dev;

	if (!mhi_dev) {
		IPA_MPM_ERR("MHI not initialized yet\n");
		return ret;
	}

	mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	/* For error state, expect modem SSR to recover from error */
	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);
		mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
		return -EFAULT;
	}

	if (start_stop == MPM_MHIP_START) {
		if (ipa_mpm_ctx->md[probe_id].remote_state ==
				MPM_MHIP_REMOTE_START) {
			IPA_MPM_DBG("Remote channel already started for %d\n",
				probe_id);
		} else {
			ret = mhi_resume_transfer(mhi_dev);
			if (ret)
				ipa_mpm_ctx->md[probe_id].remote_state =
							MPM_MHIP_REMOTE_ERR;
			else
				ipa_mpm_ctx->md[probe_id].remote_state =
							MPM_MHIP_REMOTE_START;
		}
	} else {
		if (ipa_mpm_ctx->md[probe_id].remote_state ==
				MPM_MHIP_REMOTE_STOP) {
			IPA_MPM_DBG("Remote channel already stopped for %d\n",
					probe_id);
		} else {
			ret = mhi_pause_transfer(mhi_dev);
			if (ret)
				ipa_mpm_ctx->md[probe_id].remote_state =
							MPM_MHIP_REMOTE_ERR;
			else
				ipa_mpm_ctx->md[probe_id].remote_state =
							MPM_MHIP_REMOTE_STOP;
		}
	}
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	return ret;
}

static enum mhip_status_type ipa_mpm_start_stop_mhip_chan(
	enum ipa_mpm_mhip_chan mhip_chan,
	int probe_id,
@@ -1627,6 +1687,26 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
				ret);
			return ret;
		}

		/*
		 * Make sure to start Device side channels before
		 * starting Host side UL channels. This is to make
		 * sure device side access host side only after
		 * Host IPA gets voted.
		 */
		ret = ipa_mpm_start_stop_remote_mhip_chan(probe_id,
							MPM_MHIP_START);
		if (ret) {
			/*
			 * This can fail only when modem is in SSR state.
			 * Eventually there would be a remove callback,
			 * so return a failure.
			 */
			IPA_MPM_ERR("MHIP remote chan start fail = %d\n", ret);
			return ret;
		}
		IPA_MPM_DBG("MHIP remote channels are started\n");

		status = ipa_mpm_start_stop_mhip_chan(
				IPA_MPM_MHIP_CHAN_UL, probe_id, MPM_MHIP_START);
		switch (status) {
@@ -1636,7 +1716,7 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
			ret = ipa_mpm_start_stop_ul_mhip_data_path(
						probe_id, MPM_MHIP_START);
			if (ret) {
				IPA_MPM_ERR("err UL chan start\n");
				IPA_MPM_ERR("UL chan start err = %d\n", ret);
				ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id);
				return ret;
			}
@@ -1662,6 +1742,25 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
		}
		ipa_mpm_ctx->md[probe_id].mhip_client = mhip_client;
	} else {
		/*
		 * Make sure to stop Device side channels before
		 * stopping Host side UL channels. This is to make
		 * sure device side doesn't access host IPA after
		 * Host IPA gets devoted.
		 */
		ret = ipa_mpm_start_stop_remote_mhip_chan(probe_id,
						MPM_MHIP_STOP);
		if (ret) {
			/*
			 * This can fail only when modem is in SSR state.
			 * Eventually there would be a remove callback,
			 * so return a failure.
			 */
			IPA_MPM_ERR("MHIP remote chan stop fail = %d\n", ret);
			return ret;
		}
		IPA_MPM_DBG("MHIP remote channels are stopped\n");

		status = ipa_mpm_start_stop_mhip_chan(
					IPA_MPM_MHIP_CHAN_UL, probe_id,
					MPM_MHIP_STOP);
@@ -1691,7 +1790,7 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
		ret = ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id);

		if (ret) {
			IPA_MPM_ERR("Error cloking on PCIe clk, err = %d\n",
			IPA_MPM_ERR("Error cloking off PCIe clk, err = %d\n",
				ret);
			return ret;
		}
@@ -1892,6 +1991,9 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
	ipa_mpm_ctx->mhi_parent_dev =
		ipa_mpm_ctx->md[probe_id].mhi_dev->dev.parent;

	mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	ipa_mpm_ctx->md[probe_id].remote_state = MPM_MHIP_REMOTE_STOP;
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	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);
@@ -1938,6 +2040,33 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
		ch->evt_props.device_db =
			ipa_mpm_ctx->dev_info.erdb_base +
			ch->chan_props.ch_ctx.erindex * 8;

		/* connect Host GSI pipes with MHI' protocol */
		ret = ipa_mpm_connect_mhip_gsi_pipe(ul_prod,
			probe_id, &ul_out_params);
		if (ret) {
			IPA_MPM_ERR("failed connecting MPM client %d\n",
					ul_prod);
			goto fail_gsi_setup;
		}

		ch->evt_props.ev_ctx.update_rp_addr =
			ipa_mpm_smmu_map_doorbell(
				MHIP_SMMU_DOMAIN_PCIE,
				ul_out_params.db_reg_phs_addr_lsb);
		if (ch->evt_props.ev_ctx.update_rp_addr == 0)
			ipa_assert();

		ipa_mpm_ctx->md[probe_id].ul_prod.db_device_iova =
			ch->evt_props.ev_ctx.update_rp_addr;

		ret = __ipa_mpm_configure_mhi_device(
				ch, probe_id, DMA_TO_HIPA);
		if (ret) {
			IPA_MPM_ERR("configure_mhi_dev fail %d\n",
					ret);
			goto fail_smmu;
		}
	}

	if (dl_cons != IPA_CLIENT_MAX) {
@@ -1965,19 +2094,8 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
		ch->evt_props.device_db =
			ipa_mpm_ctx->dev_info.erdb_base +
			ch->chan_props.ch_ctx.erindex * 8;
	}
	/* connect Host GSI pipes with MHI' protocol */
	if (ul_prod != IPA_CLIENT_MAX)  {
		ret = ipa_mpm_connect_mhip_gsi_pipe(ul_prod,
			probe_id, &ul_out_params);
		if (ret) {
			IPA_MPM_ERR("failed connecting MPM client %d\n",
					ul_prod);
			goto fail_gsi_setup;
		}
	}

	if (dl_cons != IPA_CLIENT_MAX) {
		/* connect Host GSI pipes with MHI' protocol */
		ret = ipa_mpm_connect_mhip_gsi_pipe(dl_cons,
			probe_id, &dl_out_params);
		if (ret) {
@@ -1985,30 +2103,7 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
				dl_cons);
			goto fail_gsi_setup;
		}
	}

	if (ul_prod != IPA_CLIENT_MAX) {
		ch = &ipa_mpm_ctx->md[probe_id].ul_prod;
		ch->evt_props.ev_ctx.update_rp_addr =
			ipa_mpm_smmu_map_doorbell(
				MHIP_SMMU_DOMAIN_PCIE,
				ul_out_params.db_reg_phs_addr_lsb);
		if (ch->evt_props.ev_ctx.update_rp_addr == 0)
			ipa_assert();
		ipa_mpm_ctx->md[probe_id].ul_prod.db_device_iova =
			ch->evt_props.ev_ctx.update_rp_addr;

		ret = __ipa_mpm_configure_mhi_device(
				ch, probe_id, DMA_TO_HIPA);
		if (ret) {
			IPA_MPM_ERR("configure_mhi_dev fail %d\n",
					ret);
			goto fail_smmu;
		}
	}

	if (dl_cons != IPA_CLIENT_MAX) {
		ch = &ipa_mpm_ctx->md[probe_id].dl_cons;
		ch->evt_props.ev_ctx.update_rp_addr =
			ipa_mpm_smmu_map_doorbell(
					MHIP_SMMU_DOMAIN_PCIE,
@@ -2044,6 +2139,10 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
		return 0;
	}

	/* mhi_prepare_for_transfer translates to starting remote channels */
	mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	ipa_mpm_ctx->md[probe_id].remote_state = MPM_MHIP_REMOTE_START;
	mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
	/*
	 * Ring initial channel db - Host Side UL and Device side DL channel.
	 * To ring doorbell, write "WP" into doorbell register.
@@ -2068,13 +2167,11 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,

		iounmap(db_addr);
		ipa_mpm_read_channel(ul_prod);
	}

		/* Ring UL PRODUCER EVENT RING (HOST IPA -> DEVICE IPA) Doorbell
		 * Ring the event DB to a value outside the
		 * ring range such that rp and wp never meet.
		 */
	if (ul_prod != IPA_CLIENT_MAX) {
		ipa_ep_idx = ipa3_get_ep_mapping(ul_prod);

		if (ipa_ep_idx == IPA_EP_NOT_ALLOCATED) {
@@ -2100,10 +2197,8 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,

		iowrite32(wp_addr, db_addr);
		iounmap(db_addr);
	}

		/* Ring DEVICE IPA DL CONSUMER Event Doorbell */
	if (ul_prod != IPA_CLIENT_MAX) {
		db_addr = ioremap((phys_addr_t)
			(ipa_mpm_ctx->md[probe_id].ul_prod.evt_props.device_db),
			4);
@@ -2130,14 +2225,12 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
		iowrite32(wp_addr, db_addr);

		iounmap(db_addr);
	}

		/*
		 * Ring event ring DB on Device side.
		 * ipa_mpm should ring the event DB to a value outside the
		 * ring range such that rp and wp never meet.
		 */
	if (dl_cons != IPA_CLIENT_MAX) {
		db_addr =
		ioremap(
		(phys_addr_t)
@@ -2151,10 +2244,8 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
		IPA_MPM_DBG("Device  UL ER  DB = 0X%pK,wp_addr = 0X%0x",
			db_addr, wp_addr);
		iounmap(db_addr);
	}

		/* Ring DL EVENT RING CONSUMER (DEVICE IPA CONSUMER) Doorbell */
	if (dl_cons != IPA_CLIENT_MAX) {
		ipa_ep_idx = ipa3_get_ep_mapping(dl_cons);

		if (ipa_ep_idx == IPA_EP_NOT_ALLOCATED) {
@@ -2182,6 +2273,23 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
	 */
	switch (ipa_mpm_ctx->md[probe_id].teth_state) {
	case IPA_MPM_TETH_INIT:
		/*
		 * Make sure to stop Device side channels before
		 * stopping Host side UL channels. This is to make
		 * sure Device side doesn't access host side IPA if
		 * Host IPA gets unvoted.
		 */
		ret = ipa_mpm_start_stop_remote_mhip_chan(probe_id,
						MPM_MHIP_STOP);
		if (ret) {
			/*
			 * This can fail only when modem is in SSR.
			 * Eventually there would be a remove callback,
			 * so return a failure.
			 */
			IPA_MPM_ERR("MHIP remote chan stop fail = %d\n", ret);
			return ret;
		}
		if (ul_prod != IPA_CLIENT_MAX) {
			/* No teth started yet, disable UL channel */
			ipa_mpm_start_stop_mhip_chan(IPA_MPM_MHIP_CHAN_UL,
@@ -2437,6 +2545,27 @@ int ipa_mpm_mhip_xdci_pipe_enable(enum ipa_usb_teth_prot xdci_teth_prot)
		return ret;
	}

	/*
	 * Make sure to start Device side channels before
	 * starting Host side UL channels. This is to make
	 * sure device side access host side IPA only when
	 * Host IPA gets voted.
	 */
	ret = ipa_mpm_start_stop_remote_mhip_chan(probe_id,
						MPM_MHIP_START);
	if (ret) {
		/*
		 * This can fail only when modem is in SSR state.
		 * Eventually there would be a remove callback,
		 * so return a failure.
		 */
		IPA_MPM_ERR("MHIP remote chan start fail = %d\n",
				ret);
		return ret;
	}

	IPA_MPM_DBG("MHIP remote channel start success\n");

	switch (mhip_client) {
	case IPA_MPM_MHIP_USB_RMNET:
		ipa_mpm_set_dma_mode(IPA_CLIENT_USB_PROD,
@@ -2529,6 +2658,25 @@ int ipa_mpm_mhip_xdci_pipe_disable(enum ipa_usb_teth_prot xdci_teth_prot)

	IPA_MPM_ERR("xdci disconnect prot %d mhip_client = %d probe_id = %d\n",
			xdci_teth_prot, mhip_client, probe_id);
	/*
	 * Make sure to stop Device side channels before
	 * stopping Host side UL channels. This is to make
	 * sure device side doesn't access host side IPA if
	 * Host IPA gets unvoted.
	 */
	ret = ipa_mpm_start_stop_remote_mhip_chan(probe_id,
						MPM_MHIP_STOP);
	if (ret) {
		/*
		 * This can fail only when modem is in SSR state.
		 * Eventually there would be a remove callback,
		 * so return a failure.
		 */
		IPA_MPM_ERR("MHIP remote chan stop fail = %d\n", ret);
		return ret;
	}

	IPA_MPM_DBG("MHIP remote channels are stopped\n");

	switch (mhip_client) {
	case IPA_MPM_MHIP_USB_RMNET: