2023-01-04 13:21:34

by Jason Gunthorpe

[permalink] [raw]
Subject: Re: [PATCH v4 10/19] iommu: Add set_platform_dma_ops iommu ops

On Wed, Jan 04, 2023 at 08:57:16PM +0800, Lu Baolu wrote:

> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index de91dd88705b..4e35a9f94873 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -2163,6 +2163,17 @@ static int iommu_group_do_detach_device(struct device *dev, void *data)
> return 0;
> }
>
> +static int iommu_group_do_set_platform_dma(struct device *dev, void *data)
> +{
> + const struct iommu_ops *ops = dev_iommu_ops(dev);
> +
> + if (!ops->set_platform_dma_ops)
> + return -EINVAL;
> +
> + ops->set_platform_dma_ops(dev);
> + return 0;
> +}
> +
> static int __iommu_group_set_domain(struct iommu_group *group,
> struct iommu_domain *new_domain)
> {
> @@ -2177,10 +2188,14 @@ static int __iommu_group_set_domain(struct iommu_group *group,
> * platform specific behavior.
> */
> if (!new_domain) {
> - if (WARN_ON(!group->domain->ops->detach_dev))
> - return -EINVAL;

This should still have the WARN_ON..

if (WARN_ON(!group->domain->ops->detach_dev && !dev_iommu_ops(dev)->set_platform_dma_ops)

Jason


2023-01-05 06:18:21

by Baolu Lu

[permalink] [raw]
Subject: Re: [PATCH v4 10/19] iommu: Add set_platform_dma_ops iommu ops

Hi Jason,

On 2023/1/4 21:17, Jason Gunthorpe wrote:
> On Wed, Jan 04, 2023 at 08:57:16PM +0800, Lu Baolu wrote:
>
>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>> index de91dd88705b..4e35a9f94873 100644
>> --- a/drivers/iommu/iommu.c
>> +++ b/drivers/iommu/iommu.c
>> @@ -2163,6 +2163,17 @@ static int iommu_group_do_detach_device(struct device *dev, void *data)
>> return 0;
>> }
>>
>> +static int iommu_group_do_set_platform_dma(struct device *dev, void *data)
>> +{
>> + const struct iommu_ops *ops = dev_iommu_ops(dev);
>> +
>> + if (!ops->set_platform_dma_ops)
>> + return -EINVAL;
>> +
>> + ops->set_platform_dma_ops(dev);
>> + return 0;
>> +}
>> +
>> static int __iommu_group_set_domain(struct iommu_group *group,
>> struct iommu_domain *new_domain)
>> {
>> @@ -2177,10 +2188,14 @@ static int __iommu_group_set_domain(struct iommu_group *group,
>> * platform specific behavior.
>> */
>> if (!new_domain) {
>> - if (WARN_ON(!group->domain->ops->detach_dev))
>> - return -EINVAL;
> This should still have the WARN_ON..
>
> if (WARN_ON(!group->domain->ops->detach_dev && !dev_iommu_ops(dev)->set_platform_dma_ops)

This has been implicitly included in the code.

iommu_group_do_set_platform_dma() returns -EINVAL if the iommu driver
doesn't support set_platform_dma_ops (otherwise always return success).
Then, the domain->ops->detach_dev is required and a WARN_ON was there.

if (!new_domain) {
ret = __iommu_group_for_each_dev(group, NULL,
iommu_group_do_set_platform_dma);
if (ret) {
if (WARN_ON(!group->domain->ops->detach_dev))
return -EINVAL;
__iommu_group_for_each_dev(group, group->domain,
iommu_group_do_detach_device);
}
group->domain = NULL;
return 0;
}

Perhaps I should add a comment to explain this?

--
Best regards,
baolu

2023-01-05 13:40:37

by Jason Gunthorpe

[permalink] [raw]
Subject: Re: [PATCH v4 10/19] iommu: Add set_platform_dma_ops iommu ops

On Thu, Jan 05, 2023 at 01:58:42PM +0800, Baolu Lu wrote:
> Hi Jason,
>
> On 2023/1/4 21:17, Jason Gunthorpe wrote:
> > On Wed, Jan 04, 2023 at 08:57:16PM +0800, Lu Baolu wrote:
> >
> > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> > > index de91dd88705b..4e35a9f94873 100644
> > > --- a/drivers/iommu/iommu.c
> > > +++ b/drivers/iommu/iommu.c
> > > @@ -2163,6 +2163,17 @@ static int iommu_group_do_detach_device(struct device *dev, void *data)
> > > return 0;
> > > }
> > > +static int iommu_group_do_set_platform_dma(struct device *dev, void *data)
> > > +{
> > > + const struct iommu_ops *ops = dev_iommu_ops(dev);
> > > +
> > > + if (!ops->set_platform_dma_ops)
> > > + return -EINVAL;
> > > +
> > > + ops->set_platform_dma_ops(dev);
> > > + return 0;
> > > +}
> > > +
> > > static int __iommu_group_set_domain(struct iommu_group *group,
> > > struct iommu_domain *new_domain)
> > > {
> > > @@ -2177,10 +2188,14 @@ static int __iommu_group_set_domain(struct iommu_group *group,
> > > * platform specific behavior.
> > > */
> > > if (!new_domain) {
> > > - if (WARN_ON(!group->domain->ops->detach_dev))
> > > - return -EINVAL;
> > This should still have the WARN_ON..
> >
> > if (WARN_ON(!group->domain->ops->detach_dev && !dev_iommu_ops(dev)->set_platform_dma_ops)
>
> This has been implicitly included in the code.
>
> iommu_group_do_set_platform_dma() returns -EINVAL if the iommu driver
> doesn't support set_platform_dma_ops (otherwise always return success).
> Then, the domain->ops->detach_dev is required and a WARN_ON was there.
>
> if (!new_domain) {
> ret = __iommu_group_for_each_dev(group, NULL,
> iommu_group_do_set_platform_dma);
> if (ret) {
> if (WARN_ON(!group->domain->ops->detach_dev))
> return -EINVAL;
> __iommu_group_for_each_dev(group, group->domain,
> iommu_group_do_detach_device);
> }
> group->domain = NULL;
> return 0;
> }
>
> Perhaps I should add a comment to explain this?

But you delete this later when you remove this.

I think testing the op directly is much clearer, get rid of the whole
ret and EINVAL thinig:

if (dev_iommu_ops(dev)->set_platform_dma_ops)
__iommu_group_for_each_dev(group, NULL,
iommu_group_do_set_platform_dma); // Can't fail!
else if (group->domain->ops->detach_dev)
__iommu_group_for_each_dev(group, group->domain,
iommu_group_do_detach_device);
else
WARN(true)

Jason

2023-01-06 06:34:19

by Baolu Lu

[permalink] [raw]
Subject: Re: [PATCH v4 10/19] iommu: Add set_platform_dma_ops iommu ops

On 1/5/23 9:15 PM, Jason Gunthorpe wrote:
> On Thu, Jan 05, 2023 at 01:58:42PM +0800, Baolu Lu wrote:
>> Hi Jason,
>>
>> On 2023/1/4 21:17, Jason Gunthorpe wrote:
>>> On Wed, Jan 04, 2023 at 08:57:16PM +0800, Lu Baolu wrote:
>>>
>>>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>>>> index de91dd88705b..4e35a9f94873 100644
>>>> --- a/drivers/iommu/iommu.c
>>>> +++ b/drivers/iommu/iommu.c
>>>> @@ -2163,6 +2163,17 @@ static int iommu_group_do_detach_device(struct device *dev, void *data)
>>>> return 0;
>>>> }
>>>> +static int iommu_group_do_set_platform_dma(struct device *dev, void *data)
>>>> +{
>>>> + const struct iommu_ops *ops = dev_iommu_ops(dev);
>>>> +
>>>> + if (!ops->set_platform_dma_ops)
>>>> + return -EINVAL;
>>>> +
>>>> + ops->set_platform_dma_ops(dev);
>>>> + return 0;
>>>> +}
>>>> +
>>>> static int __iommu_group_set_domain(struct iommu_group *group,
>>>> struct iommu_domain *new_domain)
>>>> {
>>>> @@ -2177,10 +2188,14 @@ static int __iommu_group_set_domain(struct iommu_group *group,
>>>> * platform specific behavior.
>>>> */
>>>> if (!new_domain) {
>>>> - if (WARN_ON(!group->domain->ops->detach_dev))
>>>> - return -EINVAL;
>>> This should still have the WARN_ON..
>>>
>>> if (WARN_ON(!group->domain->ops->detach_dev && !dev_iommu_ops(dev)->set_platform_dma_ops)
>> This has been implicitly included in the code.
>>
>> iommu_group_do_set_platform_dma() returns -EINVAL if the iommu driver
>> doesn't support set_platform_dma_ops (otherwise always return success).
>> Then, the domain->ops->detach_dev is required and a WARN_ON was there.
>>
>> if (!new_domain) {
>> ret = __iommu_group_for_each_dev(group, NULL,
>> iommu_group_do_set_platform_dma);
>> if (ret) {
>> if (WARN_ON(!group->domain->ops->detach_dev))
>> return -EINVAL;
>> __iommu_group_for_each_dev(group, group->domain,
>> iommu_group_do_detach_device);
>> }
>> group->domain = NULL;
>> return 0;
>> }
>>
>> Perhaps I should add a comment to explain this?
> But you delete this later when you remove this.
>
> I think testing the op directly is much clearer, get rid of the whole
> ret and EINVAL thinig:
>
> if (dev_iommu_ops(dev)->set_platform_dma_ops)
> __iommu_group_for_each_dev(group, NULL,
> iommu_group_do_set_platform_dma); // Can't fail!
> else if (group->domain->ops->detach_dev)
> __iommu_group_for_each_dev(group, group->domain,
> iommu_group_do_detach_device);
> else
> WARN(true)

Above looks good to me. Thanks! I have updated this part of code like
below:

@@ -2177,10 +2188,20 @@ static int __iommu_group_set_domain(struct
iommu_group *group,
* platform specific behavior.
*/
if (!new_domain) {
- if (WARN_ON(!group->domain->ops->detach_dev))
- return -EINVAL;
- __iommu_group_for_each_dev(group, group->domain,
- iommu_group_do_detach_device);
+ struct group_device *grp_dev;
+
+ grp_dev = list_first_entry(&group->devices,
+ struct group_device, list);
+
+ if (dev_iommu_ops(grp_dev->dev)->set_platform_dma_ops)
+ __iommu_group_for_each_dev(group, NULL,
+ iommu_group_do_set_platform_dma);
+ else if (group->domain->ops->detach_dev)
+ __iommu_group_for_each_dev(group, group->domain,
+ iommu_group_do_detach_device);
+ else
+ WARN_ON_ONCE(1);
+
group->domain = NULL;
return 0;
}

--
Best regards,
baolu

2023-01-06 15:07:01

by Jason Gunthorpe

[permalink] [raw]
Subject: Re: [PATCH v4 10/19] iommu: Add set_platform_dma_ops iommu ops

On Fri, Jan 06, 2023 at 02:07:32PM +0800, Baolu Lu wrote:

> Above looks good to me. Thanks! I have updated this part of code like
> below:
>
> @@ -2177,10 +2188,20 @@ static int __iommu_group_set_domain(struct
> iommu_group *group,
> * platform specific behavior.
> */
> if (!new_domain) {
> - if (WARN_ON(!group->domain->ops->detach_dev))
> - return -EINVAL;
> - __iommu_group_for_each_dev(group, group->domain,
> - iommu_group_do_detach_device);
> + struct group_device *grp_dev;
> +
> + grp_dev = list_first_entry(&group->devices,
> + struct group_device, list);

It seems OK - I hope we naturally can't ever get in a situation where
a group has disjoint iommu drivers.

Jason

2023-01-07 03:16:42

by Baolu Lu

[permalink] [raw]
Subject: Re: [PATCH v4 10/19] iommu: Add set_platform_dma_ops iommu ops

On 1/6/2023 10:26 PM, Jason Gunthorpe wrote:
> On Fri, Jan 06, 2023 at 02:07:32PM +0800, Baolu Lu wrote:
>
>> Above looks good to me. Thanks! I have updated this part of code like
>> below:
>>
>> @@ -2177,10 +2188,20 @@ static int __iommu_group_set_domain(struct
>> iommu_group *group,
>> * platform specific behavior.
>> */
>> if (!new_domain) {
>> - if (WARN_ON(!group->domain->ops->detach_dev))
>> - return -EINVAL;
>> - __iommu_group_for_each_dev(group, group->domain,
>> - iommu_group_do_detach_device);
>> + struct group_device *grp_dev;
>> +
>> + grp_dev = list_first_entry(&group->devices,
>> + struct group_device, list);
> It seems OK - I hope we naturally can't ever get in a situation where
> a group has disjoint iommu drivers.

The final code after cleanup looks like below. We will WARN_ON the lack
of callback in the iommu_group_do_set_platform_dma() helper.

2152 static int iommu_group_do_set_platform_dma(struct device *dev, void
*data)
2153 {
2154 const struct iommu_ops *ops = dev_iommu_ops(dev);
2155
2156 if (!WARN_ON(!ops->set_platform_dma_ops))
2157 ops->set_platform_dma_ops(dev);
2158
2159 return 0;
2160 }
2161
2162 static int __iommu_group_set_domain(struct iommu_group *group,
2163 struct iommu_domain *new_domain)
2164 {
2165 int ret;
2166
2167 if (group->domain == new_domain)
2168 return 0;
2169
2170 /*
2171 * New drivers should support default domains, so
set_platform_dma()
2172 * op will never be called. Otherwise the NULL domain
represents some
2173 * platform specific behavior.
2174 */
2175 if (!new_domain) {
2176 __iommu_group_for_each_dev(group, NULL,
2177
iommu_group_do_set_platform_dma);
2178 group->domain = NULL;
2179 return 0;
2180 }

How do you like this?

--
Best regards,
baolu

2023-01-09 12:33:43

by Jason Gunthorpe

[permalink] [raw]
Subject: Re: [PATCH v4 10/19] iommu: Add set_platform_dma_ops iommu ops

On Sat, Jan 07, 2023 at 10:48:31AM +0800, Baolu Lu wrote:
> On 1/6/2023 10:26 PM, Jason Gunthorpe wrote:
> > On Fri, Jan 06, 2023 at 02:07:32PM +0800, Baolu Lu wrote:
> >
> > > Above looks good to me. Thanks! I have updated this part of code like
> > > below:
> > >
> > > @@ -2177,10 +2188,20 @@ static int __iommu_group_set_domain(struct
> > > iommu_group *group,
> > > * platform specific behavior.
> > > */
> > > if (!new_domain) {
> > > - if (WARN_ON(!group->domain->ops->detach_dev))
> > > - return -EINVAL;
> > > - __iommu_group_for_each_dev(group, group->domain,
> > > - iommu_group_do_detach_device);
> > > + struct group_device *grp_dev;
> > > +
> > > + grp_dev = list_first_entry(&group->devices,
> > > + struct group_device, list);
> > It seems OK - I hope we naturally can't ever get in a situation where
> > a group has disjoint iommu drivers.
>
> The final code after cleanup looks like below. We will WARN_ON the lack
> of callback in the iommu_group_do_set_platform_dma() helper.

Yeah OK

Jason