msm: ipa: clear uC interrupt only before processing

Clearing Non uC interrupts before processing will
result in clearing interrupt data.

Change-Id: I47ea7c22250264da206e1fb8691e77224c825ab0
CRs-Fixed: 1008549
Acked-by: Mohammed Javid <mjavid@qti.qualcomm.com>
Signed-off-by: sunil paidimarri <hisunil@codeaurora.org>
This commit is contained in:
sunil paidimarri 2016-05-17 17:06:12 -07:00 committed by syphyr
parent f290807c52
commit a78f95743c
1 changed files with 35 additions and 18 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -16,6 +16,7 @@
struct ipa_interrupt_info {
ipa_irq_handler_t handler;
enum ipa_irq_type interrupt;
void *private_data;
bool deferred_flag;
};
@ -126,37 +127,52 @@ fail_alloc_work:
return res;
}
static inline bool is_uc_irq(int irq_num)
{
if (ipa_interrupt_to_cb[irq_num].interrupt >= IPA_UC_IRQ_0 &&
ipa_interrupt_to_cb[irq_num].interrupt <= IPA_UC_IRQ_3)
return true;
else
return false;
}
static void ipa_process_interrupts(bool isr_context)
{
u32 reg;
u32 bmsk;
u32 i = 0;
u32 en;
bool uc_irq;
en = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee));
reg = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_STTS_EE_n_ADDR(ipa_ee));
while (en & reg) {
/*
* Clear interrupt before processing to avoid
* clearing unhandled interrupts
*/
ipa_write_reg(ipa_ctx->mmio,
IPA_IRQ_CLR_EE_n_ADDR(ipa_ee), reg);
/*
* Process the interrupts
*/
bmsk = 1;
for (i = 0; i < IPA_IRQ_MAX; i++) {
if (en & reg & bmsk)
handle_interrupt(i, isr_context);
if (!(en & reg & bmsk)) {
bmsk = bmsk << 1;
continue;
}
uc_irq = is_uc_irq(i);
/* Clear uC interrupt before processing to avoid
clearing unhandled interrupts */
if (uc_irq)
ipa_write_reg(ipa_ctx->mmio,
IPA_IRQ_CLR_EE_n_ADDR(ipa_ee), bmsk);
/* Process the interrupts */
handle_interrupt(i, isr_context);
/* Clear non uC interrupt after processing
to avoid clearing interrupt data */
if (!uc_irq)
ipa_write_reg(ipa_ctx->mmio,
IPA_IRQ_CLR_EE_n_ADDR(ipa_ee), bmsk);
bmsk = bmsk << 1;
}
/*
* Check pending interrupts that may have
* been raised since last read
*/
/* Check pending interrupts that may have
been raised since last read */
reg = ipa_read_reg(ipa_ctx->mmio,
IPA_IRQ_STTS_EE_n_ADDR(ipa_ee));
}
@ -221,6 +237,7 @@ int ipa_add_interrupt_handler(enum ipa_irq_type interrupt,
ipa_interrupt_to_cb[interrupt].deferred_flag = deferred_flag;
ipa_interrupt_to_cb[interrupt].handler = handler;
ipa_interrupt_to_cb[interrupt].private_data = private_data;
ipa_interrupt_to_cb[interrupt].interrupt = interrupt;
val = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee));
IPADBG("read IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val);