Skip to content

Commit 67ea0b7

Browse files
Tomas Krckawilldeacon
authored andcommitted
iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any
When an overflow occurs in the PRI queue, the SMMU toggles the overflow flag in the PROD register. To exit the overflow condition, the PRI thread is supposed to acknowledge it by toggling this flag in the CONS register. Unacknowledged overflow causes the queue to stop adding anything new. Currently, the priq thread always writes the CONS register back to the SMMU after clearing the queue. The writeback is not necessary if the OVFLG in the PROD register has not been changed, no overflow has occured. This commit checks the difference of the overflow flag between CONS and PROD register. If it's different, toggles the OVACKFLG flag in the CONS register and write it to the SMMU. The situation is similar for the event queue. The acknowledge register is also toggled after clearing the event queue but never propagated to the hardware. This would only be done the next time when executing evtq thread. Unacknowledged event queue overflow doesn't affect the event queue, because the SMMU still adds elements to that queue when the overflow condition is active. But it feel nicer to keep SMMU in sync when possible, so use the same way here as well. Signed-off-by: Tomas Krcka <krckatom@amazon.de> Link: https://lore.kernel.org/r/20230329123420.34641-1-tomas.krcka@gmail.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent 1226113 commit 67ea0b7

1 file changed

Lines changed: 14 additions & 5 deletions

File tree

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ static void queue_inc_cons(struct arm_smmu_ll_queue *q)
152152
q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
153153
}
154154

155+
static void queue_sync_cons_ovf(struct arm_smmu_queue *q)
156+
{
157+
struct arm_smmu_ll_queue *llq = &q->llq;
158+
159+
if (likely(Q_OVF(llq->prod) == Q_OVF(llq->cons)))
160+
return;
161+
162+
llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
163+
Q_IDX(llq, llq->cons);
164+
queue_sync_cons_out(q);
165+
}
166+
155167
static int queue_sync_prod_in(struct arm_smmu_queue *q)
156168
{
157169
u32 prod;
@@ -1577,8 +1589,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
15771589
} while (!queue_empty(llq));
15781590

15791591
/* Sync our overflow flag, as we believe we're up to speed */
1580-
llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
1581-
Q_IDX(llq, llq->cons);
1592+
queue_sync_cons_ovf(q);
15821593
return IRQ_HANDLED;
15831594
}
15841595

@@ -1636,9 +1647,7 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
16361647
} while (!queue_empty(llq));
16371648

16381649
/* Sync our overflow flag, as we believe we're up to speed */
1639-
llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
1640-
Q_IDX(llq, llq->cons);
1641-
queue_sync_cons_out(q);
1650+
queue_sync_cons_ovf(q);
16421651
return IRQ_HANDLED;
16431652
}
16441653

0 commit comments

Comments
 (0)