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

Commit 5f24436f authored by Ravinder Konka's avatar Ravinder Konka
Browse files

msm: ipa: Fix to processing of BAM IRQ when IPA is clock gated



When suspend IRQ is received from IPA HW, IPA clocks are voted on
and suspend IRQ handling is deferred and clocks are voted off.
When IPA clocks are voted on, end point suspend is removed on
WAN_CONS and LAN_CONS pipes. There is a possibility that between
clock voting on and off, BAM IRQ is raised and is tried to be
processed which results in a NOC error. Make a change to not
to defer processing of suspend IRQ to keep the IPA clock on
till BAM IRQ is processed.

Change-Id: Iae7a720e06d7bdedd0f65af330434cdfaa941d54
Acked-by: default avatarChaitanya Pratapa <cpratapa@qti.qualcomm.com>
Signed-off-by: default avatarRavinder Konka <rkonka@codeaurora.org>
parent 049b7256
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -2544,6 +2544,8 @@ void _ipa_enable_clks_v2_0(void)

	if (smmu_clk)
		clk_prepare_enable(smmu_clk);
	/* Enable the BAM IRQ. */
	ipa_sps_irq_control_all(true);
	ipa_suspend_apps_pipes(false);
}

@@ -2667,6 +2669,7 @@ void _ipa_disable_clks_v2_0(void)
{
	IPADBG("disabling gcc_ipa_clk\n");
	ipa_suspend_apps_pipes(true);
	ipa_sps_irq_control_all(false);
	ipa_uc_notify_clk_state(false);
	if (ipa_clk)
		clk_disable_unprepare(ipa_clk);
@@ -3023,6 +3026,8 @@ void ipa_suspend_handler(enum ipa_irq_type interrupt,
					&ipa_ctx->sps_pm.dec_clients)
					) {
					ipa_inc_client_enable_clks();
					IPADBG("Pipes un-suspended.\n");
					IPADBG("Enter poll mode.\n");
					atomic_set(
						&ipa_ctx->sps_pm.dec_clients,
						1);
@@ -3575,8 +3580,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
	}

	/*add handler for suspend interrupt*/
	result = ipa2_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
			ipa_suspend_handler, true, NULL);
	result = ipa_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
			ipa_suspend_handler, false, NULL);
	if (result) {
		IPAERR("register handler for suspend interrupt failed\n");
		result = -ENODEV;
+71 −0
Original line number Diff line number Diff line
@@ -792,6 +792,77 @@ fail:
			msecs_to_jiffies(1));
}


/**
 * ipa_sps_irq_control() - Function to enable or disable BAM IRQ.
 */
static void ipa_sps_irq_control(struct ipa_sys_context *sys, bool enable)
{
	int ret;

	if (enable) {
		ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
		if (ret) {
			IPAERR("sps_get_config() failed %d\n", ret);
			return;
		}
		sys->event.options = SPS_O_EOT;
		ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
		if (ret) {
			IPAERR("sps_register_event() failed %d\n", ret);
			return;
		}
		sys->ep->connect.options =
			SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
		ret = sps_set_config(sys->ep->ep_hdl, &sys->ep->connect);
		if (ret) {
			IPAERR("sps_set_config() failed %d\n", ret);
			return;
		}
	} else {
		ret = sps_get_config(sys->ep->ep_hdl,
				&sys->ep->connect);
		if (ret) {
			IPAERR("sps_get_config() failed %d\n", ret);
			return;
		}
		sys->ep->connect.options = SPS_O_AUTO_ENABLE |
			SPS_O_ACK_TRANSFERS | SPS_O_POLL;
		ret = sps_set_config(sys->ep->ep_hdl,
				&sys->ep->connect);
		if (ret) {
			IPAERR("sps_set_config() failed %d\n", ret);
			return;
		}
	}
}

void ipa_sps_irq_control_all(bool enable)
{
	struct ipa_ep_context *ep;
	int ipa_ep_idx, client_num;

	IPADBG("\n");

	for (client_num = IPA_CLIENT_CONS;
		client_num < IPA_CLIENT_MAX; client_num++) {
		if (!IPA_CLIENT_IS_APPS_CONS(client_num))
			continue;

		ipa_ep_idx = ipa_get_ep_mapping(client_num);
		if (ipa_ep_idx == -1) {
			IPAERR("Invalid client.\n");
			continue;
		}
		ep = &ipa_ctx->ep[ipa_ep_idx];
		if (!ep->valid) {
			IPAERR("EP (%d) not allocated.\n", ipa_ep_idx);
			continue;
		}
		ipa_sps_irq_control(ep->sys, enable);
	}
}

/**
 * ipa_rx_notify() - Callback function which is called by the SPS driver when a
 * a packet is received
+1 −0
Original line number Diff line number Diff line
@@ -1987,4 +1987,5 @@ void ipa_update_repl_threshold(enum ipa_client_type ipa_client);
void ipa_flow_control(enum ipa_client_type ipa_client, bool enable,
			uint32_t qmap_id);
int ipa2_restore_suspend_handler(void);
void ipa_sps_irq_control_all(bool enable);
#endif /* _IPA_I_H_ */
+7 −6
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ static bool is_valid_ep(u32 ep_suspend_data)
	return false;
}

static int handle_interrupt(int irq_num)
static int handle_interrupt(int irq_num, bool isr_context)
{
	struct ipa_interrupt_info interrupt_info;
	struct ipa_interrupt_work_wrap *work_data;
@@ -121,7 +121,8 @@ static int handle_interrupt(int irq_num)
		break;
	}

	if (interrupt_info.deferred_flag) {
	/* Force defer processing if in ISR context. */
	if (interrupt_info.deferred_flag || isr_context) {
		work_data = kzalloc(sizeof(struct ipa_interrupt_work_wrap),
				GFP_ATOMIC);
		if (!work_data) {
@@ -150,7 +151,7 @@ fail_alloc_work:
	return res;
}

static void ipa_process_interrupts(void)
static void ipa_process_interrupts(bool isr_context)
{
	u32 reg;
	u32 bmsk;
@@ -163,7 +164,7 @@ static void ipa_process_interrupts(void)
		bmsk = 1;
		for (i = 0; i < IPA_IRQ_NUM_MAX; i++) {
			if (en & reg & bmsk)
				handle_interrupt(i);
				handle_interrupt(i, isr_context);
			bmsk = bmsk << 1;
		}
		ipa_write_reg(ipa_ctx->mmio,
@@ -177,7 +178,7 @@ static void ipa_interrupt_defer(struct work_struct *work)
{
	IPADBG("processing interrupts in wq\n");
	ipa_inc_client_enable_clks();
	ipa_process_interrupts();
	ipa_process_interrupts(false);
	ipa_dec_client_disable_clks();
	IPADBG("Done\n");
}
@@ -199,7 +200,7 @@ static irqreturn_t ipa_isr(int irq, void *ctxt)
		goto bail;
	}

	ipa_process_interrupts();
	ipa_process_interrupts(true);

bail:
	ipa_active_clients_trylock_unlock(&flags);
+43 −4
Original line number Diff line number Diff line
@@ -5097,15 +5097,54 @@ void ipa_suspend_apps_pipes(bool suspend)
{
	struct ipa_ep_cfg_ctrl cfg;
	int ipa_ep_idx;
	u32 lan_empty = 0, wan_empty = 0;
	int ret;
	struct sps_event_notify notify;
	struct ipa_ep_context *ep;

	memset(&cfg, 0, sizeof(cfg));
	cfg.ipa_ep_suspend = suspend;

	ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS);
	if (ipa_ctx->ep[ipa_ep_idx].valid)
		ipa_cfg_ep_ctrl(ipa_ep_idx, &cfg);
	ep = &ipa_ctx->ep[ipa_ep_idx];
	if (ep->valid) {
		ipa2_cfg_ep_ctrl(ipa_ep_idx, &cfg);
		/* Check if the pipes are empty. */
		ret = sps_is_pipe_empty(ep->ep_hdl, &lan_empty);
		if (ret) {
			IPAERR("%s: sps_is_pipe_empty failed with %d\n",
				__func__, ret);
		}
		if (!lan_empty) {
			IPADBG("LAN Cons is not-empty. Enter poll mode.\n");
			notify.user = ep->sys;
			notify.event_id = SPS_EVENT_EOT;
			if (ep->sys->sps_callback)
				ep->sys->sps_callback(&notify);
		}
	}

	ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
	if (ipa_ctx->ep[ipa_ep_idx].valid)
		ipa_cfg_ep_ctrl(ipa_ep_idx, &cfg);
	/* Considering the case for SSR. */
	if (ipa_ep_idx == -1) {
		IPADBG("Invalid client.\n");
		return;
	}
	ep = &ipa_ctx->ep[ipa_ep_idx];
	if (ep->valid) {
		ipa2_cfg_ep_ctrl(ipa_ep_idx, &cfg);
		/* Check if the pipes are empty. */
		ret = sps_is_pipe_empty(ep->ep_hdl, &wan_empty);
		if (ret) {
			IPAERR("%s: sps_is_pipe_empty failed with %d\n",
				__func__, ret);
		}
		if (!wan_empty) {
			IPADBG("WAN Cons is not-empty. Enter poll mode.\n");
			notify.user = ep->sys;
			notify.event_id = SPS_EVENT_EOT;
			if (ep->sys->sps_callback)
				ep->sys->sps_callback(&notify);
		}
	}
}