Skip to content

Commit e3d4571

Browse files
stephan-ghandersson
authored andcommitted
soc: qcom: smsm: Fix missed interrupts if state changes while masked
The SMSM driver detects interrupt edges by tracking the last state it has seen (and has triggered the interrupt handler for). This works fine, but only if the interrupt does not change state while masked. For example, if an interrupt is unmasked while the state is HIGH, the stored last_value for that interrupt might still be LOW. Then, when the remote processor triggers smsm_intr() we assume that nothing has changed, even though the state might have changed from HIGH to LOW. Attempt to fix this by checking the current remote state before unmasking an IRQ. Use atomic operations to avoid the interrupt handler from interfering with the unmask function. This fixes modem crashes in some edge cases with the BAM-DMUX driver. Specifically, the BAM-DMUX interrupt handler is not called for the HIGH -> LOW smsm state transition if the BAM-DMUX driver is loaded (and therefore unmasks the interrupt) after the modem was already started: qcom-q6v5-mss 4080000.remoteproc: fatal error received: a2_task.c:3188: Assert FALSE failed: A2 DL PER deadlock timer expired waiting for Apps ACK Fixes: c97c409 ("soc: qcom: smsm: Add driver for Qualcomm SMSM") Signed-off-by: Stephan Gerhold <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Bjorn Andersson <[email protected]>
1 parent c73a685 commit e3d4571

File tree

1 file changed

+8
-3
lines changed

1 file changed

+8
-3
lines changed

drivers/soc/qcom/smsm.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ struct smsm_entry {
109109
DECLARE_BITMAP(irq_enabled, 32);
110110
DECLARE_BITMAP(irq_rising, 32);
111111
DECLARE_BITMAP(irq_falling, 32);
112-
u32 last_value;
112+
unsigned long last_value;
113113

114114
u32 *remote_state;
115115
u32 *subscription;
@@ -204,8 +204,7 @@ static irqreturn_t smsm_intr(int irq, void *data)
204204
u32 val;
205205

206206
val = readl(entry->remote_state);
207-
changed = val ^ entry->last_value;
208-
entry->last_value = val;
207+
changed = val ^ xchg(&entry->last_value, val);
209208

210209
for_each_set_bit(i, entry->irq_enabled, 32) {
211210
if (!(changed & BIT(i)))
@@ -264,6 +263,12 @@ static void smsm_unmask_irq(struct irq_data *irqd)
264263
struct qcom_smsm *smsm = entry->smsm;
265264
u32 val;
266265

266+
/* Make sure our last cached state is up-to-date */
267+
if (readl(entry->remote_state) & BIT(irq))
268+
set_bit(irq, &entry->last_value);
269+
else
270+
clear_bit(irq, &entry->last_value);
271+
267272
set_bit(irq, entry->irq_enabled);
268273

269274
if (entry->subscription) {

0 commit comments

Comments
 (0)