summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlex Elder <elder@linaro.org>2020-12-22 12:00:10 -0600
committerJakub Kicinski <kuba@kernel.org>2020-12-23 12:17:48 -0800
commit94ad8f3ac6aff5acde3f6c4719997efc61e0dccf (patch)
tree5295ed6fc70bd2a176864a7e5057b08f3549bf44 /drivers
parent8450e23f142f629e40bd67afc8375c86c7fbf8f1 (diff)
net: ipa: clear pending interrupts before enabling
We enable the completion interrupt for channel or event ring commands only when we issue them. The interrupt is disabled after the interrupt has fired, or after we have timed out waiting for it. If we time out, the command could complete after the interrupt has been disabled, causing a state change in the channel or event ring. The interrupt associated with that state change would be delivered the next time the completion interrupt is enabled. To avoid previous command completions interfering with new commands, clear all pending completion interrupts before re-enabling them for a new command. Fixes: b4175f8731f78 ("net: ipa: only enable GSI event control IRQs when needed") Signed-off-by: Alex Elder <elder@linaro.org> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ipa/gsi.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c
index c4795249719d..4aee60d62ab0 100644
--- a/drivers/net/ipa/gsi.c
+++ b/drivers/net/ipa/gsi.c
@@ -340,7 +340,13 @@ static int evt_ring_command(struct gsi *gsi, u32 evt_ring_id,
* is issued here. Only permit *this* event ring to trigger
* an interrupt, and only enable the event control IRQ type
* when we expect it to occur.
+ *
+ * There's a small chance that a previous command completed
+ * after the interrupt was disabled, so make sure we have no
+ * pending interrupts before we enable them.
*/
+ iowrite32(~0, gsi->virt + GSI_CNTXT_SRC_EV_CH_IRQ_CLR_OFFSET);
+
val = BIT(evt_ring_id);
iowrite32(val, gsi->virt + GSI_CNTXT_SRC_EV_CH_IRQ_MSK_OFFSET);
gsi_irq_type_enable(gsi, GSI_EV_CTRL);
@@ -453,7 +459,13 @@ gsi_channel_command(struct gsi_channel *channel, enum gsi_ch_cmd_opcode opcode)
* issued here. So we only permit *this* channel to trigger
* an interrupt and only enable the channel control IRQ type
* when we expect it to occur.
+ *
+ * There's a small chance that a previous command completed
+ * after the interrupt was disabled, so make sure we have no
+ * pending interrupts before we enable them.
*/
+ iowrite32(~0, gsi->virt + GSI_CNTXT_SRC_CH_IRQ_CLR_OFFSET);
+
val = BIT(channel_id);
iowrite32(val, gsi->virt + GSI_CNTXT_SRC_CH_IRQ_MSK_OFFSET);
gsi_irq_type_enable(gsi, GSI_CH_CTRL);