diff mbox series

[02/13] iommu: Move bus setup to IOMMU device registration

Message ID e607a32be8e84c56d65160902f4bd3fb434ee9d3.1649935679.git.robin.murphy@arm.com (mailing list archive)
State New, archived
Headers show
Series iommu: Retire bus_set_iommu() | expand

Commit Message

Robin Murphy April 14, 2022, 12:42 p.m. UTC
Move the bus setup to iommu_device_register(). This should allow
bus_iommu_probe() to be correctly replayed for multiple IOMMU instances,
and leaves bus_set_iommu() as a glorfied no-op to be cleaned up next.

Note that although the handling of errors from bus_iommu_probe() looks
inadequate, it is merely preserving the well-established existing
behaviour. This could be improved in future - probably combined with
equivalent cleanup for iommu_device_unregister() - but that isn't a
priority right now.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
 drivers/iommu/iommu.c | 50 ++++++++++++++++++++++---------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

Comments

Baolu Lu April 16, 2022, 12:04 a.m. UTC | #1
On 2022/4/14 20:42, Robin Murphy wrote:
> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct bus_type *bus)
>    */
>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
>   {
> -	int err;
> -
> -	if (ops == NULL) {
> -		bus->iommu_ops = NULL;
> -		return 0;
> -	}
> -
> -	if (bus->iommu_ops != NULL)
> +	if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>   		return -EBUSY;
>   
>   	bus->iommu_ops = ops;

Do we still need to keep above lines in bus_set_iommu()?

Best regards,
baolu
Robin Murphy April 18, 2022, 10:09 p.m. UTC | #2
On 2022-04-16 01:04, Lu Baolu wrote:
> On 2022/4/14 20:42, Robin Murphy wrote:
>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct bus_type *bus)
>>    */
>>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
>>   {
>> -    int err;
>> -
>> -    if (ops == NULL) {
>> -        bus->iommu_ops = NULL;
>> -        return 0;
>> -    }
>> -
>> -    if (bus->iommu_ops != NULL)
>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>           return -EBUSY;
>>       bus->iommu_ops = ops;
> 
> Do we still need to keep above lines in bus_set_iommu()?

It preserves the existing behaviour until each callsite and its 
associated error handling are removed later on, which seems like as good 
a thing to do as any. Since I'm already relaxing iommu_device_register() 
to a warn-but-continue behaviour while it keeps the bus ops on 
life-support internally, I figured not changing too much at once would 
make it easier to bisect any potential issues arising from this first step.

Thanks,
Robin.
Baolu Lu April 18, 2022, 11:37 p.m. UTC | #3
On 2022/4/19 6:09, Robin Murphy wrote:
> On 2022-04-16 01:04, Lu Baolu wrote:
>> On 2022/4/14 20:42, Robin Murphy wrote:
>>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct bus_type *bus)
>>>    */
>>>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
>>>   {
>>> -    int err;
>>> -
>>> -    if (ops == NULL) {
>>> -        bus->iommu_ops = NULL;
>>> -        return 0;
>>> -    }
>>> -
>>> -    if (bus->iommu_ops != NULL)
>>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>>           return -EBUSY;
>>>       bus->iommu_ops = ops;
>>
>> Do we still need to keep above lines in bus_set_iommu()?
> 
> It preserves the existing behaviour until each callsite and its 
> associated error handling are removed later on, which seems like as good 
> a thing to do as any. Since I'm already relaxing iommu_device_register() 
> to a warn-but-continue behaviour while it keeps the bus ops on 
> life-support internally, I figured not changing too much at once would 
> make it easier to bisect any potential issues arising from this first step.

Fair enough. Thank you for the explanation.

Do you have a public tree that I could pull these patches and try them
on an Intel hardware? Or perhaps you have done this? I like the whole
idea of this series, but it's better to try it with a real hardware.

Best regards,
baolu
Robin Murphy April 19, 2022, 7:20 a.m. UTC | #4
On 2022-04-19 00:37, Lu Baolu wrote:
> On 2022/4/19 6:09, Robin Murphy wrote:
>> On 2022-04-16 01:04, Lu Baolu wrote:
>>> On 2022/4/14 20:42, Robin Murphy wrote:
>>>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct bus_type *bus)
>>>>    */
>>>>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
>>>>   {
>>>> -    int err;
>>>> -
>>>> -    if (ops == NULL) {
>>>> -        bus->iommu_ops = NULL;
>>>> -        return 0;
>>>> -    }
>>>> -
>>>> -    if (bus->iommu_ops != NULL)
>>>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>>>           return -EBUSY;
>>>>       bus->iommu_ops = ops;
>>>
>>> Do we still need to keep above lines in bus_set_iommu()?
>>
>> It preserves the existing behaviour until each callsite and its 
>> associated error handling are removed later on, which seems like as 
>> good a thing to do as any. Since I'm already relaxing 
>> iommu_device_register() to a warn-but-continue behaviour while it 
>> keeps the bus ops on life-support internally, I figured not changing 
>> too much at once would make it easier to bisect any potential issues 
>> arising from this first step.
> 
> Fair enough. Thank you for the explanation.
> 
> Do you have a public tree that I could pull these patches and try them
> on an Intel hardware? Or perhaps you have done this? I like the whole
> idea of this series, but it's better to try it with a real hardware.

I haven't bothered with separate branches since there's so many 
different pieces in-flight, but my complete (unstable) development 
branch can be found here:

https://gitlab.arm.com/linux-arm/linux-rm/-/commits/iommu/bus

For now I'd recommend winding the head back to "iommu: Clean up 
bus_set_iommu()" for testing - some of the patches above that have 
already been posted and picked up by their respective subsystems, but 
others are incomplete and barely compile-tested. I'll probably rearrange 
it later this week to better reflect what's happened so far.

Cheers,
Robin.
Baolu Lu April 19, 2022, 10:13 a.m. UTC | #5
On 2022/4/19 15:20, Robin Murphy wrote:
> On 2022-04-19 00:37, Lu Baolu wrote:
>> On 2022/4/19 6:09, Robin Murphy wrote:
>>> On 2022-04-16 01:04, Lu Baolu wrote:
>>>> On 2022/4/14 20:42, Robin Murphy wrote:
>>>>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct bus_type 
>>>>> *bus)
>>>>>    */
>>>>>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
>>>>>   {
>>>>> -    int err;
>>>>> -
>>>>> -    if (ops == NULL) {
>>>>> -        bus->iommu_ops = NULL;
>>>>> -        return 0;
>>>>> -    }
>>>>> -
>>>>> -    if (bus->iommu_ops != NULL)
>>>>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>>>>           return -EBUSY;
>>>>>       bus->iommu_ops = ops;
>>>>
>>>> Do we still need to keep above lines in bus_set_iommu()?
>>>
>>> It preserves the existing behaviour until each callsite and its 
>>> associated error handling are removed later on, which seems like as 
>>> good a thing to do as any. Since I'm already relaxing 
>>> iommu_device_register() to a warn-but-continue behaviour while it 
>>> keeps the bus ops on life-support internally, I figured not changing 
>>> too much at once would make it easier to bisect any potential issues 
>>> arising from this first step.
>>
>> Fair enough. Thank you for the explanation.
>>
>> Do you have a public tree that I could pull these patches and try them
>> on an Intel hardware? Or perhaps you have done this? I like the whole
>> idea of this series, but it's better to try it with a real hardware.
> 
> I haven't bothered with separate branches since there's so many 
> different pieces in-flight, but my complete (unstable) development 
> branch can be found here:
> 
> https://gitlab.arm.com/linux-arm/linux-rm/-/commits/iommu/bus
> 
> For now I'd recommend winding the head back to "iommu: Clean up 
> bus_set_iommu()" for testing - some of the patches above that have 
> already been posted and picked up by their respective subsystems, but 
> others are incomplete and barely compile-tested. I'll probably rearrange 
> it later this week to better reflect what's happened so far.

Okay, thanks for sharing.

Best regards,
baolu
Krishna Reddy April 22, 2022, 6:37 p.m. UTC | #6
Good effort to isolate bus config from smmu drivers.
Reviewed-By: Krishna Reddy <vdumpa@nvidia.com>

I have an orthogonal question here.
Can the following code handle the case, where different buses have different type of SMMU instances(like one bus has SMMUv2 and another bus has SMMUv3)?
If it need to handle the above case, can the smmu device bus be matched with specific bus here and ops set only for that bus? 


> +       for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
> +               struct bus_type *bus = iommu_buses[i];
> +               const struct iommu_ops *bus_ops = bus->iommu_ops;
> +               int err;
> +
> +               WARN_ON(bus_ops && bus_ops != ops);
> +               bus->iommu_ops = ops;
> +               err = bus_iommu_probe(bus);
> +               if (err) {
> +                       bus_for_each_dev(bus, NULL, iommu,
> remove_iommu_group);
> +                       bus->iommu_ops = bus_ops;
> +                       return err;
> +               }
> +       }


-KR
Robin Murphy April 22, 2022, 7:02 p.m. UTC | #7
On 2022-04-22 19:37, Krishna Reddy wrote:
> Good effort to isolate bus config from smmu drivers.
> Reviewed-By: Krishna Reddy <vdumpa@nvidia.com>

Thanks!

> I have an orthogonal question here.
> Can the following code handle the case, where different buses have different type of SMMU instances(like one bus has SMMUv2 and another bus has SMMUv3)?
> If it need to handle the above case, can the smmu device bus be matched with specific bus here and ops set only for that bus?

Not yet, but that is one of the end goals that this is all working 
towards. I think the stuff that I've added to the dev branch[1] today 
should have reached the point where that becomes viable, but I'll need 
to rig up a system to test it next week.

Intermediate solutions aren't worth it because in practice you 
inevitably end up needing both IOMMU drivers to share the platform "bus" 
anyway.

Cheers,
Robin.

[1] https://gitlab.arm.com/linux-arm/linux-rm/-/commits/iommu/bus

> 
> 
>> +       for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
>> +               struct bus_type *bus = iommu_buses[i];
>> +               const struct iommu_ops *bus_ops = bus->iommu_ops;
>> +               int err;
>> +
>> +               WARN_ON(bus_ops && bus_ops != ops);
>> +               bus->iommu_ops = ops;
>> +               err = bus_iommu_probe(bus);
>> +               if (err) {
>> +                       bus_for_each_dev(bus, NULL, iommu,
>> remove_iommu_group);
>> +                       bus->iommu_ops = bus_ops;
>> +                       return err;
>> +               }
>> +       }
> 
> 
> -KR
Baolu Lu April 23, 2022, 8:01 a.m. UTC | #8
Hi Robin,

On 2022/4/19 15:20, Robin Murphy wrote:
> On 2022-04-19 00:37, Lu Baolu wrote:
>> On 2022/4/19 6:09, Robin Murphy wrote:
>>> On 2022-04-16 01:04, Lu Baolu wrote:
>>>> On 2022/4/14 20:42, Robin Murphy wrote:
>>>>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct bus_type 
>>>>> *bus)
>>>>>    */
>>>>>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
>>>>>   {
>>>>> -    int err;
>>>>> -
>>>>> -    if (ops == NULL) {
>>>>> -        bus->iommu_ops = NULL;
>>>>> -        return 0;
>>>>> -    }
>>>>> -
>>>>> -    if (bus->iommu_ops != NULL)
>>>>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>>>>           return -EBUSY;
>>>>>       bus->iommu_ops = ops;
>>>>
>>>> Do we still need to keep above lines in bus_set_iommu()?
>>>
>>> It preserves the existing behaviour until each callsite and its 
>>> associated error handling are removed later on, which seems like as 
>>> good a thing to do as any. Since I'm already relaxing 
>>> iommu_device_register() to a warn-but-continue behaviour while it 
>>> keeps the bus ops on life-support internally, I figured not changing 
>>> too much at once would make it easier to bisect any potential issues 
>>> arising from this first step.
>>
>> Fair enough. Thank you for the explanation.
>>
>> Do you have a public tree that I could pull these patches and try them
>> on an Intel hardware? Or perhaps you have done this? I like the whole
>> idea of this series, but it's better to try it with a real hardware.
> 
> I haven't bothered with separate branches since there's so many 
> different pieces in-flight, but my complete (unstable) development 
> branch can be found here:
> 
> https://gitlab.arm.com/linux-arm/linux-rm/-/commits/iommu/bus
> 
> For now I'd recommend winding the head back to "iommu: Clean up 
> bus_set_iommu()" for testing - some of the patches above that have 
> already been posted and picked up by their respective subsystems, but 
> others are incomplete and barely compile-tested. I'll probably rearrange 
> it later this week to better reflect what's happened so far.

I wound the head back to "iommu: Clean up bus_set_iommu" and tested it
on an Intel machine. It got stuck during boot. This test was on a remote
machine and I have no means to access it physically. So I can't get any
kernel debugging messages. (I have to work from home these days. :-()

I guess it's due to the fact that intel_iommu_probe_device() callback
only works for the pci devices. The issue occurs when probing a device
other than a PCI one.

Best regards,
baolu
Robin Murphy April 23, 2022, 8:37 a.m. UTC | #9
On 2022-04-23 09:01, Lu Baolu wrote:
> Hi Robin,
> 
> On 2022/4/19 15:20, Robin Murphy wrote:
>> On 2022-04-19 00:37, Lu Baolu wrote:
>>> On 2022/4/19 6:09, Robin Murphy wrote:
>>>> On 2022-04-16 01:04, Lu Baolu wrote:
>>>>> On 2022/4/14 20:42, Robin Murphy wrote:
>>>>>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct bus_type 
>>>>>> *bus)
>>>>>>    */
>>>>>>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops 
>>>>>> *ops)
>>>>>>   {
>>>>>> -    int err;
>>>>>> -
>>>>>> -    if (ops == NULL) {
>>>>>> -        bus->iommu_ops = NULL;
>>>>>> -        return 0;
>>>>>> -    }
>>>>>> -
>>>>>> -    if (bus->iommu_ops != NULL)
>>>>>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>>>>>           return -EBUSY;
>>>>>>       bus->iommu_ops = ops;
>>>>>
>>>>> Do we still need to keep above lines in bus_set_iommu()?
>>>>
>>>> It preserves the existing behaviour until each callsite and its 
>>>> associated error handling are removed later on, which seems like as 
>>>> good a thing to do as any. Since I'm already relaxing 
>>>> iommu_device_register() to a warn-but-continue behaviour while it 
>>>> keeps the bus ops on life-support internally, I figured not changing 
>>>> too much at once would make it easier to bisect any potential issues 
>>>> arising from this first step.
>>>
>>> Fair enough. Thank you for the explanation.
>>>
>>> Do you have a public tree that I could pull these patches and try them
>>> on an Intel hardware? Or perhaps you have done this? I like the whole
>>> idea of this series, but it's better to try it with a real hardware.
>>
>> I haven't bothered with separate branches since there's so many 
>> different pieces in-flight, but my complete (unstable) development 
>> branch can be found here:
>>
>> https://gitlab.arm.com/linux-arm/linux-rm/-/commits/iommu/bus
>>
>> For now I'd recommend winding the head back to "iommu: Clean up 
>> bus_set_iommu()" for testing - some of the patches above that have 
>> already been posted and picked up by their respective subsystems, but 
>> others are incomplete and barely compile-tested. I'll probably 
>> rearrange it later this week to better reflect what's happened so far.
> 
> I wound the head back to "iommu: Clean up bus_set_iommu" and tested it
> on an Intel machine. It got stuck during boot. This test was on a remote
> machine and I have no means to access it physically. So I can't get any
> kernel debugging messages. (I have to work from home these days. :-()
> 
> I guess it's due to the fact that intel_iommu_probe_device() callback
> only works for the pci devices. The issue occurs when probing a device
> other than a PCI one.

Yeah, I was wondering if that would be significant, since it's the only 
driver that never registered itself for platform_bus_type so won't have 
actually seen those calls before. I'm inclined to bodge that as below 
for now, as long as it then works OK in terms of the rest of the changes.

Thanks,
Robin.

----->8-----
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 9fa1b98186a3..6e359f92ec00 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4565,6 +4565,10 @@ static struct iommu_device 
*intel_iommu_probe_device(struct device *dev)
  	unsigned long flags;
  	u8 bus, devfn;

+	/* ANDD platform device support needs fixing */
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
  	iommu = device_to_iommu(dev, &bus, &devfn);
  	if (!iommu)
  		return ERR_PTR(-ENODEV);
Baolu Lu April 23, 2022, 8:51 a.m. UTC | #10
On 2022/4/23 16:37, Robin Murphy wrote:
> On 2022-04-23 09:01, Lu Baolu wrote:
>> Hi Robin,
>>
>> On 2022/4/19 15:20, Robin Murphy wrote:
>>> On 2022-04-19 00:37, Lu Baolu wrote:
>>>> On 2022/4/19 6:09, Robin Murphy wrote:
>>>>> On 2022-04-16 01:04, Lu Baolu wrote:
>>>>>> On 2022/4/14 20:42, Robin Murphy wrote:
>>>>>>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct bus_type 
>>>>>>> *bus)
>>>>>>>    */
>>>>>>>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops 
>>>>>>> *ops)
>>>>>>>   {
>>>>>>> -    int err;
>>>>>>> -
>>>>>>> -    if (ops == NULL) {
>>>>>>> -        bus->iommu_ops = NULL;
>>>>>>> -        return 0;
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    if (bus->iommu_ops != NULL)
>>>>>>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>>>>>>           return -EBUSY;
>>>>>>>       bus->iommu_ops = ops;
>>>>>>
>>>>>> Do we still need to keep above lines in bus_set_iommu()?
>>>>>
>>>>> It preserves the existing behaviour until each callsite and its 
>>>>> associated error handling are removed later on, which seems like as 
>>>>> good a thing to do as any. Since I'm already relaxing 
>>>>> iommu_device_register() to a warn-but-continue behaviour while it 
>>>>> keeps the bus ops on life-support internally, I figured not 
>>>>> changing too much at once would make it easier to bisect any 
>>>>> potential issues arising from this first step.
>>>>
>>>> Fair enough. Thank you for the explanation.
>>>>
>>>> Do you have a public tree that I could pull these patches and try them
>>>> on an Intel hardware? Or perhaps you have done this? I like the whole
>>>> idea of this series, but it's better to try it with a real hardware.
>>>
>>> I haven't bothered with separate branches since there's so many 
>>> different pieces in-flight, but my complete (unstable) development 
>>> branch can be found here:
>>>
>>> https://gitlab.arm.com/linux-arm/linux-rm/-/commits/iommu/bus
>>>
>>> For now I'd recommend winding the head back to "iommu: Clean up 
>>> bus_set_iommu()" for testing - some of the patches above that have 
>>> already been posted and picked up by their respective subsystems, but 
>>> others are incomplete and barely compile-tested. I'll probably 
>>> rearrange it later this week to better reflect what's happened so far.
>>
>> I wound the head back to "iommu: Clean up bus_set_iommu" and tested it
>> on an Intel machine. It got stuck during boot. This test was on a remote
>> machine and I have no means to access it physically. So I can't get any
>> kernel debugging messages. (I have to work from home these days. :-()
>>
>> I guess it's due to the fact that intel_iommu_probe_device() callback
>> only works for the pci devices. The issue occurs when probing a device
>> other than a PCI one.
> 
> Yeah, I was wondering if that would be significant, since it's the only 
> driver that never registered itself for platform_bus_type so won't have 
> actually seen those calls before. I'm inclined to bodge that as below 
> for now, as long as it then works OK in terms of the rest of the changes.
> 
> Thanks,
> Robin.
> 
> ----->8-----
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index 9fa1b98186a3..6e359f92ec00 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4565,6 +4565,10 @@ static struct iommu_device 
> *intel_iommu_probe_device(struct device *dev)
>       unsigned long flags;
>       u8 bus, devfn;
> 
> +    /* ANDD platform device support needs fixing */
> +    if (!pdev)
> +        return ERR_PTR(-ENODEV);
> +
>       iommu = device_to_iommu(dev, &bus, &devfn);
>       if (!iommu)
>           return ERR_PTR(-ENODEV);

I haven't seen any real ANDD platform devices, hence this works for me.

Best regards,
baolu
Baolu Lu April 23, 2022, 9 a.m. UTC | #11
On 2022/4/23 16:51, Lu Baolu wrote:
> On 2022/4/23 16:37, Robin Murphy wrote:
>> On 2022-04-23 09:01, Lu Baolu wrote:
>>> Hi Robin,
>>>
>>> On 2022/4/19 15:20, Robin Murphy wrote:
>>>> On 2022-04-19 00:37, Lu Baolu wrote:
>>>>> On 2022/4/19 6:09, Robin Murphy wrote:
>>>>>> On 2022-04-16 01:04, Lu Baolu wrote:
>>>>>>> On 2022/4/14 20:42, Robin Murphy wrote:
>>>>>>>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct 
>>>>>>>> bus_type *bus)
>>>>>>>>    */
>>>>>>>>   int bus_set_iommu(struct bus_type *bus, const struct iommu_ops 
>>>>>>>> *ops)
>>>>>>>>   {
>>>>>>>> -    int err;
>>>>>>>> -
>>>>>>>> -    if (ops == NULL) {
>>>>>>>> -        bus->iommu_ops = NULL;
>>>>>>>> -        return 0;
>>>>>>>> -    }
>>>>>>>> -
>>>>>>>> -    if (bus->iommu_ops != NULL)
>>>>>>>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>>>>>>>           return -EBUSY;
>>>>>>>>       bus->iommu_ops = ops;
>>>>>>>
>>>>>>> Do we still need to keep above lines in bus_set_iommu()?
>>>>>>
>>>>>> It preserves the existing behaviour until each callsite and its 
>>>>>> associated error handling are removed later on, which seems like 
>>>>>> as good a thing to do as any. Since I'm already relaxing 
>>>>>> iommu_device_register() to a warn-but-continue behaviour while it 
>>>>>> keeps the bus ops on life-support internally, I figured not 
>>>>>> changing too much at once would make it easier to bisect any 
>>>>>> potential issues arising from this first step.
>>>>>
>>>>> Fair enough. Thank you for the explanation.
>>>>>
>>>>> Do you have a public tree that I could pull these patches and try them
>>>>> on an Intel hardware? Or perhaps you have done this? I like the whole
>>>>> idea of this series, but it's better to try it with a real hardware.
>>>>
>>>> I haven't bothered with separate branches since there's so many 
>>>> different pieces in-flight, but my complete (unstable) development 
>>>> branch can be found here:
>>>>
>>>> https://gitlab.arm.com/linux-arm/linux-rm/-/commits/iommu/bus
>>>>
>>>> For now I'd recommend winding the head back to "iommu: Clean up 
>>>> bus_set_iommu()" for testing - some of the patches above that have 
>>>> already been posted and picked up by their respective subsystems, 
>>>> but others are incomplete and barely compile-tested. I'll probably 
>>>> rearrange it later this week to better reflect what's happened so far.
>>>
>>> I wound the head back to "iommu: Clean up bus_set_iommu" and tested it
>>> on an Intel machine. It got stuck during boot. This test was on a remote
>>> machine and I have no means to access it physically. So I can't get any
>>> kernel debugging messages. (I have to work from home these days. :-()
>>>
>>> I guess it's due to the fact that intel_iommu_probe_device() callback
>>> only works for the pci devices. The issue occurs when probing a device
>>> other than a PCI one.
>>
>> Yeah, I was wondering if that would be significant, since it's the 
>> only driver that never registered itself for platform_bus_type so 
>> won't have actually seen those calls before. I'm inclined to bodge 
>> that as below for now, as long as it then works OK in terms of the 
>> rest of the changes.
>>
>> Thanks,
>> Robin.
>>
>> ----->8-----
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index 9fa1b98186a3..6e359f92ec00 100644
>> --- a/drivers/iommu/intel/iommu.c
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -4565,6 +4565,10 @@ static struct iommu_device 
>> *intel_iommu_probe_device(struct device *dev)
>>       unsigned long flags;
>>       u8 bus, devfn;
>>
>> +    /* ANDD platform device support needs fixing */
>> +    if (!pdev)
>> +        return ERR_PTR(-ENODEV);
>> +
>>       iommu = device_to_iommu(dev, &bus, &devfn);
>>       if (!iommu)
>>           return ERR_PTR(-ENODEV);
> 
> I haven't seen any real ANDD platform devices, hence this works for me.

Or more precisely, return NULL when @dev goes through device_to_iommu()?

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index df5c62ecf942..0d447739e076 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -797,8 +797,11 @@ struct intel_iommu *device_to_iommu(struct device 
*dev, u8 *bus, u8 *devfn)
                 pf_pdev = pci_physfn(pdev);
                 dev = &pf_pdev->dev;
                 segment = pci_domain_nr(pdev->bus);
-       } else if (has_acpi_companion(dev))
+       } else if (has_acpi_companion(dev)) {
                 dev = &ACPI_COMPANION(dev)->dev;
+       } else {
+               return NULL;
+       }

         rcu_read_lock();
         for_each_iommu(iommu, drhd) {

Best regards,
baolu
Baolu Lu April 23, 2022, 9:41 a.m. UTC | #12
On 2022/4/23 17:00, Lu Baolu wrote:
> On 2022/4/23 16:51, Lu Baolu wrote:
>> On 2022/4/23 16:37, Robin Murphy wrote:
>>> On 2022-04-23 09:01, Lu Baolu wrote:
>>>> Hi Robin,
>>>>
>>>> On 2022/4/19 15:20, Robin Murphy wrote:
>>>>> On 2022-04-19 00:37, Lu Baolu wrote:
>>>>>> On 2022/4/19 6:09, Robin Murphy wrote:
>>>>>>> On 2022-04-16 01:04, Lu Baolu wrote:
>>>>>>>> On 2022/4/14 20:42, Robin Murphy wrote:
>>>>>>>>> @@ -1883,27 +1900,12 @@ static int iommu_bus_init(struct 
>>>>>>>>> bus_type *bus)
>>>>>>>>>    */
>>>>>>>>>   int bus_set_iommu(struct bus_type *bus, const struct 
>>>>>>>>> iommu_ops *ops)
>>>>>>>>>   {
>>>>>>>>> -    int err;
>>>>>>>>> -
>>>>>>>>> -    if (ops == NULL) {
>>>>>>>>> -        bus->iommu_ops = NULL;
>>>>>>>>> -        return 0;
>>>>>>>>> -    }
>>>>>>>>> -
>>>>>>>>> -    if (bus->iommu_ops != NULL)
>>>>>>>>> +    if (bus->iommu_ops && ops && bus->iommu_ops != ops)
>>>>>>>>>           return -EBUSY;
>>>>>>>>>       bus->iommu_ops = ops;
>>>>>>>>
>>>>>>>> Do we still need to keep above lines in bus_set_iommu()?
>>>>>>>
>>>>>>> It preserves the existing behaviour until each callsite and its 
>>>>>>> associated error handling are removed later on, which seems like 
>>>>>>> as good a thing to do as any. Since I'm already relaxing 
>>>>>>> iommu_device_register() to a warn-but-continue behaviour while it 
>>>>>>> keeps the bus ops on life-support internally, I figured not 
>>>>>>> changing too much at once would make it easier to bisect any 
>>>>>>> potential issues arising from this first step.
>>>>>>
>>>>>> Fair enough. Thank you for the explanation.
>>>>>>
>>>>>> Do you have a public tree that I could pull these patches and try 
>>>>>> them
>>>>>> on an Intel hardware? Or perhaps you have done this? I like the whole
>>>>>> idea of this series, but it's better to try it with a real hardware.
>>>>>
>>>>> I haven't bothered with separate branches since there's so many 
>>>>> different pieces in-flight, but my complete (unstable) development 
>>>>> branch can be found here:
>>>>>
>>>>> https://gitlab.arm.com/linux-arm/linux-rm/-/commits/iommu/bus
>>>>>
>>>>> For now I'd recommend winding the head back to "iommu: Clean up 
>>>>> bus_set_iommu()" for testing - some of the patches above that have 
>>>>> already been posted and picked up by their respective subsystems, 
>>>>> but others are incomplete and barely compile-tested. I'll probably 
>>>>> rearrange it later this week to better reflect what's happened so far.
>>>>
>>>> I wound the head back to "iommu: Clean up bus_set_iommu" and tested it
>>>> on an Intel machine. It got stuck during boot. This test was on a 
>>>> remote
>>>> machine and I have no means to access it physically. So I can't get any
>>>> kernel debugging messages. (I have to work from home these days. :-()
>>>>
>>>> I guess it's due to the fact that intel_iommu_probe_device() callback
>>>> only works for the pci devices. The issue occurs when probing a device
>>>> other than a PCI one.
>>>
>>> Yeah, I was wondering if that would be significant, since it's the 
>>> only driver that never registered itself for platform_bus_type so 
>>> won't have actually seen those calls before. I'm inclined to bodge 
>>> that as below for now, as long as it then works OK in terms of the 
>>> rest of the changes.
>>>
>>> Thanks,
>>> Robin.
>>>
>>> ----->8-----
>>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>>> index 9fa1b98186a3..6e359f92ec00 100644
>>> --- a/drivers/iommu/intel/iommu.c
>>> +++ b/drivers/iommu/intel/iommu.c
>>> @@ -4565,6 +4565,10 @@ static struct iommu_device 
>>> *intel_iommu_probe_device(struct device *dev)
>>>       unsigned long flags;
>>>       u8 bus, devfn;
>>>
>>> +    /* ANDD platform device support needs fixing */
>>> +    if (!pdev)
>>> +        return ERR_PTR(-ENODEV);
>>> +
>>>       iommu = device_to_iommu(dev, &bus, &devfn);
>>>       if (!iommu)
>>>           return ERR_PTR(-ENODEV);
>>
>> I haven't seen any real ANDD platform devices, hence this works for me.
> 
> Or more precisely, return NULL when @dev goes through device_to_iommu()?
> 
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index df5c62ecf942..0d447739e076 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -797,8 +797,11 @@ struct intel_iommu *device_to_iommu(struct device 
> *dev, u8 *bus, u8 *devfn)
>                  pf_pdev = pci_physfn(pdev);
>                  dev = &pf_pdev->dev;
>                  segment = pci_domain_nr(pdev->bus);
> -       } else if (has_acpi_companion(dev))
> +       } else if (has_acpi_companion(dev)) {
>                  dev = &ACPI_COMPANION(dev)->dev;
> +       } else {
> +               return NULL;
> +       }
> 
>          rcu_read_lock();
>          for_each_iommu(iommu, drhd) {

Robin, please ignore this. "has_acpi_companion(dev)" isn't equal to an
ANDD device. Please use yours. Sorry for the noise.

Best regards,
baolu
diff mbox series

Patch

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 13e1a8bd5435..51205c33c426 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -175,6 +175,14 @@  static int __init iommu_subsys_init(void)
 }
 subsys_initcall(iommu_subsys_init);
 
+static int remove_iommu_group(struct device *dev, void *data)
+{
+	if (dev->iommu && dev->iommu->iommu_dev == data)
+		iommu_release_device(dev);
+
+	return 0;
+}
+
 /**
  * iommu_device_register() - Register an IOMMU hardware instance
  * @iommu: IOMMU handle for the instance
@@ -197,6 +205,22 @@  int iommu_device_register(struct iommu_device *iommu,
 	spin_lock(&iommu_device_lock);
 	list_add_tail(&iommu->list, &iommu_device_list);
 	spin_unlock(&iommu_device_lock);
+
+	for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
+		struct bus_type *bus = iommu_buses[i];
+		const struct iommu_ops *bus_ops = bus->iommu_ops;
+		int err;
+
+		WARN_ON(bus_ops && bus_ops != ops);
+		bus->iommu_ops = ops;
+		err = bus_iommu_probe(bus);
+		if (err) {
+			bus_for_each_dev(bus, NULL, iommu, remove_iommu_group);
+			bus->iommu_ops = bus_ops;
+			return err;
+		}
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(iommu_device_register);
@@ -1654,13 +1678,6 @@  static int probe_iommu_group(struct device *dev, void *data)
 	return ret;
 }
 
-static int remove_iommu_group(struct device *dev, void *data)
-{
-	iommu_release_device(dev);
-
-	return 0;
-}
-
 static int iommu_bus_notifier(struct notifier_block *nb,
 			      unsigned long action, void *data)
 {
@@ -1883,27 +1900,12 @@  static int iommu_bus_init(struct bus_type *bus)
  */
 int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
 {
-	int err;
-
-	if (ops == NULL) {
-		bus->iommu_ops = NULL;
-		return 0;
-	}
-
-	if (bus->iommu_ops != NULL)
+	if (bus->iommu_ops && ops && bus->iommu_ops != ops)
 		return -EBUSY;
 
 	bus->iommu_ops = ops;
 
-	/* Do IOMMU specific setup for this bus-type */
-	err = bus_iommu_probe(bus);
-	if (err) {
-		/* Clean up */
-		bus_for_each_dev(bus, NULL, NULL, remove_iommu_group);
-		bus->iommu_ops = NULL;
-	}
-
-	return err;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(bus_set_iommu);