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

Commit 146680f1 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 1e5f1a2f 5f24436f
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);
		}
	}
}