[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v3 1/4] iommu/amd: support all delivery modes with x2APIC



On 15.10.2019 17:47, Roger Pau Monne wrote:
> Current AMD IOMMU code will attempt to create remapping entries for
> all IO-APIC pins, regardless of the delivery mode. AMD IOMMU
> implementation doesn't support remapping entries for IO-APIC pins with
> delivery mode set to SMI, MNI, INIT or ExtINT, instead those entries

Nit: "NMI"

> are not translated provided the right bits are set in the device table
> entry.
> 
> This change checks whether the device table entry has the correct bits
> set in order to delivery the requested interrupt or a warning message
> is printed. It also translates the 32bit destination field into a
> physical or logical IO-APIC entry format. Note that if the 32bit
> destination cannot fit into the legacy format a message is printed and
> the entry is masked.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>

For this to have an effect on firmware initialized RTEs, it also
requires patch 4 aiui. In fact I think it should be _only_ this
case where we allow delivery modes other than fixed and lowest
priority ("arbitrated" in AMD terminology). Hence I think this
patch wants to go last in the series, and the code be changed to
reject runtime requests to fiddle with non-"normal" delivery
modes (this may go further and actually disallow changing such
RTEs at runtime alongside disallowing their production).

> --- a/xen/drivers/passthrough/amd/iommu_intr.c
> +++ b/xen/drivers/passthrough/amd/iommu_intr.c
> @@ -439,6 +439,80 @@ int __init amd_iommu_setup_ioapic_remapping(void)
>      return 0;
>  }
>  
> +void setup_forced_ioapic_rte(unsigned int apic, unsigned int pin,
> +                             struct amd_iommu *iommu,
> +                             struct IO_APIC_route_entry *rte)
> +{
> +    unsigned int idx = ioapic_id_to_index(IO_APIC_ID(apic));
> +    struct amd_iommu_dte *table = iommu->dev_table.buffer;
> +    unsigned int req_id, dest, offset;
> +    union irte_ptr entry;
> +
> +    ASSERT(x2apic_enabled);
> +
> +    if ( idx == MAX_IO_APICS )

Better >= ?

> +    {
> +        rte->mask = true;
> +        return;
> +    }
> +
> +    req_id = get_intremap_requestor_id(ioapic_sbdf[idx].seg,
> +                                       ioapic_sbdf[idx].bdf);
> +
> +    switch ( rte->delivery_mode )
> +    {
> +    case dest_SMI:
> +        break;

Don't you want to check the sys_mgt field here, along the lines of the
other ones below?

> +#define DEL_CHECK(type, dte_field)                                      \
> +    case dest_ ## type:                                                 \
> +        if ( !table[req_id].dte_field )                                 \
> +            printk(XENLOG_WARNING                                       \
> +                   STR(type) " on IO-APIC %u pin %u will be aborted\n", \
> +                   apic, pin);                                          \
> +        break;

Please omit the final ; here, such that ...

> +    DEL_CHECK(NMI, nmi_pass);
> +    DEL_CHECK(INIT, init_pass);
> +    DEL_CHECK(ExtINT, ext_int_pass);

... the ones here become an actual requirement.

> +#undef DEL_CHECK
> +
> +    default:
> +        ASSERT_UNREACHABLE();
> +        return;
> +    }
> +
> +    offset = ioapic_sbdf[idx].pin_2_idx[pin];
> +    if ( offset >= INTREMAP_MAX_ENTRIES )
> +    {
> +        rte->mask = true;
> +        return;
> +    }
> +
> +    entry = get_intremap_entry(iommu, req_id, offset);
> +    dest = get_full_dest(entry.ptr128);
> +
> +#define SET_DEST(name, dest_mask) {                                          
>   \
> +    if ( dest & ~(dest_mask) )                                               
>   \
> +    {                                                                        
>   \
> +        printk(XENLOG_WARNING                                                
>   \
> +               "IO-APIC %u pin %u " STR(name) " destination (%x) > %x\n",    
>   \
> +               apic, pin, dest, dest_mask);                                  
>   \
> +        rte->mask = true;                                                    
>   \
> +        return;                                                              
>   \
> +    }                                                                        
>   \
> +    rte->dest.name.name ## _dest = dest;                                     
>   \
> +}
> +
> +    if ( rte->dest_mode )
> +        SET_DEST(physical, 0xf)
> +    else
> +        SET_DEST(logical, 0xff)

This reads as if the code was broken. Please add () around the outermost
{} of the macro, allowing you to put ; here. Or otherwise, just like
above for DEL_CHECK(), omit the {} as well as the final semicolon.

Furthermore - are you sure about this distinction? See e.g.
update_intremap_entry_from_ioapic() and
amd_iommu_setup_ioapic_remapping(), which unilaterally use
rte->dest.logical.logical_dest. Likewise io_apic.c's SET_DEST() users,
which generally pass "logical" for as middle argument. I thought one of
my half way recent patches (IRQ handling or AMD IOMMU work) had a remark
in it regarding such a badly documented extension, but I can't seem to
be able to find it anymore.

> @@ -482,6 +556,13 @@ void amd_iommu_ioapic_update_ire(
>          *((u32 *)&new_rte) = value;
>          /* read upper 32 bits from io-apic rte */
>          *(((u32 *)&new_rte) + 1) = __io_apic_read(apic, reg + 1);
> +
> +        if ( new_rte.delivery_mode > 1 && x2apic_enabled )

The literal 1 here wants attaching of a comment. And why the
x2apic_enabled part of the condition?

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.