[PATCH] iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any

tomas.krcka@gmail.com posted 1 patch 2 years, 10 months ago
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
[PATCH] iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any
Posted by tomas.krcka@gmail.com 2 years, 10 months ago
From: Tomas Krcka <krckatom@amazon.de>

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>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index f2425b0f0cd6..7614739ea2c1 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -152,6 +152,18 @@ static void queue_inc_cons(struct arm_smmu_ll_queue *q)
 	q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
 }
 
+static void queue_sync_cons_ovf(struct arm_smmu_queue *q)
+{
+	struct arm_smmu_ll_queue *llq = &q->llq;
+
+	if (likely(Q_OVF(llq->prod) == Q_OVF(llq->cons)))
+		return;
+
+	llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
+		      Q_IDX(llq, llq->cons);
+	queue_sync_cons_out(q);
+}
+
 static int queue_sync_prod_in(struct arm_smmu_queue *q)
 {
 	u32 prod;
@@ -1577,8 +1589,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 	} while (!queue_empty(llq));
 
 	/* Sync our overflow flag, as we believe we're up to speed */
-	llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
-		    Q_IDX(llq, llq->cons);
+	queue_sync_cons_ovf(q);
 	return IRQ_HANDLED;
 }
 
@@ -1636,9 +1647,7 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
 	} while (!queue_empty(llq));
 
 	/* Sync our overflow flag, as we believe we're up to speed */
-	llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
-		      Q_IDX(llq, llq->cons);
-	queue_sync_cons_out(q);
+	queue_sync_cons_ovf(q);
 	return IRQ_HANDLED;
 }
 
-- 
2.39.2
Re: [PATCH] iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any
Posted by Will Deacon 2 years, 10 months ago
On Wed, 29 Mar 2023 12:34:19 +0000, tomas.krcka@gmail.com wrote:
> From: Tomas Krcka <krckatom@amazon.de>
> 
> 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.
> 
> [...]

Applied to will (for-joerg/arm-smmu/updates), thanks!

[1/1] iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any
      https://git.kernel.org/will/c/67ea0b7ce418

Cheers,
-- 
Will

https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev
Re: [PATCH] iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any
Posted by Tomas Krcka 2 years, 10 months ago
Am Mi., 29. März 2023 um 14:34 Uhr schrieb <tomas.krcka@gmail.com>:
>
> From: Tomas Krcka <krckatom@amazon.de>
>
> 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>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 19 ++++++++++++++-----
>  1 file changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index f2425b0f0cd6..7614739ea2c1 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -152,6 +152,18 @@ static void queue_inc_cons(struct arm_smmu_ll_queue *q)
>         q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
>  }
>
> +static void queue_sync_cons_ovf(struct arm_smmu_queue *q)
> +{
> +       struct arm_smmu_ll_queue *llq = &q->llq;
> +
> +       if (likely(Q_OVF(llq->prod) == Q_OVF(llq->cons)))
> +               return;
> +
> +       llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
> +                     Q_IDX(llq, llq->cons);
> +       queue_sync_cons_out(q);
> +}
> +
>  static int queue_sync_prod_in(struct arm_smmu_queue *q)
>  {
>         u32 prod;
> @@ -1577,8 +1589,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>         } while (!queue_empty(llq));
>
>         /* Sync our overflow flag, as we believe we're up to speed */
> -       llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
> -                   Q_IDX(llq, llq->cons);
> +       queue_sync_cons_ovf(q);
>         return IRQ_HANDLED;
>  }
>
> @@ -1636,9 +1647,7 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
>         } while (!queue_empty(llq));
>
>         /* Sync our overflow flag, as we believe we're up to speed */
> -       llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
> -                     Q_IDX(llq, llq->cons);
> -       queue_sync_cons_out(q);
> +       queue_sync_cons_ovf(q);
>         return IRQ_HANDLED;
>  }
>
> --
> 2.39.2
>

ping for this patch ...