On Tue, Jan 14, 2020 at 03:25:39PM +0000, Will Deacon wrote:
> On Thu, Dec 19, 2019 at 05:30:31PM +0100, Jean-Philippe Brucker wrote:
> > Let add_device() clean up after itself. The iommu_bus_init() function
> > does call remove_device() on error, but other sites (e.g. of_iommu) do
> > not.
> > 
> > Don't free level-2 stream tables because we'd have to track if we
> > allocated each of them or if they are used by other endpoints. It's not
> > worth the hassle since they are managed resources.
> > 
> > Reviewed-by: Eric Auger <eric.au...@redhat.com>
> > Reviewed-by: Jonathan Cameron <jonathan.came...@huawei.com>
> > Signed-off-by: Jean-Philippe Brucker <jean-phili...@linaro.org>
> > ---
> >  drivers/iommu/arm-smmu-v3.c | 28 +++++++++++++++++++++-------
> >  1 file changed, 21 insertions(+), 7 deletions(-)
> 
> I think this is alright, with one caveat relating to:
> 
> 
>       /*
>        * We _can_ actually withstand dodgy bus code re-calling add_device()
>        * without an intervening remove_device()/of_xlate() sequence, but
>        * we're not going to do so quietly...
>        */
>       if (WARN_ON_ONCE(fwspec->iommu_priv)) {
>               master = fwspec->iommu_priv;
>               smmu = master->smmu;
>       } ...
> 
> 
> which may be on shakey ground if the subsequent add_device() call can fail
> and free stuff that the first one allocated. At least, I don't know what
> we're trying to support with this, so it's hard to tell whether or not it
> still works as intended after your change.
> 
> How is this supposed to work? I don't recall ever seeing that WARN fire,
> so can we just remove this and bail instead? Robin?
> 
> Something like below before your changes...

FWIW, I've written this as a patch locally, since I'd like to apply it
on top of v5 of your series.

Will

--->8

>From 6029102f406d4db5e7a465da5fd2e08a5b12c532 Mon Sep 17 00:00:00 2001
From: Will Deacon <w...@kernel.org>
Date: Wed, 15 Jan 2020 15:35:16 +0000
Subject: [PATCH] iommu/arm-smmu-v3: Return -EBUSY when trying to re-add a
 device

Although we WARN in arm_smmu_add_device() if the device being added has
been added already without a subsequent call to arm_smmu_remove_device(),
we still continue half-heartedly, initialising the stream-table for any
new StreamIDs that may have magically appeared and re-establishing device
links that should still be there from last time.

Given that calling ->add_device() twice without removing the device in the
meantime is indicative of an error in the caller, just return -EBUSY after
warning.

Cc: Robin Murphy <robin.mur...@arm.com>
Cc: Jean Philippe-Brucker <jean-phili...@linaro.org>
Signed-off-by: Will Deacon <w...@kernel.org>
---
 drivers/iommu/arm-smmu-v3.c | 37 ++++++++++++++++---------------------
 1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index efa326601308..cc26e1323da3 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -2841,28 +2841,23 @@ static int arm_smmu_add_device(struct device *dev)
 
        if (!fwspec || fwspec->ops != &arm_smmu_ops)
                return -ENODEV;
-       /*
-        * We _can_ actually withstand dodgy bus code re-calling add_device()
-        * without an intervening remove_device()/of_xlate() sequence, but
-        * we're not going to do so quietly...
-        */
-       if (WARN_ON_ONCE(fwspec->iommu_priv)) {
-               master = fwspec->iommu_priv;
-               smmu = master->smmu;
-       } else {
-               smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
-               if (!smmu)
-                       return -ENODEV;
-               master = kzalloc(sizeof(*master), GFP_KERNEL);
-               if (!master)
-                       return -ENOMEM;
 
-               master->dev = dev;
-               master->smmu = smmu;
-               master->sids = fwspec->ids;
-               master->num_sids = fwspec->num_ids;
-               fwspec->iommu_priv = master;
-       }
+       if (WARN_ON_ONCE(fwspec->iommu_priv))
+               return -EBUSY;
+
+       smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
+       if (!smmu)
+               return -ENODEV;
+
+       master = kzalloc(sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+       master->dev = dev;
+       master->smmu = smmu;
+       master->sids = fwspec->ids;
+       master->num_sids = fwspec->num_ids;
+       fwspec->iommu_priv = master;
 
        /* Check the SIDs are in range of the SMMU and our stream table */
        for (i = 0; i < master->num_sids; i++) {
-- 
2.25.0.rc1.283.g88dfdc4193-goog

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to