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

Commit 6701e893 authored by Skylar Chang's avatar Skylar Chang
Browse files

msm: ipa3: Fix to processing of GSI 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, GSI 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 GSI IRQ is processed.

Change-Id: Icc3b3b9854898fe4772e60e71651420d296d446b
Acked-by: default avatarAdy Abraham <adya@qti.qualcomm.com>
Signed-off-by: default avatarSkylar Chang <chiaweic@codeaurora.org>
parent 26f280d9
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -2991,6 +2991,8 @@ void ipa3_suspend_handler(enum ipa_irq_type interrupt,
					&ipa3_ctx->transport_pm.dec_clients)
					) {
					ipa3_inc_client_enable_clks();
					IPADBG("Pipes un-suspended.\n");
					IPADBG("Enter poll mode.\n");
					atomic_set(
					&ipa3_ctx->transport_pm.dec_clients,
					1);
@@ -3035,7 +3037,7 @@ int ipa3_restore_suspend_handler(void)
	}

	result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
			ipa3_suspend_handler, true, NULL);
			ipa3_suspend_handler, false, NULL);
	if (result) {
		IPAERR("register handler for suspend interrupt failed\n");
		result = -EPERM;
@@ -3116,7 +3118,7 @@ int ipa3_init_interrupts(void)

	/*add handler for suspend interrupt*/
	result = ipa3_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
			ipa3_suspend_handler, true, NULL);
			ipa3_suspend_handler, false, NULL);
	if (result) {
		IPAERR("register handler for suspend interrupt failed\n");
		result = -ENODEV;
+20 −9
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ static void ipa3_enable_tx_suspend_wa(struct work_struct *work);
static DECLARE_DELAYED_WORK(dwork_en_suspend_int,
						ipa3_enable_tx_suspend_wa);
static spinlock_t suspend_wa_lock;
static void ipa3_process_interrupts(void);
static void ipa3_process_interrupts(bool isr_context);

static int ipa3_irq_mapping[IPA_IRQ_MAX] = {
	[IPA_UC_TX_CMD_Q_NOT_FULL_IRQ]		= -1,
@@ -93,7 +93,7 @@ static bool ipa3_is_valid_ep(u32 ep_suspend_data)
	return false;
}

static int ipa3_handle_interrupt(int irq_num)
static int ipa3_handle_interrupt(int irq_num, bool isr_context)
{
	struct ipa3_interrupt_info interrupt_info;
	struct ipa3_interrupt_work_wrap *work_data;
@@ -131,7 +131,8 @@ static int ipa3_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 ipa3_interrupt_work_wrap),
				GFP_ATOMIC);
		if (!work_data) {
@@ -183,7 +184,7 @@ static void ipa3_enable_tx_suspend_wa(struct work_struct *work)
		, en);
	ipa3_uc_rg10_write_reg(ipa3_ctx->mmio,
		IPA_IRQ_EN_EE_n_ADDR(ipa_ee), en);
	ipa3_process_interrupts();
	ipa3_process_interrupts(false);
	ipa3_dec_client_disable_clks();

	IPADBG("Exit\n");
@@ -215,7 +216,7 @@ static void ipa3_tx_suspend_interrupt_wa(void)
	IPADBG("Exit\n");
}

static void ipa3_process_interrupts(void)
static void ipa3_process_interrupts(bool isr_context)
{
	u32 reg;
	u32 bmsk;
@@ -231,8 +232,18 @@ static void ipa3_process_interrupts(void)
	while (en & reg) {
		bmsk = 1;
		for (i = 0; i < IPA_IRQ_NUM_MAX; i++) {
			if (en & reg & bmsk)
				ipa3_handle_interrupt(i);
			if (en & reg & bmsk) {
				/*
				 * handle the interrupt with spin_lock
				 * unlocked to avoid calling client in atomic
				 * context. mutual exclusion still preserved
				 * as the read/clr is done with spin_lock
				 * locked.
				 */
				spin_unlock_irqrestore(&suspend_wa_lock, flags);
				ipa3_handle_interrupt(i, isr_context);
				spin_lock_irqsave(&suspend_wa_lock, flags);
			}
			bmsk = bmsk << 1;
		}
		ipa3_uc_rg10_write_reg(ipa3_ctx->mmio,
@@ -253,7 +264,7 @@ static void ipa3_interrupt_defer(struct work_struct *work)
{
	IPADBG("processing interrupts in wq\n");
	ipa3_inc_client_enable_clks();
	ipa3_process_interrupts();
	ipa3_process_interrupts(false);
	ipa3_dec_client_disable_clks();
	IPADBG("Done\n");
}
@@ -276,7 +287,7 @@ static irqreturn_t ipa3_isr(int irq, void *ctxt)
		goto bail;
	}

	ipa3_process_interrupts();
	ipa3_process_interrupts(true);
	IPADBG("Exit\n");

bail:
+45 −3
Original line number Diff line number Diff line
@@ -5061,21 +5061,63 @@ void ipa3_set_resorce_groups_min_max_limits(void)
	IPADBG("EXIT\n");
}

static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep)
{
	bool empty;

	IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl);
	gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL);
	gsi_is_channel_empty(ep->gsi_chan_hdl, &empty);
	if (!empty) {
		IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl);
		/* queue a work to start polling if don't have one */
		atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
		if (!atomic_read(&ep->sys->curr_polling_state)) {
			atomic_set(&ep->sys->curr_polling_state, 1);
			queue_work(ep->sys->wq, &ep->sys->work);
		}
	}
}

void ipa3_suspend_apps_pipes(bool suspend)
{
	struct ipa_ep_cfg_ctrl cfg;
	int ipa_ep_idx;
	struct ipa3_ep_context *ep;

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

	ipa_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS);
	if (ipa3_ctx->ep[ipa_ep_idx].valid)
	ep = &ipa3_ctx->ep[ipa_ep_idx];
	if (ep->valid) {
		IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
			ipa_ep_idx);
		ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
		if (suspend)
			ipa3_gsi_poll_after_suspend(ep);
		else if (!atomic_read(&ep->sys->curr_polling_state))
			gsi_config_channel_mode(ep->gsi_chan_hdl,
				GSI_CHAN_MODE_CALLBACK);
	}

	ipa_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
	if (ipa3_ctx->ep[ipa_ep_idx].valid)
	ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
	/* Considering the case for SSR. */
	if (ipa_ep_idx == -1) {
		IPADBG("Invalid client.\n");
		return;
	}
	ep = &ipa3_ctx->ep[ipa_ep_idx];
	if (ep->valid) {
		IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
			ipa_ep_idx);
		ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
		if (suspend)
			ipa3_gsi_poll_after_suspend(ep);
		else if (!atomic_read(&ep->sys->curr_polling_state))
			gsi_config_channel_mode(ep->gsi_chan_hdl,
				GSI_CHAN_MODE_CALLBACK);
	}
}

/**