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

Commit 8492131e authored by Amir Levy's avatar Amir Levy
Browse files

msm: ipa3: workaround for HW limitation suspend IRQ not generated



On ipa_v3 HW suspend IRQ is not generated for timer
expiration \ force close of an open aggregation frame when a producer
is suspended. This workaround force closes the aggregation frame
and emulates a suspend IRQ in software in order to bypass this limitation.

Change-Id: I728cb540a34d051bc14ab3ed6440284f6513f1f4
Signed-off-by: default avatarAmir Levy <alevy@codeaurora.org>
parent abbec11b
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -2077,6 +2077,10 @@ int _ipa_read_dbg_cnt_v3_0(char *buf, int max_len);
void _ipa_enable_clks_v3_0(void);
void _ipa_disable_clks_v3_0(void);
struct device *ipa3_get_dma_dev(void);
void ipa3_suspend_active_aggr_wa(u32 clnt_hdl);
void ipa3_suspend_handler(enum ipa_irq_type interrupt,
				void *private_data,
				void *interrupt_data);


static inline u32 ipa_read_reg(void *base, u32 offset)
+57 −0
Original line number Diff line number Diff line
@@ -426,3 +426,60 @@ int ipa3_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev)
	spin_lock_init(&suspend_wa_lock);
	return 0;
}

/**
* ipa3_suspend_active_aggr_wa() - Emulate suspend IRQ
* @clnt_hndl:		suspended client handle, IRQ is emulated for this pipe
*
*  Emulate suspend IRQ to unsuspend client which was suspended with an open
*  aggregation frame in order to bypass HW bug of IRQ not generated when
*  endpoint is suspended during an open aggregation.
*/
void ipa3_suspend_active_aggr_wa(u32 clnt_hdl)
{
	struct ipa3_interrupt_info interrupt_info;
	struct ipa3_interrupt_work_wrap *work_data;
	struct ipa_tx_suspend_irq_data *suspend_interrupt_data;
	int irq_num;
	int aggr_active_bitmap = ipa_read_reg(ipa3_ctx->mmio,
			IPA_STATE_AGGR_ACTIVE_OFST);

	if (aggr_active_bitmap & (1 << clnt_hdl)) {
		/* force close aggregation */
		ipa_write_reg(ipa3_ctx->mmio, IPA_AGGR_FORCE_CLOSE_OFST,
				(1 << clnt_hdl));

		/* simulate suspend IRQ */
		irq_num = ipa3_irq_mapping[IPA_TX_SUSPEND_IRQ];
		interrupt_info = ipa_interrupt_to_cb[irq_num];
		if (interrupt_info.handler == NULL) {
			IPAERR("no CB function for IPA_TX_SUSPEND_IRQ!\n");
			return;
		}
		suspend_interrupt_data = kzalloc(
				sizeof(*suspend_interrupt_data),
				GFP_KERNEL);
		if (!suspend_interrupt_data) {
			IPAERR("failed allocating suspend_interrupt_data\n");
			return;
		}
		suspend_interrupt_data->endpoints = 1 << clnt_hdl;

		work_data = kzalloc(sizeof(struct ipa3_interrupt_work_wrap),
				GFP_KERNEL);
		if (!work_data) {
			IPAERR("failed allocating ipa3_interrupt_work_wrap\n");
			goto fail_alloc_work;
		}
		INIT_WORK(&work_data->interrupt_work,
				ipa3_deferred_interrupt_work);
		work_data->handler = interrupt_info.handler;
		work_data->interrupt = IPA_TX_SUSPEND_IRQ;
		work_data->private_data = interrupt_info.private_data;
		work_data->interrupt_data = (void *)suspend_interrupt_data;
		queue_work(ipa_interrupt_wq, &work_data->interrupt_work);
		return;
fail_alloc_work:
		kfree(suspend_interrupt_data);
	}
}
+4 −1
Original line number Diff line number Diff line
@@ -2994,8 +2994,11 @@ int ipa3_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl)
	ipa_write_reg(ipa3_ctx->mmio,
		IPA_ENDP_INIT_CTRL_N_OFST(clnt_hdl), reg_val);

	return 0;
	if (ep_ctrl->ipa_ep_suspend == true &&
			IPA_CLIENT_IS_CONS(ipa3_ctx->ep[clnt_hdl].client))
		ipa3_suspend_active_aggr_wa(clnt_hdl);

	return 0;
}

/**