diff mbox series

AMD/IOMMU: correct handling when XT's prereq features are unavailable

Message ID 640545a6-689a-6ba9-4978-a83183df2e1b@suse.com (mailing list archive)
State New, archived
Headers show
Series AMD/IOMMU: correct handling when XT's prereq features are unavailable | expand

Commit Message

Jan Beulich Feb. 27, 2020, 2:34 p.m. UTC
We should neither cause IOMMU initialization as a whole to fail in this
case (we should still be able to bring up the system in non-x2APIC or
x2APIC physical mode), nor should the remainder of the function be
skipped (as the main part of it won't get entered a 2nd time) in such an
event. It is merely necessary for the function to indicate to the caller
(iov_supports_xt()) that setup failed as far as x2APIC is concerned.

Signed-off-by: Jan Beulich <jbeulich@suse.com>

Comments

Roger Pau Monné Feb. 27, 2020, 3:07 p.m. UTC | #1
On Thu, Feb 27, 2020 at 03:34:48PM +0100, Jan Beulich wrote:
> We should neither cause IOMMU initialization as a whole to fail in this
> case (we should still be able to bring up the system in non-x2APIC or
> x2APIC physical mode), nor should the remainder of the function be
> skipped (as the main part of it won't get entered a 2nd time) in such an
> event. It is merely necessary for the function to indicate to the caller
> (iov_supports_xt()) that setup failed as far as x2APIC is concerned.
> 
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> 
> --- a/xen/drivers/passthrough/amd/iommu_init.c
> +++ b/xen/drivers/passthrough/amd/iommu_init.c
> @@ -1364,6 +1364,7 @@ static int __init amd_iommu_prepare_one(
>  int __init amd_iommu_prepare(bool xt)
>  {
>      struct amd_iommu *iommu;
> +    bool no_xt = false;
>      int rc = -ENODEV;
>  
>      BUG_ON( !iommu_found() );
> @@ -1400,9 +1401,8 @@ int __init amd_iommu_prepare(bool xt)
>          if ( rc )
>              goto error_out;
>  
> -        rc = -ENODEV;
> -        if ( xt && (!iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup) )
> -            goto error_out;
> +        if ( !iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup )
> +            no_xt = true;

Don't you need to also adjust the usage of xt in the
for_each_amd_iommu loop below, so that the control registers fields
get initialized properly?

Thanks, Roger.
Andrew Cooper Feb. 27, 2020, 3:25 p.m. UTC | #2
On 27/02/2020 14:34, Jan Beulich wrote:
> --- a/xen/drivers/passthrough/amd/iommu_init.c
> +++ b/xen/drivers/passthrough/amd/iommu_init.c
> @@ -1364,6 +1364,7 @@ static int __init amd_iommu_prepare_one(
>  int __init amd_iommu_prepare(bool xt)
>  {
>      struct amd_iommu *iommu;
> +    bool no_xt = false;

I think the logic would be easier to follow if this was has_xt, with
inverted meaning.  However...

>      int rc = -ENODEV;
>  
>      BUG_ON( !iommu_found() );
> @@ -1400,9 +1401,8 @@ int __init amd_iommu_prepare(bool xt)
>          if ( rc )
>              goto error_out;
>  
> -        rc = -ENODEV;
> -        if ( xt && (!iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup) )
> -            goto error_out;
> +        if ( !iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup )
> +            no_xt = true;
>      }
>  
>      for_each_amd_iommu ( iommu )

... the contents of this loop depends on the early exit path you've just
deleted.

In the case of x2apic not being available, we'll still set {ga,xt}_en to
the caller requested value.

~Andrew
Jan Beulich Feb. 28, 2020, 8:14 a.m. UTC | #3
On 27.02.2020 16:25, Andrew Cooper wrote:
> On 27/02/2020 14:34, Jan Beulich wrote:
>> --- a/xen/drivers/passthrough/amd/iommu_init.c
>> +++ b/xen/drivers/passthrough/amd/iommu_init.c
>> @@ -1364,6 +1364,7 @@ static int __init amd_iommu_prepare_one(
>>  int __init amd_iommu_prepare(bool xt)
>>  {
>>      struct amd_iommu *iommu;
>> +    bool no_xt = false;
> 
> I think the logic would be easier to follow if this was has_xt, with
> inverted meaning.

I'm not fully convinced it'll make it easier, but I've switched
things around.

>  However...
> 
>>      int rc = -ENODEV;
>>  
>>      BUG_ON( !iommu_found() );
>> @@ -1400,9 +1401,8 @@ int __init amd_iommu_prepare(bool xt)
>>          if ( rc )
>>              goto error_out;
>>  
>> -        rc = -ENODEV;
>> -        if ( xt && (!iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup) )
>> -            goto error_out;
>> +        if ( !iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup )
>> +            no_xt = true;
>>      }
>>  
>>      for_each_amd_iommu ( iommu )
> 
> ... the contents of this loop depends on the early exit path you've just
> deleted.
> 
> In the case of x2apic not being available, we'll still set {ga,xt}_en to
> the caller requested value.

Oh, indeed (and Roger, thank you too for noticing this). In fact
it explains a hang later during boot that I did observe, and that
I meant to look into later. That said, interrupts for Dom0 still
don't seem to work quite right in this (partly broken) mode even
with this fixed (there are several "No irq handler for vector"
messages, and at the very least the disk doesn't work); I'll see
to find time to look into that as well, but I'm pretty convinced
it's an independent issue. (Seeing that interrupt remapping gets
enabled this way, and x2APIC is pre-enabled, I'm suspecting this
is another case where we need to force physical mode.)

Let me blame this on the cold I'm fighting, which isn't quite bad
enough to stay home, but which also isn't helpful. v2 coming ...

Jan
Jan Beulich Feb. 28, 2020, 8:31 a.m. UTC | #4
On 28.02.2020 09:14, Jan Beulich wrote:
> On 27.02.2020 16:25, Andrew Cooper wrote:
>> On 27/02/2020 14:34, Jan Beulich wrote:
>>> @@ -1400,9 +1401,8 @@ int __init amd_iommu_prepare(bool xt)
>>>          if ( rc )
>>>              goto error_out;
>>>  
>>> -        rc = -ENODEV;
>>> -        if ( xt && (!iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup) )
>>> -            goto error_out;
>>> +        if ( !iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup )
>>> +            no_xt = true;
>>>      }
>>>  
>>>      for_each_amd_iommu ( iommu )
>>
>> ... the contents of this loop depends on the early exit path you've just
>> deleted.
>>
>> In the case of x2apic not being available, we'll still set {ga,xt}_en to
>> the caller requested value.
> 
> Oh, indeed (and Roger, thank you too for noticing this). In fact
> it explains a hang later during boot that I did observe, and that
> I meant to look into later. That said, interrupts for Dom0 still
> don't seem to work quite right in this (partly broken) mode even
> with this fixed (there are several "No irq handler for vector"
> messages, and at the very least the disk doesn't work); I'll see
> to find time to look into that as well, but I'm pretty convinced
> it's an independent issue. (Seeing that interrupt remapping gets
> enabled this way, and x2APIC is pre-enabled, I'm suspecting this
> is another case where we need to force physical mode.)

And indeed x2apic_phys on the command line makes things work. Now
I'll have to figure a reasonable way when and how to communicate
the need to switch the mode. (Another potential issue I'm seeing is
that it may not be okay to bring up a CPU with APIC ID 0xff in
this case, and it pretty certainly would require further precautions
if we were to allow bringing up CPUs with even larger APIC IDs.)

Jan
diff mbox series

Patch

--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -1364,6 +1364,7 @@  static int __init amd_iommu_prepare_one(
 int __init amd_iommu_prepare(bool xt)
 {
     struct amd_iommu *iommu;
+    bool no_xt = false;
     int rc = -ENODEV;
 
     BUG_ON( !iommu_found() );
@@ -1400,9 +1401,8 @@  int __init amd_iommu_prepare(bool xt)
         if ( rc )
             goto error_out;
 
-        rc = -ENODEV;
-        if ( xt && (!iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup) )
-            goto error_out;
+        if ( !iommu->features.flds.ga_sup || !iommu->features.flds.xt_sup )
+            no_xt = true;
     }
 
     for_each_amd_iommu ( iommu )
@@ -1422,7 +1422,7 @@  int __init amd_iommu_prepare(bool xt)
         ivhd_type = 0;
     }
 
-    return rc;
+    return rc ?: xt && no_xt ? -ENODEV : 0;
 }
 
 int __init amd_iommu_init(bool xt)