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