Message ID | 20230329123420.34641-1-tomas.krcka@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any | expand |
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 ...
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,
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; }