CDNS_MCP_INT_SLAVE_MASK, 0);
int_status &= ~CDNS_MCP_INT_SLAVE_MASK;
- schedule_work(&cdns->work);
+
+ /*
+ * Deal with possible race condition between interrupt
+ * handling and disabling interrupts on suspend.
+ *
+ * If the master is in the process of disabling
+ * interrupts, don't schedule a workqueue
+ */
+ if (cdns->interrupt_enabled)
+ schedule_work(&cdns->work);
}
cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status);
slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave_state);
}
+ cdns->interrupt_enabled = state;
+
+ /*
+ * Complete any on-going status updates before updating masks,
+ * and cancel queued status updates.
+ *
+ * There could be a race with a new interrupt thrown before
+ * the 3 mask updates below are complete, so in the interrupt
+ * we use the 'interrupt_enabled' status to prevent new work
+ * from being queued.
+ */
+ if (!state)
+ cancel_work_sync(&cdns->work);
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0);
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1);