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

Commit 58c73c8d authored by Michael Adisumarta's avatar Michael Adisumarta Committed by Gerrit - the friendly Code Review server
Browse files

msm:ipa: uc based flow control for UL tethering offload



This change enables uc UL tethering offload flow control by
setting/resetting end point delay  for tethering clients
such as USB/WiFi.

Change-Id: Ie02c9234fe264f88042b4cf4b7682d9b86d154c2
Signed-off-by: default avatarMichael Adisumarta <madisuma@codeaurora.org>
parent a347cbb3
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -3260,4 +3260,10 @@ static inline void *alloc_and_init(u32 size, u32 init_val)
bool ipa3_is_apq(void);
/* check if odl is connected */
bool ipa3_is_odl_connected(void);

int ipa3_uc_send_enable_flow_control(uint16_t gsi_chid,
	uint16_t redMarkerThreshold);
int ipa3_uc_send_disable_flow_control(void);
int ipa3_uc_send_update_flow_control(uint32_t bitmask,
	uint8_t  add_delete);
#endif /* _IPA3_I_H_ */
+79 −0
Original line number Diff line number Diff line
@@ -71,6 +71,8 @@
#define IPA_CHANNEL_STOP_IN_PROC_TO_MSEC 5
#define IPA_CHANNEL_STOP_IN_PROC_SLEEP_USEC 200
#define IPA_MHIP_HOLB_TMO 31 /* value to match granularity on ipa HW 4.5 */
#define IPA_MPM_FLOW_CTRL_ADD 1
#define IPA_MPM_FLOW_CTRL_DELETE 0

enum mhip_re_type {
	MHIP_RE_XFER = 0x2,
@@ -393,6 +395,7 @@ struct ipa_mpm_context {
	atomic_t probe_cnt;
	atomic_t pcie_clk_total_cnt;
	atomic_t ipa_clk_total_cnt;
	atomic_t flow_ctrl_mask;
	atomic_t adpl_over_usb_available;
	struct device *parent_pdev;
	struct ipa_smmu_cb_ctx carved_smmu_cb;
@@ -1719,6 +1722,8 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
	int ret = 0;
	enum ipa_mpm_mhip_client_type mhip_client = IPA_MPM_MHIP_TETH;
	bool is_acted = true;
	const struct ipa_gsi_ep_config *ep_cfg;
	uint32_t flow_ctrl_mask = 0;

	if (!state)
		return -EPERM;
@@ -1775,6 +1780,35 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
		}
		IPA_MPM_DBG("MHIP remote channels are started\n");

		 /*
		  * Update flow control monitoring end point info.
		  * This info will be used to set delay on the end points upon
		  * hitting RED water mark.
		  */
		ep_cfg = ipa3_get_gsi_ep_info(IPA_CLIENT_WLAN2_PROD);

		if (!ep_cfg)
			IPA_MPM_ERR("ep = %d not allocated yet\n",
					IPA_CLIENT_WLAN2_PROD);
		else
			flow_ctrl_mask |= 1 << (ep_cfg->ipa_gsi_chan_num);

		ep_cfg = ipa3_get_gsi_ep_info(IPA_CLIENT_USB_PROD);

		if (!ep_cfg)
			IPA_MPM_ERR("ep = %d not allocated yet\n",
					IPA_CLIENT_USB_PROD);
		else
			flow_ctrl_mask |= 1 << (ep_cfg->ipa_gsi_chan_num);

		atomic_set(&ipa_mpm_ctx->flow_ctrl_mask, flow_ctrl_mask);

		ret = ipa3_uc_send_update_flow_control(flow_ctrl_mask,
						IPA_MPM_FLOW_CTRL_ADD);

		if (ret)
			IPA_MPM_ERR("Err = %d setting uc flow control\n", ret);

		status = ipa_mpm_start_stop_mhip_chan(
				IPA_MPM_MHIP_CHAN_UL, probe_id, MPM_MHIP_START);
		switch (status) {
@@ -1812,6 +1846,23 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
		}
		ipa_mpm_ctx->md[probe_id].mhip_client = mhip_client;
	} else {
		/*
		 * Update flow control monitoring end point info.
		 * This info will be used to reset delay on the end points.
		 */
		flow_ctrl_mask =
			atomic_read(&ipa_mpm_ctx->flow_ctrl_mask);

		ret = ipa3_uc_send_update_flow_control(flow_ctrl_mask,
						IPA_MPM_FLOW_CTRL_DELETE);
		flow_ctrl_mask = 0;
		atomic_set(&ipa_mpm_ctx->flow_ctrl_mask, 0);

		if (ret) {
			IPA_MPM_ERR("Err = %d resetting uc flow control\n",
					ret);
			ipa_assert();
		}
		/*
		 * Make sure to stop Device side channels before
		 * stopping Host side UL channels. This is to make
@@ -1968,6 +2019,8 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
	u32 wp_addr;
	int pipe_idx;
	bool is_acted = true;
	uint64_t flow_ctrl_mask = 0;
	bool add_delete = false;

	IPA_MPM_FUNC_ENTRY();

@@ -2348,6 +2401,27 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
	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);
	/* Update Flow control Monitoring, only for the teth UL Prod pipes */
	if (probe_id == IPA_MPM_MHIP_CH_ID_0) {
		ipa_ep_idx = ipa3_get_ep_mapping(ul_prod);
		ep = &ipa3_ctx->ep[ipa_ep_idx];
		ret = ipa3_uc_send_enable_flow_control(ep->gsi_chan_hdl,
			IPA_MPM_RING_LEN / 4);
		if (ret) {
			IPA_MPM_ERR("Err %d flow control enable\n", ret);
			goto fail_flow_control;
		}
		IPA_MPM_DBG("Flow Control enabled for %d", probe_id);
		flow_ctrl_mask = atomic_read(&ipa_mpm_ctx->flow_ctrl_mask);
		add_delete = flow_ctrl_mask > 0 ? 1 : 0;
		ret = ipa3_uc_send_update_flow_control(flow_ctrl_mask,
							add_delete);
		if (ret) {
			IPA_MPM_ERR("Err %d flow control update\n", ret);
			goto fail_flow_control;
		}
		IPA_MPM_DBG("Flow Control updated for %d", probe_id);
	}
	IPA_MPM_FUNC_EXIT();
	return 0;

@@ -2355,6 +2429,7 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
fail_start_channel:
fail_stop_channel:
fail_smmu:
fail_flow_control:
	if (ipa_mpm_ctx->dev_info.ipa_smmu_enabled)
		IPA_MPM_DBG("SMMU failed\n");
	if (is_acted)
@@ -2424,6 +2499,9 @@ static void ipa_mpm_mhi_remove_cb(struct mhi_device *mhi_dev)
	ipa_mpm_ctx->md[mhip_idx].init_complete = false;
	mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);

	if (mhip_idx == IPA_MPM_MHIP_CH_ID_0)
		ipa3_uc_send_disable_flow_control();

	ipa_mpm_mhip_shutdown(mhip_idx);

	atomic_dec(&ipa_mpm_ctx->probe_cnt);
@@ -2909,6 +2987,7 @@ static int ipa_mpm_probe(struct platform_device *pdev)

	atomic_set(&ipa_mpm_ctx->ipa_clk_total_cnt, 0);
	atomic_set(&ipa_mpm_ctx->pcie_clk_total_cnt, 0);
	atomic_set(&ipa_mpm_ctx->flow_ctrl_mask, 0);

	for (idx = 0; idx < IPA_MPM_MHIP_CH_ID_MAX; idx++) {
		ipa_mpm_ctx->md[idx].ul_prod.gsi_state = GSI_INIT;
+103 −0
Original line number Diff line number Diff line
@@ -45,6 +45,10 @@
 * IPA_CPU_2_HW_CMD_GSI_CH_EMPTY : Command to check for GSI channel emptiness.
 * IPA_CPU_2_HW_CMD_REMOTE_IPA_INFO: Command to store remote IPA Info
 * IPA_CPU_2_HW_CMD_SETUP_EVENT_RING:  Command to setup the event ring
 * IPA_CPU_2_HW_CMD_ENABLE_FLOW_CTL_MONITOR: Command to enable pipe monitoring.
 * IPA_CPU_2_HW_CMD_UPDATE_FLOW_CTL_MONITOR: Command to update pipes to monitor.
 * IPA_CPU_2_HW_CMD_DISABLE_FLOW_CTL_MONITOR: Command to disable pipe
					monitoring, no parameter required.
 */
enum ipa3_cpu_2_hw_commands {
	IPA_CPU_2_HW_CMD_NO_OP                     =
@@ -73,6 +77,13 @@ enum ipa3_cpu_2_hw_commands {
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 11),
	IPA_CPU_2_HW_CMD_SETUP_EVENT_RING          =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 12),
	IPA_CPU_2_HW_CMD_ENABLE_FLOW_CTL_MONITOR   =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 13),
	IPA_CPU_2_HW_CMD_UPDATE_FLOW_CTL_MONITOR   =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 14),
	IPA_CPU_2_HW_CMD_DISABLE_FLOW_CTL_MONITOR  =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 15),

};

/**
@@ -198,6 +209,36 @@ struct IpaHwDbAddrInfo_t {
	uint32_t mboxN;
} __packed;


/**
 * Structure holding the parameters for IPA_CPU_2_HW_CMD_ENABLE_PIPE_MONITOR
 * command.
 * @ipaProdGsiChid       IPA prod GSI chid to monitor
 * @redMarkerThreshold   red marker threshold in elements for the GSI channel
 */
union IpaEnablePipeMonitorCmdData_t {
	struct IpaEnablePipeMonitorCmdParams_t {
		u32 ipaProdGsiChid:16;
		u32 redMarkerThreshold:16;
	} __packed params;
	u32 raw32b;
} __packed;

/**
 * Structure holding the parameters for IPA_CPU_2_HW_CMD_UPDATE_PIPE_MONITOR
 * command.
 *
 * @bitmask      The parameter of bitmask to add/delete channels/pipes from
 *                global monitoring pipemask
 *                IPA pipe# bitmask or GSI chid bitmask
 * add_delete   1: add pipes to monitor
 *              0: delete pipes to monitor
 */
struct IpaUpdateFlowCtlMonitorData_t {
	u32 bitmask;
	u8 add_delete;
};

static DEFINE_MUTEX(uc_loaded_nb_lock);
static BLOCKING_NOTIFIER_HEAD(uc_loaded_notifier);

@@ -1484,3 +1525,65 @@ int ipa3_set_wlan_tx_info(struct ipa_wdi_tx_info *info)

	return 0;
}

int ipa3_uc_send_enable_flow_control(uint16_t gsi_chid,
		uint16_t redMarkerThreshold)
{

	int res;
	union IpaEnablePipeMonitorCmdData_t cmd;

	cmd.params.ipaProdGsiChid = gsi_chid;
	cmd.params.redMarkerThreshold = redMarkerThreshold;

	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
	res = ipa3_uc_send_cmd((cmd.raw32b),
		IPA_CPU_2_HW_CMD_ENABLE_FLOW_CTL_MONITOR, 0,
		false, 10 * HZ);

	if (res)
		IPAERR("fail to enable flow ctrl for 0x%x\n",
			cmd.params.ipaProdGsiChid);

	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
	return res;
}

int ipa3_uc_send_disable_flow_control(void)
{
	int res;

	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
	res = ipa3_uc_send_cmd(0,
		IPA_CPU_2_HW_CMD_DISABLE_FLOW_CTL_MONITOR, 0,
		false, 10 * HZ);

	if (res)
		IPAERR("fail to disable flow control\n");

	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
	return res;
}

int ipa3_uc_send_update_flow_control(uint32_t bitmask,
		 uint8_t  add_delete)
{
	int res;

	if (bitmask == 0) {
		IPAERR("Err update flow control, mask = 0\n");
		return 0;
	}

	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
	res = ipa3_uc_send_cmd_64b_param(bitmask, add_delete,
		IPA_CPU_2_HW_CMD_UPDATE_FLOW_CTL_MONITOR, 0,
		false, 10 * HZ);

	if (res)
		IPAERR("fail flowCtrl update mask = 0x%x add_del = 0x%x\n",
			bitmask, add_delete);

	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
	return res;
}