1 From 1a27f2261b683a80ba80c38bc477757534550ac6 Mon Sep 17 00:00:00 2001
2 From: Will Deacon <will.deacon@arm.com>
3 Date: Wed, 7 Nov 2018 22:58:24 +0000
4 Subject: iommu/arm-smmu-v3: Use explicit mb() when moving cons pointer
6 [ Upstream commit a868e8530441286342f90c1fd9c5f24de3aa2880 ]
8 After removing an entry from a queue (e.g. reading an event in
9 arm_smmu_evtq_thread()) it is necessary to advance the MMIO consumer
10 pointer to free the queue slot back to the SMMU. A memory barrier is
11 required here so that all reads targetting the queue entry have
12 completed before the consumer pointer is updated.
14 The implementation of queue_inc_cons() relies on a writel() to complete
15 the previous reads, but this is incorrect because writel() is only
16 guaranteed to complete prior writes. This patch replaces the call to
17 writel() with an mb(); writel_relaxed() sequence, which gives us the
18 read->write ordering which we require.
20 Cc: Robin Murphy <robin.murphy@arm.com>
21 Signed-off-by: Will Deacon <will.deacon@arm.com>
22 Signed-off-by: Sasha Levin <sashal@kernel.org>
24 drivers/iommu/arm-smmu-v3.c | 8 +++++++-
25 1 file changed, 7 insertions(+), 1 deletion(-)
27 diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
28 index 26e99c03390f..09eb258a9a7d 100644
29 --- a/drivers/iommu/arm-smmu-v3.c
30 +++ b/drivers/iommu/arm-smmu-v3.c
31 @@ -730,7 +730,13 @@ static void queue_inc_cons(struct arm_smmu_queue *q)
32 u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1;
34 q->cons = Q_OVF(q, q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
35 - writel(q->cons, q->cons_reg);
38 + * Ensure that all CPU accesses (reads and writes) to the queue
39 + * are complete before we update the cons pointer.
42 + writel_relaxed(q->cons, q->cons_reg);
45 static int queue_sync_prod(struct arm_smmu_queue *q)