diff mbox series

[1/9] AMD/IOMMU: use bit field for extended feature register

Message ID 5D024E170200007800237DFD@prv1-mh.provo.novell.com (mailing list archive)
State Superseded
Headers show
Series x86: AMD x2APIC support | expand

Commit Message

Jan Beulich June 13, 2019, 1:22 p.m. UTC
This also takes care of several of the shift values wrongly having been
specified as hex rather than dec.

Take the opportunity and add further fields.

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

Comments

Woods, Brian June 17, 2019, 7:07 p.m. UTC | #1
On Thu, Jun 13, 2019 at 07:22:31AM -0600, Jan Beulich wrote:
> This also takes care of several of the shift values wrongly having been
> specified as hex rather than dec.
> 
> Take the opportunity and add further fields.
> 
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> 
> --- a/xen/drivers/passthrough/amd/iommu_detect.c
> +++ b/xen/drivers/passthrough/amd/iommu_detect.c
> @@ -60,43 +60,72 @@ static int __init get_iommu_capabilities
>  
>  void __init get_iommu_features(struct amd_iommu *iommu)
>  {
> -    u32 low, high;
> -    int i = 0 ;
> -    static const char *__initdata feature_str[] = {
> -        "- Prefetch Pages Command", 
> -        "- Peripheral Page Service Request", 
> -        "- X2APIC Supported", 
> -        "- NX bit Supported", 
> -        "- Guest Translation", 
> -        "- Reserved bit [5]",
> -        "- Invalidate All Command", 
> -        "- Guest APIC supported", 
> -        "- Hardware Error Registers", 
> -        "- Performance Counters", 
> -        NULL
> -    };
> -
>      ASSERT( iommu->mmio_base );
>  
>      if ( !iommu_has_cap(iommu, PCI_CAP_EFRSUP_SHIFT) )
>      {
> -        iommu->features = 0;
> +        iommu->features.raw = 0;
>          return;
>      }
>  
> -    low = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
> -    high = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET + 4);
> -
> -    iommu->features = ((u64)high << 32) | low;
> +    iommu->features.raw =
> +        readq(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
>  
>      printk("AMD-Vi: IOMMU Extended Features:\n");
>  
> -    while ( feature_str[i] )
> +#define MASK(fld) ((union amd_iommu_ext_features){ .flds.fld = ~0 }).raw
> +#define FEAT(fld, str) do { \
> +    if ( MASK(fld) & (MASK(fld) - 1) ) \
> +        printk( "- " str ": %#x\n", iommu->features.flds.fld); \
> +    else if ( iommu->features.raw & MASK(fld) ) \
> +        printk( "- " str "\n"); \
> +} while ( false )
> +
> +    FEAT(pref_sup,           "Prefetch Pages Command");
> +    FEAT(ppr_sup,            "Peripheral Page Service Request");
> +    FEAT(xt_sup,             "x2APIC");
> +    FEAT(nx_sup,             "NX bit");
> +    FEAT(gappi_sup,          "Guest APIC Physical Processor Interrupt");
> +    FEAT(ia_sup,             "Invalidate All Command");
> +    FEAT(ga_sup,             "Guest APIC");
> +    FEAT(he_sup,             "Hardware Error Registers");
> +    FEAT(pc_sup,             "Performance Counters");
> +    FEAT(hats,               "Host Address Translation Size");
> +
> +    if ( iommu->features.flds.gt_sup )
>      {
> -        if ( amd_iommu_has_feature(iommu, i) )
> -            printk( " %s\n", feature_str[i]);
> -        i++;
> +        FEAT(gats,           "Guest Address Translation Size");
> +        FEAT(glx_sup,        "Guest CR3 Root Table Level");
> +        FEAT(pas_max,        "Maximum PASID");
>      }
> +
> +    FEAT(smif_sup,           "SMI Filter Register");
> +    FEAT(smif_rc,            "SMI Filter Register Count");
> +    FEAT(gam_sup,            "Guest Virtual APIC Modes");
> +    FEAT(dual_ppr_log_sup,   "Dual PPR Log");
> +    FEAT(dual_event_log_sup, "Dual Event Log");
> +    FEAT(sat_sup,            "Secure ATS");
> +    FEAT(us_sup,             "User / Supervisor Page Protection");
> +    FEAT(dev_tbl_seg_sup,    "Device Table Segmentation");
> +    FEAT(ppr_early_of_sup,   "PPR Log Overflow Early Warning");
> +    FEAT(ppr_auto_rsp_sup,   "PPR Automatic Response");
> +    FEAT(marc_sup,           "Memory Access Routing and Control");
> +    FEAT(blk_stop_mrk_sup,   "Block StopMark Message");
> +    FEAT(perf_opt_sup ,      "Performance Optimization");
> +    FEAT(msi_cap_mmio_sup,   "MSI Capability MMIO Access");
> +    FEAT(gio_sup,            "Guest I/O Protection");
> +    FEAT(ha_sup,             "Host Access");
> +    FEAT(eph_sup,            "Enhanced PPR Handling");
> +    FEAT(attr_fw_sup,        "Attribute Forward");
> +    FEAT(hd_sup,             "Host Dirty");
> +    FEAT(inv_iotlb_type_sup, "Invalidate IOTLB Type");
> +    FEAT(viommu_sup,         "Virtualized IOMMU");
> +    FEAT(vm_guard_io_sup,    "VMGuard I/O Support");
> +    FEAT(vm_table_size,      "VM Table Size");
> +    FEAT(ga_update_dis_sup,  "Guest Access Bit Update Disable");
> +
> +#undef FEAT
> +#undef MASK
>  }
>  
>  int __init amd_iommu_detect_one_acpi(
> --- a/xen/drivers/passthrough/amd/iommu_guest.c
> +++ b/xen/drivers/passthrough/amd/iommu_guest.c
> @@ -638,7 +638,7 @@ static uint64_t iommu_mmio_read64(struct
>          val = reg_to_u64(iommu->reg_status);
>          break;
>      case IOMMU_EXT_FEATURE_MMIO_OFFSET:
> -        val = reg_to_u64(iommu->reg_ext_feature);
> +        val = iommu->reg_ext_feature.raw;
>          break;
>  
>      default:
> @@ -802,39 +802,26 @@ int guest_iommu_set_base(struct domain *
>  /* Initialize mmio read only bits */
>  static void guest_iommu_reg_init(struct guest_iommu *iommu)
>  {
> -    uint32_t lower, upper;
> +    union amd_iommu_ext_features ef = {
> +        /* Support prefetch */
> +        .flds.pref_sup = 1,
> +        /* Support PPR log */
> +        .flds.ppr_sup = 1,
> +        /* Support guest translation */
> +        .flds.gt_sup = 1,
> +        /* Support invalidate all command */
> +        .flds.ia_sup = 1,
> +        /* Host translation size has 6 levels */
> +        .flds.hats = HOST_ADDRESS_SIZE_6_LEVEL,
> +        /* Guest translation size has 6 levels */
> +        .flds.gats = GUEST_ADDRESS_SIZE_6_LEVEL,
> +        /* Single level gCR3 */
> +        .flds.glx_sup = GUEST_CR3_1_LEVEL,
> +        /* 9 bit PASID */
> +        .flds.pas_max = PASMAX_9_bit,
> +    };
>  
> -    lower = upper = 0;
> -    /* Support prefetch */
> -    iommu_set_bit(&lower,IOMMU_EXT_FEATURE_PREFSUP_SHIFT);
> -    /* Support PPR log */
> -    iommu_set_bit(&lower,IOMMU_EXT_FEATURE_PPRSUP_SHIFT);
> -    /* Support guest translation */
> -    iommu_set_bit(&lower,IOMMU_EXT_FEATURE_GTSUP_SHIFT);
> -    /* Support invalidate all command */
> -    iommu_set_bit(&lower,IOMMU_EXT_FEATURE_IASUP_SHIFT);
> -
> -    /* Host translation size has 6 levels */
> -    set_field_in_reg_u32(HOST_ADDRESS_SIZE_6_LEVEL, lower,
> -                         IOMMU_EXT_FEATURE_HATS_MASK,
> -                         IOMMU_EXT_FEATURE_HATS_SHIFT,
> -                         &lower);
> -    /* Guest translation size has 6 levels */
> -    set_field_in_reg_u32(GUEST_ADDRESS_SIZE_6_LEVEL, lower,
> -                         IOMMU_EXT_FEATURE_GATS_MASK,
> -                         IOMMU_EXT_FEATURE_GATS_SHIFT,
> -                         &lower);
> -    /* Single level gCR3 */
> -    set_field_in_reg_u32(GUEST_CR3_1_LEVEL, lower,
> -                         IOMMU_EXT_FEATURE_GLXSUP_MASK,
> -                         IOMMU_EXT_FEATURE_GLXSUP_SHIFT, &lower);
> -    /* 9 bit PASID */
> -    set_field_in_reg_u32(PASMAX_9_bit, upper,
> -                         IOMMU_EXT_FEATURE_PASMAX_MASK,
> -                         IOMMU_EXT_FEATURE_PASMAX_SHIFT, &upper);
> -
> -    iommu->reg_ext_feature.lo = lower;
> -    iommu->reg_ext_feature.hi = upper;
> +    iommu->reg_ext_feature = ef;
>  }
>  
>  static int guest_iommu_mmio_range(struct vcpu *v, unsigned long addr)
> --- a/xen/drivers/passthrough/amd/iommu_init.c
> +++ b/xen/drivers/passthrough/amd/iommu_init.c
> @@ -883,7 +883,7 @@ static void enable_iommu(struct amd_iomm
>      register_iommu_event_log_in_mmio_space(iommu);
>      register_iommu_exclusion_range(iommu);
>  
> -    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
> +    if ( iommu->features.flds.ppr_sup )
>          register_iommu_ppr_log_in_mmio_space(iommu);
>  
>      desc = irq_to_desc(iommu->msi.irq);
> @@ -897,15 +897,15 @@ static void enable_iommu(struct amd_iomm
>      set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_ENABLED);
>      set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
>  
> -    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
> +    if ( iommu->features.flds.ppr_sup )
>          set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_ENABLED);
>  
> -    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_GTSUP_SHIFT) )
> +    if ( iommu->features.flds.gt_sup )
>          set_iommu_guest_translation_control(iommu, IOMMU_CONTROL_ENABLED);
>  
>      set_iommu_translation_control(iommu, IOMMU_CONTROL_ENABLED);
>  
> -    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_IASUP_SHIFT) )
> +    if ( iommu->features.flds.ia_sup )
>          amd_iommu_flush_all_caches(iommu);
>  
>      iommu->enabled = 1;
> @@ -928,10 +928,10 @@ static void disable_iommu(struct amd_iom
>      set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_DISABLED);
>      set_iommu_event_log_control(iommu, IOMMU_CONTROL_DISABLED);
>  
> -    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
> +    if ( iommu->features.flds.ppr_sup )
>          set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_DISABLED);
>  
> -    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_GTSUP_SHIFT) )
> +    if ( iommu->features.flds.gt_sup )
>          set_iommu_guest_translation_control(iommu, IOMMU_CONTROL_DISABLED);
>  
>      set_iommu_translation_control(iommu, IOMMU_CONTROL_DISABLED);
> @@ -1027,7 +1027,7 @@ static int __init amd_iommu_init_one(str
>  
>      get_iommu_features(iommu);
>  
> -    if ( iommu->features )
> +    if ( iommu->features.raw )
>          iommuv2_enabled = 1;
>  
>      if ( allocate_cmd_buffer(iommu) == NULL )
> @@ -1036,9 +1036,8 @@ static int __init amd_iommu_init_one(str
>      if ( allocate_event_log(iommu) == NULL )
>          goto error_out;
>  
> -    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
> -        if ( allocate_ppr_log(iommu) == NULL )
> -            goto error_out;
> +    if ( iommu->features.flds.ppr_sup && !allocate_ppr_log(iommu) )
> +        goto error_out;
>  
>      if ( !set_iommu_interrupt_handler(iommu) )
>          goto error_out;
> @@ -1389,7 +1388,7 @@ void amd_iommu_resume(void)
>      }
>  
>      /* flush all cache entries after iommu re-enabled */
> -    if ( !amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_IASUP_SHIFT) )
> +    if ( !iommu->features.flds.ia_sup )
>      {
>          invalidate_all_devices();
>          invalidate_all_domain_pages();
> --- a/xen/include/asm-x86/amd-iommu.h
> +++ b/xen/include/asm-x86/amd-iommu.h
> @@ -83,7 +83,7 @@ struct amd_iommu {
>      iommu_cap_t cap;
>  
>      u8 ht_flags;
> -    u64 features;
> +    union amd_iommu_ext_features features;
>  
>      void *mmio_base;
>      unsigned long mmio_base_phys;
> @@ -174,7 +174,7 @@ struct guest_iommu {
>      /* MMIO regs */
>      struct mmio_reg         reg_ctrl;              /* MMIO offset 0018h */
>      struct mmio_reg         reg_status;            /* MMIO offset 2020h */
> -    struct mmio_reg         reg_ext_feature;       /* MMIO offset 0030h */
> +    union amd_iommu_ext_features reg_ext_feature;  /* MMIO offset 0030h */
>  
>      /* guest interrupt settings */
>      struct guest_iommu_msi  msi;
> --- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
> +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
> @@ -346,26 +346,57 @@ struct amd_iommu_dte {
>  #define IOMMU_EXCLUSION_LIMIT_HIGH_MASK		0xFFFFFFFF
>  #define IOMMU_EXCLUSION_LIMIT_HIGH_SHIFT	0
>  
> -/* Extended Feature Register*/
> +/* Extended Feature Register */
>  #define IOMMU_EXT_FEATURE_MMIO_OFFSET                   0x30
> -#define IOMMU_EXT_FEATURE_PREFSUP_SHIFT                 0x0
> -#define IOMMU_EXT_FEATURE_PPRSUP_SHIFT                  0x1
> -#define IOMMU_EXT_FEATURE_XTSUP_SHIFT                   0x2
> -#define IOMMU_EXT_FEATURE_NXSUP_SHIFT                   0x3
> -#define IOMMU_EXT_FEATURE_GTSUP_SHIFT                   0x4
> -#define IOMMU_EXT_FEATURE_IASUP_SHIFT                   0x6
> -#define IOMMU_EXT_FEATURE_GASUP_SHIFT                   0x7
> -#define IOMMU_EXT_FEATURE_HESUP_SHIFT                   0x8
> -#define IOMMU_EXT_FEATURE_PCSUP_SHIFT                   0x9
> -#define IOMMU_EXT_FEATURE_HATS_SHIFT                    0x10
> -#define IOMMU_EXT_FEATURE_HATS_MASK                     0x00000C00
> -#define IOMMU_EXT_FEATURE_GATS_SHIFT                    0x12
> -#define IOMMU_EXT_FEATURE_GATS_MASK                     0x00003000
> -#define IOMMU_EXT_FEATURE_GLXSUP_SHIFT                  0x14
> -#define IOMMU_EXT_FEATURE_GLXSUP_MASK                   0x0000C000
>  
> -#define IOMMU_EXT_FEATURE_PASMAX_SHIFT                  0x0
> -#define IOMMU_EXT_FEATURE_PASMAX_MASK                   0x0000001F
> +union amd_iommu_ext_features {
> +    uint64_t raw;
> +    struct {
> +        unsigned int pref_sup:1;
> +        unsigned int ppr_sup:1;
> +        unsigned int xt_sup:1;
> +        unsigned int nx_sup:1;
> +        unsigned int gt_sup:1;
> +        unsigned int gappi_sup:1;
> +        unsigned int ia_sup:1;
> +        unsigned int ga_sup:1;
> +        unsigned int he_sup:1;
> +        unsigned int pc_sup:1;
> +        unsigned int hats:2;
> +        unsigned int gats:2;
> +        unsigned int glx_sup:2;
> +        unsigned int smif_sup:2;
> +        unsigned int smif_rc:3;
> +        unsigned int gam_sup:3;
> +        unsigned int dual_ppr_log_sup:2;
> +        unsigned int :2;
> +        unsigned int dual_event_log_sup:2;

> +        unsigned int sat_sup:1;
> +        unsigned int :1;
I think these might be flipped.

> +        unsigned int pas_max:5;
> +        unsigned int us_sup:1;
> +        unsigned int dev_tbl_seg_sup:2;
> +        unsigned int ppr_early_of_sup:1;
> +        unsigned int ppr_auto_rsp_sup:1;
> +        unsigned int marc_sup:2;
> +        unsigned int blk_stop_mrk_sup:1;
> +        unsigned int perf_opt_sup:1;
> +        unsigned int msi_cap_mmio_sup:1;
> +        unsigned int :1;
> +        unsigned int gio_sup:1;
> +        unsigned int ha_sup:1;
> +        unsigned int eph_sup:1;
> +        unsigned int attr_fw_sup:1;
> +        unsigned int hd_sup:1;
> +        unsigned int :1;
> +        unsigned int inv_iotlb_type_sup:1;
> +        unsigned int viommu_sup:1;
> +        unsigned int vm_guard_io_sup:1;
> +        unsigned int vm_table_size:4;
> +        unsigned int ga_update_dis_sup:1;
> +        unsigned int :2;
> +    } flds;
> +};
>  
>  /* Status Register*/
>  #define IOMMU_STATUS_MMIO_OFFSET		0x2020
> --- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
> +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
> @@ -219,13 +219,6 @@ static inline int iommu_has_cap(struct a
>      return !!(iommu->cap.header & (1u << bit));
>  }
>  
> -static inline int amd_iommu_has_feature(struct amd_iommu *iommu, uint32_t bit)
> -{
> -    if ( !iommu_has_cap(iommu, PCI_CAP_EFRSUP_SHIFT) )
> -        return 0;
> -    return !!(iommu->features & (1U << bit));
> -}
> -
>  /* access tail or head pointer of ring buffer */
>  static inline uint32_t iommu_get_rb_pointer(uint32_t reg)
>  {
> 
> 
>
Andrew Cooper June 17, 2019, 8:23 p.m. UTC | #2
On 13/06/2019 14:22, Jan Beulich wrote:
> This also takes care of several of the shift values wrongly having been
> specified as hex rather than dec.
>
> Take the opportunity and add further fields.
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
>
> --- a/xen/drivers/passthrough/amd/iommu_detect.c
> +++ b/xen/drivers/passthrough/amd/iommu_detect.c
> @@ -60,43 +60,72 @@ static int __init get_iommu_capabilities
>  
>  void __init get_iommu_features(struct amd_iommu *iommu)
>  {
> -    u32 low, high;
> -    int i = 0 ;
> -    static const char *__initdata feature_str[] = {
> -        "- Prefetch Pages Command", 
> -        "- Peripheral Page Service Request", 
> -        "- X2APIC Supported", 
> -        "- NX bit Supported", 
> -        "- Guest Translation", 
> -        "- Reserved bit [5]",
> -        "- Invalidate All Command", 
> -        "- Guest APIC supported", 
> -        "- Hardware Error Registers", 
> -        "- Performance Counters", 
> -        NULL
> -    };
> -
>      ASSERT( iommu->mmio_base );
>  
>      if ( !iommu_has_cap(iommu, PCI_CAP_EFRSUP_SHIFT) )
>      {
> -        iommu->features = 0;
> +        iommu->features.raw = 0;
>          return;
>      }
>  
> -    low = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
> -    high = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET + 4);
> -
> -    iommu->features = ((u64)high << 32) | low;
> +    iommu->features.raw =
> +        readq(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
>  
>      printk("AMD-Vi: IOMMU Extended Features:\n");
>  
> -    while ( feature_str[i] )
> +#define MASK(fld) ((union amd_iommu_ext_features){ .flds.fld = ~0 }).raw
> +#define FEAT(fld, str) do { \
> +    if ( MASK(fld) & (MASK(fld) - 1) ) \
> +        printk( "- " str ": %#x\n", iommu->features.flds.fld); \
> +    else if ( iommu->features.raw & MASK(fld) ) \
> +        printk( "- " str "\n"); \
> +} while ( false )
> +
> +    FEAT(pref_sup,           "Prefetch Pages Command");
> +    FEAT(ppr_sup,            "Peripheral Page Service Request");
> +    FEAT(xt_sup,             "x2APIC");
> +    FEAT(nx_sup,             "NX bit");
> +    FEAT(gappi_sup,          "Guest APIC Physical Processor Interrupt");
> +    FEAT(ia_sup,             "Invalidate All Command");
> +    FEAT(ga_sup,             "Guest APIC");
> +    FEAT(he_sup,             "Hardware Error Registers");
> +    FEAT(pc_sup,             "Performance Counters");
> +    FEAT(hats,               "Host Address Translation Size");
> +
> +    if ( iommu->features.flds.gt_sup )
>      {
> -        if ( amd_iommu_has_feature(iommu, i) )
> -            printk( " %s\n", feature_str[i]);
> -        i++;
> +        FEAT(gats,           "Guest Address Translation Size");
> +        FEAT(glx_sup,        "Guest CR3 Root Table Level");
> +        FEAT(pas_max,        "Maximum PASID");
>      }
> +
> +    FEAT(smif_sup,           "SMI Filter Register");
> +    FEAT(smif_rc,            "SMI Filter Register Count");
> +    FEAT(gam_sup,            "Guest Virtual APIC Modes");
> +    FEAT(dual_ppr_log_sup,   "Dual PPR Log");
> +    FEAT(dual_event_log_sup, "Dual Event Log");
> +    FEAT(sat_sup,            "Secure ATS");
> +    FEAT(us_sup,             "User / Supervisor Page Protection");
> +    FEAT(dev_tbl_seg_sup,    "Device Table Segmentation");
> +    FEAT(ppr_early_of_sup,   "PPR Log Overflow Early Warning");
> +    FEAT(ppr_auto_rsp_sup,   "PPR Automatic Response");
> +    FEAT(marc_sup,           "Memory Access Routing and Control");
> +    FEAT(blk_stop_mrk_sup,   "Block StopMark Message");
> +    FEAT(perf_opt_sup ,      "Performance Optimization");
> +    FEAT(msi_cap_mmio_sup,   "MSI Capability MMIO Access");
> +    FEAT(gio_sup,            "Guest I/O Protection");
> +    FEAT(ha_sup,             "Host Access");
> +    FEAT(eph_sup,            "Enhanced PPR Handling");
> +    FEAT(attr_fw_sup,        "Attribute Forward");
> +    FEAT(hd_sup,             "Host Dirty");
> +    FEAT(inv_iotlb_type_sup, "Invalidate IOTLB Type");
> +    FEAT(viommu_sup,         "Virtualized IOMMU");
> +    FEAT(vm_guard_io_sup,    "VMGuard I/O Support");
> +    FEAT(vm_table_size,      "VM Table Size");
> +    FEAT(ga_update_dis_sup,  "Guest Access Bit Update Disable");
> +
> +#undef FEAT
> +#undef MASK
>  }

So this is fine, but does come with a downside.  This is the log from a
Rome system:

(XEN) [   17.928225] AMD-Vi: IOMMU Extended Features:
(XEN) [   17.988264] - Peripheral Page Service Request
(XEN) [   18.048082] - x2APIC
(XEN) [   18.104735] - NX bit
(XEN) [   18.160751] - Invalidate All Command
(XEN) [   18.218116] - Guest APIC
(XEN) [   18.273660] - Performance Counters
(XEN) [   18.329868] - Host Address Translation Size: 0x2
(XEN) [   18.387363] - Guest Address Translation Size: 0
(XEN) [   18.444446] - Guest CR3 Root Table Level: 0x1
(XEN) [   18.501006] - Maximum PASID: 0xf
(XEN) [   18.555753] - SMI Filter Register: 0x1
(XEN) [   18.610773] - SMI Filter Register Count: 0x2
(XEN) [   18.666116] - Guest Virtual APIC Modes: 0x1
(XEN) [   18.721036] - Dual PPR Log: 0x2
(XEN) [   18.774237] - Dual Event Log: 0x2
(XEN) [   18.827164] - User / Supervisor Page Protection
(XEN) [   18.881374] - Device Table Segmentation: 0x3
(XEN) [   18.934949] - PPR Log Overflow Early Warning
(XEN) [   18.988186] - PPR Automatic Response
(XEN) [   19.040193] - Memory Access Routing and Control: 0x1
(XEN) [   19.093770] - Block StopMark Message
(XEN) [   19.145300] - Performance Optimization
(XEN) [   19.196603] - MSI Capability MMIO Access
(XEN) [   19.247754] - Guest I/O Protection
(XEN) [   19.297811] - Host Access
(XEN) [   19.346396] - Enhanced PPR Handling
(XEN) [   19.395647] - Attribute Forward
(XEN) [   19.443986] - Virtualized IOMMU
(XEN) [   19.491828] - VMGuard I/O Support
(XEN) [   19.539404] - VM Table Size: 0x2
(XEN) [   19.589837] AMD-Vi: IOMMU Extended Features:
(XEN) [   19.637829] - Peripheral Page Service Request
(XEN) [   19.685607] - x2APIC
(XEN) [   19.730231] - NX bit
(XEN) [   19.774195] - Invalidate All Command
(XEN) [   19.819528] - Guest APIC
(XEN) [   19.863027] - Performance Counters
(XEN) [   19.907165] - Host Address Translation Size: 0x2
(XEN) [   19.952578] - Guest Address Translation Size: 0
(XEN) [   19.997588] - Guest CR3 Root Table Level: 0x1
(XEN) [   20.042057] - Maximum PASID: 0xf
(XEN) [   20.084732] - SMI Filter Register: 0x1
(XEN) [   20.127648] - SMI Filter Register Count: 0x2
(XEN) [   20.170910] - Guest Virtual APIC Modes: 0x1
(XEN) [   20.213702] - Dual PPR Log: 0x2
(XEN) [   20.254765] - Dual Event Log: 0x2
(XEN) [   20.295567] - User / Supervisor Page Protection
(XEN) [   20.337626] - Device Table Segmentation: 0x3
(XEN) [   20.379042] - PPR Log Overflow Early Warning
(XEN) [   20.420094] - PPR Automatic Response
(XEN) [   20.459890] - Memory Access Routing and Control: 0x1
(XEN) [   20.501248] - Block StopMark Message
(XEN) [   20.540577] - Performance Optimization
(XEN) [   20.579876] - MSI Capability MMIO Access
(XEN) [   20.619309] - Guest I/O Protection
(XEN) [   20.658041] - Host Access
(XEN) [   20.695937] - Enhanced PPR Handling
(XEN) [   20.735276] - Attribute Forward
(XEN) [   20.773830] - Virtualized IOMMU
(XEN) [   20.812335] - VMGuard I/O Support
(XEN) [   20.850868] - VM Table Size: 0x2
(XEN) [   20.892543] AMD-Vi: IOMMU Extended Features:
(XEN) [   20.932087] - Peripheral Page Service Request
(XEN) [   20.971756] - x2APIC
(XEN) [   21.008681] - NX bit
(XEN) [   21.045279] - Invalidate All Command
(XEN) [   21.083567] - Guest APIC
(XEN) [   21.120410] - Performance Counters
(XEN) [   21.158386] - Host Address Translation Size: 0x2
(XEN) [   21.197956] - Guest Address Translation Size: 0
(XEN) [   21.237433] - Guest CR3 Root Table Level: 0x1
(XEN) [   21.276709] - Maximum PASID: 0xf
(XEN) [   21.314538] - SMI Filter Register: 0x1
(XEN) [   21.352844] - SMI Filter Register Count: 0x2
(XEN) [   21.391728] - Guest Virtual APIC Modes: 0x1
(XEN) [   21.430614] - Dual PPR Log: 0x2
(XEN) [   21.468150] - Dual Event Log: 0x2
(XEN) [   21.505833] - User / Supervisor Page Protection
(XEN) [   21.545270] - Device Table Segmentation: 0x3
(XEN) [   21.584538] - PPR Log Overflow Early Warning
(XEN) [   21.623928] - PPR Automatic Response
(XEN) [   21.662564] - Memory Access Routing and Control: 0x1
(XEN) [   21.703268] - Block StopMark Message
(XEN) [   21.742415] - Performance Optimization
(XEN) [   21.781692] - MSI Capability MMIO Access
(XEN) [   21.821159] - Guest I/O Protection
(XEN) [   21.859916] - Host Access
(XEN) [   21.897811] - Enhanced PPR Handling
(XEN) [   21.936818] - Attribute Forward
(XEN) [   21.975387] - Virtualized IOMMU
(XEN) [   22.013898] - VMGuard I/O Support
(XEN) [   22.052448] - VM Table Size: 0x2
(XEN) [   22.094140] AMD-Vi: IOMMU Extended Features:
(XEN) [   22.133685] - Peripheral Page Service Request
(XEN) [   22.173363] - x2APIC
(XEN) [   22.210287] - NX bit
(XEN) [   22.246888] - Invalidate All Command
(XEN) [   22.285176] - Guest APIC
(XEN) [   22.322008] - Performance Counters
(XEN) [   22.359994] - Host Address Translation Size: 0x2
(XEN) [   22.399552] - Guest Address Translation Size: 0
(XEN) [   22.439028] - Guest CR3 Root Table Level: 0x1
(XEN) [   22.478307] - Maximum PASID: 0xf
(XEN) [   22.516133] - SMI Filter Register: 0x1
(XEN) [   22.554441] - SMI Filter Register Count: 0x2
(XEN) [   22.593345] - Guest Virtual APIC Modes: 0x1
(XEN) [   22.632221] - Dual PPR Log: 0x2
(XEN) [   22.669766] - Dual Event Log: 0x2
(XEN) [   22.707455] - User / Supervisor Page Protection
(XEN) [   22.746896] - Device Table Segmentation: 0x3
(XEN) [   22.786161] - PPR Log Overflow Early Warning
(XEN) [   22.825552] - PPR Automatic Response
(XEN) [   22.864211] - Memory Access Routing and Control: 0x1
(XEN) [   22.904917] - Block StopMark Message
(XEN) [   22.944075] - Performance Optimization
(XEN) [   22.983360] - MSI Capability MMIO Access
(XEN) [   23.022815] - Guest I/O Protection
(XEN) [   23.061548] - Host Access
(XEN) [   23.099437] - Enhanced PPR Handling
(XEN) [   23.138461] - Attribute Forward
(XEN) [   23.177008] - Virtualized IOMMU
(XEN) [   23.215523] - VMGuard I/O Support
(XEN) [   23.254043] - VM Table Size: 0x2
(XEN) [   23.295705] AMD-Vi: IOMMU Extended Features:
(XEN) [   23.335250] - Peripheral Page Service Request
(XEN) [   23.374941] - x2APIC
(XEN) [   23.411860] - NX bit
(XEN) [   23.448460] - Invalidate All Command
(XEN) [   23.486748] - Guest APIC
(XEN) [   23.523569] - Performance Counters
(XEN) [   23.561564] - Host Address Translation Size: 0x2
(XEN) [   23.601127] - Guest Address Translation Size: 0
(XEN) [   23.640584] - Guest CR3 Root Table Level: 0x1
(XEN) [   23.679885] - Maximum PASID: 0xf
(XEN) [   23.717689] - SMI Filter Register: 0x1
(XEN) [   23.755994] - SMI Filter Register Count: 0x2
(XEN) [   23.794897] - Guest Virtual APIC Modes: 0x1
(XEN) [   23.833766] - Dual PPR Log: 0x2
(XEN) [   23.871319] - Dual Event Log: 0x2
(XEN) [   23.909008] - User / Supervisor Page Protection
(XEN) [   23.948434] - Device Table Segmentation: 0x3
(XEN) [   23.987698] - PPR Log Overflow Early Warning
(XEN) [   24.027099] - PPR Automatic Response
(XEN) [   24.065748] - Memory Access Routing and Control: 0x1
(XEN) [   24.106438] - Block StopMark Message
(XEN) [   24.145591] - Performance Optimization
(XEN) [   24.184893] - MSI Capability MMIO Access
(XEN) [   24.224345] - Guest I/O Protection
(XEN) [   24.263076] - Host Access
(XEN) [   24.300974] - Enhanced PPR Handling
(XEN) [   24.339982] - Attribute Forward
(XEN) [   24.378528] - Virtualized IOMMU
(XEN) [   24.417041] - VMGuard I/O Support
(XEN) [   24.455584] - VM Table Size: 0x2
(XEN) [   24.497260] AMD-Vi: IOMMU Extended Features:
(XEN) [   24.536794] - Peripheral Page Service Request
(XEN) [   24.576469] - x2APIC
(XEN) [   24.613395] - NX bit
(XEN) [   24.649996] - Invalidate All Command
(XEN) [   24.688294] - Guest APIC
(XEN) [   24.725142] - Performance Counters
(XEN) [   24.763127] - Host Address Translation Size: 0x2
(XEN) [   24.802707] - Guest Address Translation Size: 0
(XEN) [   24.842172] - Guest CR3 Root Table Level: 0x1
(XEN) [   24.881459] - Maximum PASID: 0xf
(XEN) [   24.919288] - SMI Filter Register: 0x1
(XEN) [   24.957583] - SMI Filter Register Count: 0x2
(XEN) [   24.996496] - Guest Virtual APIC Modes: 0x1
(XEN) [   25.035364] - Dual PPR Log: 0x2
(XEN) [   25.072908] - Dual Event Log: 0x2
(XEN) [   25.110588] - User / Supervisor Page Protection
(XEN) [   25.150037] - Device Table Segmentation: 0x3
(XEN) [   25.189290] - PPR Log Overflow Early Warning
(XEN) [   25.228696] - PPR Automatic Response
(XEN) [   25.267348] - Memory Access Routing a in Xennd Control: 0x1
(XEN) [   25.308045] - Block StopMark Message
(XEN) [   25.347199] - Performance Optimization
(XEN) [   25.386484] - MSI Capability MMIO Access
(XEN) [   25.425950] - Guest I/O Protection
(XEN) [   25.464680] - Host Access
(XEN) [   25.502580] - Enhanced PPR Handling
(XEN) [   25.541588] - Attribute Forward
(XEN) [   25.580145] - Virtualized IOMMU
(XEN) [   25.618647] - VMGuard I/O Support
(XEN) [   25.657196] - VM Table Size: 0x2
(XEN) [   25.698883] AMD-Vi: IOMMU Extended Features:
(XEN) [   25.738420] - Peripheral Page Service Request
(XEN) [   25.778084] - x2APIC
(XEN) [   25.815010] - NX bit
(XEN) [   25.851603] - Invalidate All Command
(XEN) [   25.889907] - Guest APIC
(XEN) [   25.926756] - Performance Counters
(XEN) [   25.964742] - Host Address Translation Size: 0x2
(XEN) [   26.004312] - Guest Address Translation Size: 0
(XEN) [   26.043787] - Guest CR3 Root Table Level: 0x1
(XEN) [   26.083064] - Maximum PASID: 0xf
(XEN) [   26.120903] - SMI Filter Register: 0x1
(XEN) [   26.159215] - SMI Filter Register Count: 0x2
(XEN) [   26.198129] - Guest Virtual APIC Modes: 0x1
(XEN) [   26.237015] - Dual PPR Log: 0x2
(XEN) [   26.274565] - Dual Event Log: 0x2
(XEN) [   26.312231] - User / Supervisor Page Protection
(XEN) [   26.351672] - Device Table Segmentation: 0x3
(XEN) [   26.390949] - PPR Log Overflow Early Warning
(XEN) [   26.430343] - PPR Automatic Response
(XEN) [   26.469006] - Memory Access Routing and Control: 0x1
(XEN) [   26.509711] - Block StopMark Message
(XEN) [   26.548867] - Performance Optimization
(XEN) [   26.588159] - MSI Capability MMIO Access
(XEN) [   26.627627] - Guest I/O Protection
(XEN) [   26.666355] - Host Access
(XEN) [   26.704253] - Enhanced PPR Handling
(XEN) [   26.743271] - Attribute Forward
(XEN) [   26.781828] - Virtualized IOMMU
(XEN) [   26.820341] - VMGuard I/O Support
(XEN) [   26.858874] - VM Table Size: 0x2
(XEN) [   26.900549] AMD-Vi: IOMMU Extended Features:
(XEN) [   26.940095] - Peripheral Page Service Request
(XEN) [   26.979769] - x2APIC
(XEN) [   27.016686] - NX bit
(XEN) [   27.053287] - Invalidate All Command
(XEN) [   27.091582] - Guest APIC
(XEN) [   27.128432] - Performance Counters
(XEN) [   27.166418] - Host Address Translation Size: 0x2
(XEN) [   27.205971] - Guest Address Translation Size: 0
(XEN) [   27.245440] - Guest CR3 Root Table Level: 0x1
(XEN) [   27.284714] - Maximum PASID: 0xf
(XEN) [   27.322543] - SMI Filter Register: 0x1
(XEN) [   27.360847] - SMI Filter Register Count: 0x2
(XEN) [   27.399768] - Guest Virtual APIC Modes: 0x1
(XEN) [   27.438656] - Dual PPR Log: 0x2
(XEN) [   27.476209] - Dual Event Log: 0x2
(XEN) [   27.513889] - User / Supervisor Page Protection
(XEN) [   27.553331] - Device Table Segmentation: 0x3
(XEN) [   27.592595] - PPR Log Overflow Early Warning
(XEN) [   27.632003] - PPR Automatic Response
(XEN) [   27.670655] - Memory Access Routing and Control: 0x1
(XEN) [   27.711351] - Block StopMark Message
(XEN) [   27.750525] - Performance Optimization
(XEN) [   27.789811] - MSI Capability MMIO Access
(XEN) [   27.829267] - Guest I/O Protection
(XEN) [   27.868005] - Host Access
(XEN) [   27.905889] - Enhanced PPR Handling
(XEN) [   27.944896] - Attribute Forward
(XEN) [   27.983445] - Virtualized IOMMU
(XEN) [   28.021956] - VMGuard I/O Support
(XEN) [   28.060494] - VM Table Size: 0x2
(XEN) [   28.284879] AMD-Vi: Disabled HAP memory map sharing with IOMMU
(XEN) [   28.326856] AMD-Vi: IOMMU 0 Enabled.
(XEN) [   28.366011] AMD-Vi: IOMMU 1 Enabled.
(XEN) [   28.405142] AMD-Vi: IOMMU 2 Enabled.
(XEN) [   28.444150] AMD-Vi: IOMMU 3 Enabled.
(XEN) [   28.483062] AMD-Vi: IOMMU 4 Enabled.
(XEN) [   28.521923] AMD-Vi: IOMMU 5 Enabled.
(XEN) [   28.560798] AMD-Vi: IOMMU 6 Enabled.
(XEN) [   28.599528] AMD-Vi: IOMMU 7 Enabled.
(XEN) [   28.645382] I/O virtualisation enabled
(XEN) [   28.684034]  - Dom0 mode: Relaxed
(XEN) [   28.722063] Interrupt remapping enabled

Given that the expected case is that all IOMMUs are identical, how about
only printing the details for IOMMU0, and eliding printing for further
IOMMUs which have an identical featureset?

> --- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
> +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
> @@ -346,26 +346,57 @@ struct amd_iommu_dte {
> -#define IOMMU_EXT_FEATURE_PASMAX_SHIFT                  0x0
> -#define IOMMU_EXT_FEATURE_PASMAX_MASK                   0x0000001F
> +union amd_iommu_ext_features {
> +    uint64_t raw;
> +    struct {
> +        unsigned int pref_sup:1;
> +        unsigned int ppr_sup:1;
> +        unsigned int xt_sup:1;
> +        unsigned int nx_sup:1;
> +        unsigned int gt_sup:1;
> +        unsigned int gappi_sup:1;
> +        unsigned int ia_sup:1;
> +        unsigned int ga_sup:1;
> +        unsigned int he_sup:1;
> +        unsigned int pc_sup:1;
> +        unsigned int hats:2;
> +        unsigned int gats:2;
> +        unsigned int glx_sup:2;
> +        unsigned int smif_sup:2;
> +        unsigned int smif_rc:3;
> +        unsigned int gam_sup:3;
> +        unsigned int dual_ppr_log_sup:2;
> +        unsigned int :2;
> +        unsigned int dual_event_log_sup:2;
> +        unsigned int sat_sup:1;
> +        unsigned int :1;
> +        unsigned int pas_max:5;
> +        unsigned int us_sup:1;
> +        unsigned int dev_tbl_seg_sup:2;
> +        unsigned int ppr_early_of_sup:1;
> +        unsigned int ppr_auto_rsp_sup:1;
> +        unsigned int marc_sup:2;
> +        unsigned int blk_stop_mrk_sup:1;
> +        unsigned int perf_opt_sup:1;
> +        unsigned int msi_cap_mmio_sup:1;
> +        unsigned int :1;
> +        unsigned int gio_sup:1;
> +        unsigned int ha_sup:1;
> +        unsigned int eph_sup:1;
> +        unsigned int attr_fw_sup:1;
> +        unsigned int hd_sup:1;
> +        unsigned int :1;
> +        unsigned int inv_iotlb_type_sup:1;
> +        unsigned int viommu_sup:1;
> +        unsigned int vm_guard_io_sup:1;
> +        unsigned int vm_table_size:4;
> +        unsigned int ga_update_dis_sup:1;
> +        unsigned int :2;
> +    } flds;
> +};

I'd suggest bool for single bitfields.  We've been bitten multiple times
by "x = (y & 0x80)" type bugs, which truncate to 0 using unsigned int
bitfields, but correctly become 1 given bool bitfields.

~Andrew
Jan Beulich June 18, 2019, 9:33 a.m. UTC | #3
>>> On 17.06.19 at 22:23, <andrew.cooper3@citrix.com> wrote:
> On 13/06/2019 14:22, Jan Beulich wrote:
>> This also takes care of several of the shift values wrongly having been
>> specified as hex rather than dec.
>>
>> Take the opportunity and add further fields.
>>
>> Signed-off-by: Jan Beulich <jbeulich@suse.com>
>>
>> --- a/xen/drivers/passthrough/amd/iommu_detect.c
>> +++ b/xen/drivers/passthrough/amd/iommu_detect.c
>> @@ -60,43 +60,72 @@ static int __init get_iommu_capabilities
>>  
>>  void __init get_iommu_features(struct amd_iommu *iommu)
>>  {
>> -    u32 low, high;
>> -    int i = 0 ;
>> -    static const char *__initdata feature_str[] = {
>> -        "- Prefetch Pages Command", 
>> -        "- Peripheral Page Service Request", 
>> -        "- X2APIC Supported", 
>> -        "- NX bit Supported", 
>> -        "- Guest Translation", 
>> -        "- Reserved bit [5]",
>> -        "- Invalidate All Command", 
>> -        "- Guest APIC supported", 
>> -        "- Hardware Error Registers", 
>> -        "- Performance Counters", 
>> -        NULL
>> -    };
>> -
>>      ASSERT( iommu->mmio_base );
>>  
>>      if ( !iommu_has_cap(iommu, PCI_CAP_EFRSUP_SHIFT) )
>>      {
>> -        iommu->features = 0;
>> +        iommu->features.raw = 0;
>>          return;
>>      }
>>  
>> -    low = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
>> -    high = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET + 4);
>> -
>> -    iommu->features = ((u64)high << 32) | low;
>> +    iommu->features.raw =
>> +        readq(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
>>  
>>      printk("AMD-Vi: IOMMU Extended Features:\n");
>>  
>> -    while ( feature_str[i] )
>> +#define MASK(fld) ((union amd_iommu_ext_features){ .flds.fld = ~0 }).raw
>> +#define FEAT(fld, str) do { \
>> +    if ( MASK(fld) & (MASK(fld) - 1) ) \
>> +        printk( "- " str ": %#x\n", iommu->features.flds.fld); \
>> +    else if ( iommu->features.raw & MASK(fld) ) \
>> +        printk( "- " str "\n"); \
>> +} while ( false )
>> +
>> +    FEAT(pref_sup,           "Prefetch Pages Command");
>> +    FEAT(ppr_sup,            "Peripheral Page Service Request");
>> +    FEAT(xt_sup,             "x2APIC");
>> +    FEAT(nx_sup,             "NX bit");
>> +    FEAT(gappi_sup,          "Guest APIC Physical Processor Interrupt");
>> +    FEAT(ia_sup,             "Invalidate All Command");
>> +    FEAT(ga_sup,             "Guest APIC");
>> +    FEAT(he_sup,             "Hardware Error Registers");
>> +    FEAT(pc_sup,             "Performance Counters");
>> +    FEAT(hats,               "Host Address Translation Size");
>> +
>> +    if ( iommu->features.flds.gt_sup )
>>      {
>> -        if ( amd_iommu_has_feature(iommu, i) )
>> -            printk( " %s\n", feature_str[i]);
>> -        i++;
>> +        FEAT(gats,           "Guest Address Translation Size");
>> +        FEAT(glx_sup,        "Guest CR3 Root Table Level");
>> +        FEAT(pas_max,        "Maximum PASID");
>>      }
>> +
>> +    FEAT(smif_sup,           "SMI Filter Register");
>> +    FEAT(smif_rc,            "SMI Filter Register Count");
>> +    FEAT(gam_sup,            "Guest Virtual APIC Modes");
>> +    FEAT(dual_ppr_log_sup,   "Dual PPR Log");
>> +    FEAT(dual_event_log_sup, "Dual Event Log");
>> +    FEAT(sat_sup,            "Secure ATS");
>> +    FEAT(us_sup,             "User / Supervisor Page Protection");
>> +    FEAT(dev_tbl_seg_sup,    "Device Table Segmentation");
>> +    FEAT(ppr_early_of_sup,   "PPR Log Overflow Early Warning");
>> +    FEAT(ppr_auto_rsp_sup,   "PPR Automatic Response");
>> +    FEAT(marc_sup,           "Memory Access Routing and Control");
>> +    FEAT(blk_stop_mrk_sup,   "Block StopMark Message");
>> +    FEAT(perf_opt_sup ,      "Performance Optimization");
>> +    FEAT(msi_cap_mmio_sup,   "MSI Capability MMIO Access");
>> +    FEAT(gio_sup,            "Guest I/O Protection");
>> +    FEAT(ha_sup,             "Host Access");
>> +    FEAT(eph_sup,            "Enhanced PPR Handling");
>> +    FEAT(attr_fw_sup,        "Attribute Forward");
>> +    FEAT(hd_sup,             "Host Dirty");
>> +    FEAT(inv_iotlb_type_sup, "Invalidate IOTLB Type");
>> +    FEAT(viommu_sup,         "Virtualized IOMMU");
>> +    FEAT(vm_guard_io_sup,    "VMGuard I/O Support");
>> +    FEAT(vm_table_size,      "VM Table Size");
>> +    FEAT(ga_update_dis_sup,  "Guest Access Bit Update Disable");
>> +
>> +#undef FEAT
>> +#undef MASK
>>  }
> 
> So this is fine, but does come with a downside.  This is the log from a
> Rome system:
> 
> (XEN) [   17.928225] AMD-Vi: IOMMU Extended Features:
> (XEN) [   17.988264] - Peripheral Page Service Request
> (XEN) [   18.048082] - x2APIC
> (XEN) [   18.104735] - NX bit
> (XEN) [   18.160751] - Invalidate All Command
> (XEN) [   18.218116] - Guest APIC
> (XEN) [   18.273660] - Performance Counters
> (XEN) [   18.329868] - Host Address Translation Size: 0x2
> (XEN) [   18.387363] - Guest Address Translation Size: 0
> (XEN) [   18.444446] - Guest CR3 Root Table Level: 0x1
> (XEN) [   18.501006] - Maximum PASID: 0xf
> (XEN) [   18.555753] - SMI Filter Register: 0x1
> (XEN) [   18.610773] - SMI Filter Register Count: 0x2
> (XEN) [   18.666116] - Guest Virtual APIC Modes: 0x1
> (XEN) [   18.721036] - Dual PPR Log: 0x2
> (XEN) [   18.774237] - Dual Event Log: 0x2
> (XEN) [   18.827164] - User / Supervisor Page Protection
> (XEN) [   18.881374] - Device Table Segmentation: 0x3
> (XEN) [   18.934949] - PPR Log Overflow Early Warning
> (XEN) [   18.988186] - PPR Automatic Response
> (XEN) [   19.040193] - Memory Access Routing and Control: 0x1
> (XEN) [   19.093770] - Block StopMark Message
> (XEN) [   19.145300] - Performance Optimization
> (XEN) [   19.196603] - MSI Capability MMIO Access
> (XEN) [   19.247754] - Guest I/O Protection
> (XEN) [   19.297811] - Host Access
> (XEN) [   19.346396] - Enhanced PPR Handling
> (XEN) [   19.395647] - Attribute Forward
> (XEN) [   19.443986] - Virtualized IOMMU
> (XEN) [   19.491828] - VMGuard I/O Support
> (XEN) [   19.539404] - VM Table Size: 0x2
> (XEN) [   19.589837] AMD-Vi: IOMMU Extended Features:
> (XEN) [   19.637829] - Peripheral Page Service Request
> (XEN) [   19.685607] - x2APIC
> (XEN) [   19.730231] - NX bit
> (XEN) [   19.774195] - Invalidate All Command
> (XEN) [   19.819528] - Guest APIC
> (XEN) [   19.863027] - Performance Counters
> (XEN) [   19.907165] - Host Address Translation Size: 0x2
> (XEN) [   19.952578] - Guest Address Translation Size: 0
> (XEN) [   19.997588] - Guest CR3 Root Table Level: 0x1
> (XEN) [   20.042057] - Maximum PASID: 0xf
> (XEN) [   20.084732] - SMI Filter Register: 0x1
> (XEN) [   20.127648] - SMI Filter Register Count: 0x2
> (XEN) [   20.170910] - Guest Virtual APIC Modes: 0x1
> (XEN) [   20.213702] - Dual PPR Log: 0x2
> (XEN) [   20.254765] - Dual Event Log: 0x2
> (XEN) [   20.295567] - User / Supervisor Page Protection
> (XEN) [   20.337626] - Device Table Segmentation: 0x3
> (XEN) [   20.379042] - PPR Log Overflow Early Warning
> (XEN) [   20.420094] - PPR Automatic Response
> (XEN) [   20.459890] - Memory Access Routing and Control: 0x1
> (XEN) [   20.501248] - Block StopMark Message
> (XEN) [   20.540577] - Performance Optimization
> (XEN) [   20.579876] - MSI Capability MMIO Access
> (XEN) [   20.619309] - Guest I/O Protection
> (XEN) [   20.658041] - Host Access
> (XEN) [   20.695937] - Enhanced PPR Handling
> (XEN) [   20.735276] - Attribute Forward
> (XEN) [   20.773830] - Virtualized IOMMU
> (XEN) [   20.812335] - VMGuard I/O Support
> (XEN) [   20.850868] - VM Table Size: 0x2
> (XEN) [   20.892543] AMD-Vi: IOMMU Extended Features:
> (XEN) [   20.932087] - Peripheral Page Service Request
> (XEN) [   20.971756] - x2APIC
> (XEN) [   21.008681] - NX bit
> (XEN) [   21.045279] - Invalidate All Command
> (XEN) [   21.083567] - Guest APIC
> (XEN) [   21.120410] - Performance Counters
> (XEN) [   21.158386] - Host Address Translation Size: 0x2
> (XEN) [   21.197956] - Guest Address Translation Size: 0
> (XEN) [   21.237433] - Guest CR3 Root Table Level: 0x1
> (XEN) [   21.276709] - Maximum PASID: 0xf
> (XEN) [   21.314538] - SMI Filter Register: 0x1
> (XEN) [   21.352844] - SMI Filter Register Count: 0x2
> (XEN) [   21.391728] - Guest Virtual APIC Modes: 0x1
> (XEN) [   21.430614] - Dual PPR Log: 0x2
> (XEN) [   21.468150] - Dual Event Log: 0x2
> (XEN) [   21.505833] - User / Supervisor Page Protection
> (XEN) [   21.545270] - Device Table Segmentation: 0x3
> (XEN) [   21.584538] - PPR Log Overflow Early Warning
> (XEN) [   21.623928] - PPR Automatic Response
> (XEN) [   21.662564] - Memory Access Routing and Control: 0x1
> (XEN) [   21.703268] - Block StopMark Message
> (XEN) [   21.742415] - Performance Optimization
> (XEN) [   21.781692] - MSI Capability MMIO Access
> (XEN) [   21.821159] - Guest I/O Protection
> (XEN) [   21.859916] - Host Access
> (XEN) [   21.897811] - Enhanced PPR Handling
> (XEN) [   21.936818] - Attribute Forward
> (XEN) [   21.975387] - Virtualized IOMMU
> (XEN) [   22.013898] - VMGuard I/O Support
> (XEN) [   22.052448] - VM Table Size: 0x2
> (XEN) [   22.094140] AMD-Vi: IOMMU Extended Features:
> (XEN) [   22.133685] - Peripheral Page Service Request
> (XEN) [   22.173363] - x2APIC
> (XEN) [   22.210287] - NX bit
> (XEN) [   22.246888] - Invalidate All Command
> (XEN) [   22.285176] - Guest APIC
> (XEN) [   22.322008] - Performance Counters
> (XEN) [   22.359994] - Host Address Translation Size: 0x2
> (XEN) [   22.399552] - Guest Address Translation Size: 0
> (XEN) [   22.439028] - Guest CR3 Root Table Level: 0x1
> (XEN) [   22.478307] - Maximum PASID: 0xf
> (XEN) [   22.516133] - SMI Filter Register: 0x1
> (XEN) [   22.554441] - SMI Filter Register Count: 0x2
> (XEN) [   22.593345] - Guest Virtual APIC Modes: 0x1
> (XEN) [   22.632221] - Dual PPR Log: 0x2
> (XEN) [   22.669766] - Dual Event Log: 0x2
> (XEN) [   22.707455] - User / Supervisor Page Protection
> (XEN) [   22.746896] - Device Table Segmentation: 0x3
> (XEN) [   22.786161] - PPR Log Overflow Early Warning
> (XEN) [   22.825552] - PPR Automatic Response
> (XEN) [   22.864211] - Memory Access Routing and Control: 0x1
> (XEN) [   22.904917] - Block StopMark Message
> (XEN) [   22.944075] - Performance Optimization
> (XEN) [   22.983360] - MSI Capability MMIO Access
> (XEN) [   23.022815] - Guest I/O Protection
> (XEN) [   23.061548] - Host Access
> (XEN) [   23.099437] - Enhanced PPR Handling
> (XEN) [   23.138461] - Attribute Forward
> (XEN) [   23.177008] - Virtualized IOMMU
> (XEN) [   23.215523] - VMGuard I/O Support
> (XEN) [   23.254043] - VM Table Size: 0x2
> (XEN) [   23.295705] AMD-Vi: IOMMU Extended Features:
> (XEN) [   23.335250] - Peripheral Page Service Request
> (XEN) [   23.374941] - x2APIC
> (XEN) [   23.411860] - NX bit
> (XEN) [   23.448460] - Invalidate All Command
> (XEN) [   23.486748] - Guest APIC
> (XEN) [   23.523569] - Performance Counters
> (XEN) [   23.561564] - Host Address Translation Size: 0x2
> (XEN) [   23.601127] - Guest Address Translation Size: 0
> (XEN) [   23.640584] - Guest CR3 Root Table Level: 0x1
> (XEN) [   23.679885] - Maximum PASID: 0xf
> (XEN) [   23.717689] - SMI Filter Register: 0x1
> (XEN) [   23.755994] - SMI Filter Register Count: 0x2
> (XEN) [   23.794897] - Guest Virtual APIC Modes: 0x1
> (XEN) [   23.833766] - Dual PPR Log: 0x2
> (XEN) [   23.871319] - Dual Event Log: 0x2
> (XEN) [   23.909008] - User / Supervisor Page Protection
> (XEN) [   23.948434] - Device Table Segmentation: 0x3
> (XEN) [   23.987698] - PPR Log Overflow Early Warning
> (XEN) [   24.027099] - PPR Automatic Response
> (XEN) [   24.065748] - Memory Access Routing and Control: 0x1
> (XEN) [   24.106438] - Block StopMark Message
> (XEN) [   24.145591] - Performance Optimization
> (XEN) [   24.184893] - MSI Capability MMIO Access
> (XEN) [   24.224345] - Guest I/O Protection
> (XEN) [   24.263076] - Host Access
> (XEN) [   24.300974] - Enhanced PPR Handling
> (XEN) [   24.339982] - Attribute Forward
> (XEN) [   24.378528] - Virtualized IOMMU
> (XEN) [   24.417041] - VMGuard I/O Support
> (XEN) [   24.455584] - VM Table Size: 0x2
> (XEN) [   24.497260] AMD-Vi: IOMMU Extended Features:
> (XEN) [   24.536794] - Peripheral Page Service Request
> (XEN) [   24.576469] - x2APIC
> (XEN) [   24.613395] - NX bit
> (XEN) [   24.649996] - Invalidate All Command
> (XEN) [   24.688294] - Guest APIC
> (XEN) [   24.725142] - Performance Counters
> (XEN) [   24.763127] - Host Address Translation Size: 0x2
> (XEN) [   24.802707] - Guest Address Translation Size: 0
> (XEN) [   24.842172] - Guest CR3 Root Table Level: 0x1
> (XEN) [   24.881459] - Maximum PASID: 0xf
> (XEN) [   24.919288] - SMI Filter Register: 0x1
> (XEN) [   24.957583] - SMI Filter Register Count: 0x2
> (XEN) [   24.996496] - Guest Virtual APIC Modes: 0x1
> (XEN) [   25.035364] - Dual PPR Log: 0x2
> (XEN) [   25.072908] - Dual Event Log: 0x2
> (XEN) [   25.110588] - User / Supervisor Page Protection
> (XEN) [   25.150037] - Device Table Segmentation: 0x3
> (XEN) [   25.189290] - PPR Log Overflow Early Warning
> (XEN) [   25.228696] - PPR Automatic Response
> (XEN) [   25.267348] - Memory Access Routing a in Xennd Control: 0x1
> (XEN) [   25.308045] - Block StopMark Message
> (XEN) [   25.347199] - Performance Optimization
> (XEN) [   25.386484] - MSI Capability MMIO Access
> (XEN) [   25.425950] - Guest I/O Protection
> (XEN) [   25.464680] - Host Access
> (XEN) [   25.502580] - Enhanced PPR Handling
> (XEN) [   25.541588] - Attribute Forward
> (XEN) [   25.580145] - Virtualized IOMMU
> (XEN) [   25.618647] - VMGuard I/O Support
> (XEN) [   25.657196] - VM Table Size: 0x2
> (XEN) [   25.698883] AMD-Vi: IOMMU Extended Features:
> (XEN) [   25.738420] - Peripheral Page Service Request
> (XEN) [   25.778084] - x2APIC
> (XEN) [   25.815010] - NX bit
> (XEN) [   25.851603] - Invalidate All Command
> (XEN) [   25.889907] - Guest APIC
> (XEN) [   25.926756] - Performance Counters
> (XEN) [   25.964742] - Host Address Translation Size: 0x2
> (XEN) [   26.004312] - Guest Address Translation Size: 0
> (XEN) [   26.043787] - Guest CR3 Root Table Level: 0x1
> (XEN) [   26.083064] - Maximum PASID: 0xf
> (XEN) [   26.120903] - SMI Filter Register: 0x1
> (XEN) [   26.159215] - SMI Filter Register Count: 0x2
> (XEN) [   26.198129] - Guest Virtual APIC Modes: 0x1
> (XEN) [   26.237015] - Dual PPR Log: 0x2
> (XEN) [   26.274565] - Dual Event Log: 0x2
> (XEN) [   26.312231] - User / Supervisor Page Protection
> (XEN) [   26.351672] - Device Table Segmentation: 0x3
> (XEN) [   26.390949] - PPR Log Overflow Early Warning
> (XEN) [   26.430343] - PPR Automatic Response
> (XEN) [   26.469006] - Memory Access Routing and Control: 0x1
> (XEN) [   26.509711] - Block StopMark Message
> (XEN) [   26.548867] - Performance Optimization
> (XEN) [   26.588159] - MSI Capability MMIO Access
> (XEN) [   26.627627] - Guest I/O Protection
> (XEN) [   26.666355] - Host Access
> (XEN) [   26.704253] - Enhanced PPR Handling
> (XEN) [   26.743271] - Attribute Forward
> (XEN) [   26.781828] - Virtualized IOMMU
> (XEN) [   26.820341] - VMGuard I/O Support
> (XEN) [   26.858874] - VM Table Size: 0x2
> (XEN) [   26.900549] AMD-Vi: IOMMU Extended Features:
> (XEN) [   26.940095] - Peripheral Page Service Request
> (XEN) [   26.979769] - x2APIC
> (XEN) [   27.016686] - NX bit
> (XEN) [   27.053287] - Invalidate All Command
> (XEN) [   27.091582] - Guest APIC
> (XEN) [   27.128432] - Performance Counters
> (XEN) [   27.166418] - Host Address Translation Size: 0x2
> (XEN) [   27.205971] - Guest Address Translation Size: 0
> (XEN) [   27.245440] - Guest CR3 Root Table Level: 0x1
> (XEN) [   27.284714] - Maximum PASID: 0xf
> (XEN) [   27.322543] - SMI Filter Register: 0x1
> (XEN) [   27.360847] - SMI Filter Register Count: 0x2
> (XEN) [   27.399768] - Guest Virtual APIC Modes: 0x1
> (XEN) [   27.438656] - Dual PPR Log: 0x2
> (XEN) [   27.476209] - Dual Event Log: 0x2
> (XEN) [   27.513889] - User / Supervisor Page Protection
> (XEN) [   27.553331] - Device Table Segmentation: 0x3
> (XEN) [   27.592595] - PPR Log Overflow Early Warning
> (XEN) [   27.632003] - PPR Automatic Response
> (XEN) [   27.670655] - Memory Access Routing and Control: 0x1
> (XEN) [   27.711351] - Block StopMark Message
> (XEN) [   27.750525] - Performance Optimization
> (XEN) [   27.789811] - MSI Capability MMIO Access
> (XEN) [   27.829267] - Guest I/O Protection
> (XEN) [   27.868005] - Host Access
> (XEN) [   27.905889] - Enhanced PPR Handling
> (XEN) [   27.944896] - Attribute Forward
> (XEN) [   27.983445] - Virtualized IOMMU
> (XEN) [   28.021956] - VMGuard I/O Support
> (XEN) [   28.060494] - VM Table Size: 0x2
> (XEN) [   28.284879] AMD-Vi: Disabled HAP memory map sharing with IOMMU
> (XEN) [   28.326856] AMD-Vi: IOMMU 0 Enabled.
> (XEN) [   28.366011] AMD-Vi: IOMMU 1 Enabled.
> (XEN) [   28.405142] AMD-Vi: IOMMU 2 Enabled.
> (XEN) [   28.444150] AMD-Vi: IOMMU 3 Enabled.
> (XEN) [   28.483062] AMD-Vi: IOMMU 4 Enabled.
> (XEN) [   28.521923] AMD-Vi: IOMMU 5 Enabled.
> (XEN) [   28.560798] AMD-Vi: IOMMU 6 Enabled.
> (XEN) [   28.599528] AMD-Vi: IOMMU 7 Enabled.
> (XEN) [   28.645382] I/O virtualisation enabled
> (XEN) [   28.684034]  - Dom0 mode: Relaxed
> (XEN) [   28.722063] Interrupt remapping enabled
> 
> Given that the expected case is that all IOMMUs are identical, how about
> only printing the details for IOMMU0, and eliding printing for further
> IOMMUs which have an identical featureset?

Obviously I did notice this too. I can add a patch to the series to
improve the situation (perhaps even ahead of this one), but I don't
think I want to do this right here.

>> --- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
>> +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
>> @@ -346,26 +346,57 @@ struct amd_iommu_dte {
>> -#define IOMMU_EXT_FEATURE_PASMAX_SHIFT                  0x0
>> -#define IOMMU_EXT_FEATURE_PASMAX_MASK                   0x0000001F
>> +union amd_iommu_ext_features {
>> +    uint64_t raw;
>> +    struct {
>> +        unsigned int pref_sup:1;
>> +        unsigned int ppr_sup:1;
>> +        unsigned int xt_sup:1;
>> +        unsigned int nx_sup:1;
>> +        unsigned int gt_sup:1;
>> +        unsigned int gappi_sup:1;
>> +        unsigned int ia_sup:1;
>> +        unsigned int ga_sup:1;
>> +        unsigned int he_sup:1;
>> +        unsigned int pc_sup:1;
>> +        unsigned int hats:2;
>> +        unsigned int gats:2;
>> +        unsigned int glx_sup:2;
>> +        unsigned int smif_sup:2;
>> +        unsigned int smif_rc:3;
>> +        unsigned int gam_sup:3;
>> +        unsigned int dual_ppr_log_sup:2;
>> +        unsigned int :2;
>> +        unsigned int dual_event_log_sup:2;
>> +        unsigned int sat_sup:1;
>> +        unsigned int :1;
>> +        unsigned int pas_max:5;
>> +        unsigned int us_sup:1;
>> +        unsigned int dev_tbl_seg_sup:2;
>> +        unsigned int ppr_early_of_sup:1;
>> +        unsigned int ppr_auto_rsp_sup:1;
>> +        unsigned int marc_sup:2;
>> +        unsigned int blk_stop_mrk_sup:1;
>> +        unsigned int perf_opt_sup:1;
>> +        unsigned int msi_cap_mmio_sup:1;
>> +        unsigned int :1;
>> +        unsigned int gio_sup:1;
>> +        unsigned int ha_sup:1;
>> +        unsigned int eph_sup:1;
>> +        unsigned int attr_fw_sup:1;
>> +        unsigned int hd_sup:1;
>> +        unsigned int :1;
>> +        unsigned int inv_iotlb_type_sup:1;
>> +        unsigned int viommu_sup:1;
>> +        unsigned int vm_guard_io_sup:1;
>> +        unsigned int vm_table_size:4;
>> +        unsigned int ga_update_dis_sup:1;
>> +        unsigned int :2;
>> +    } flds;
>> +};
> 
> I'd suggest bool for single bitfields.  We've been bitten multiple times
> by "x = (y & 0x80)" type bugs, which truncate to 0 using unsigned int
> bitfields, but correctly become 1 given bool bitfields.

Oh, it took me a while to figure what you mean - you're after the case
of x (in your example), not y being a bitfield reference. I don't think
we're at risk of introducing such constructs here, so personally I'd
prefer it to stay as it is, but I'd listen to Brian and/or Suravee leaning
more towards your suggestion.

Jan
Jan Beulich June 18, 2019, 9:37 a.m. UTC | #4
>>> On 17.06.19 at 21:07, <Brian.Woods@amd.com> wrote:
> On Thu, Jun 13, 2019 at 07:22:31AM -0600, Jan Beulich wrote:
>> --- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
>> +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
>> @@ -346,26 +346,57 @@ struct amd_iommu_dte {
>>  #define IOMMU_EXCLUSION_LIMIT_HIGH_MASK		0xFFFFFFFF
>>  #define IOMMU_EXCLUSION_LIMIT_HIGH_SHIFT	0
>>  
>> -/* Extended Feature Register*/
>> +/* Extended Feature Register */
>>  #define IOMMU_EXT_FEATURE_MMIO_OFFSET                   0x30
>> -#define IOMMU_EXT_FEATURE_PREFSUP_SHIFT                 0x0
>> -#define IOMMU_EXT_FEATURE_PPRSUP_SHIFT                  0x1
>> -#define IOMMU_EXT_FEATURE_XTSUP_SHIFT                   0x2
>> -#define IOMMU_EXT_FEATURE_NXSUP_SHIFT                   0x3
>> -#define IOMMU_EXT_FEATURE_GTSUP_SHIFT                   0x4
>> -#define IOMMU_EXT_FEATURE_IASUP_SHIFT                   0x6
>> -#define IOMMU_EXT_FEATURE_GASUP_SHIFT                   0x7
>> -#define IOMMU_EXT_FEATURE_HESUP_SHIFT                   0x8
>> -#define IOMMU_EXT_FEATURE_PCSUP_SHIFT                   0x9
>> -#define IOMMU_EXT_FEATURE_HATS_SHIFT                    0x10
>> -#define IOMMU_EXT_FEATURE_HATS_MASK                     0x00000C00
>> -#define IOMMU_EXT_FEATURE_GATS_SHIFT                    0x12
>> -#define IOMMU_EXT_FEATURE_GATS_MASK                     0x00003000
>> -#define IOMMU_EXT_FEATURE_GLXSUP_SHIFT                  0x14
>> -#define IOMMU_EXT_FEATURE_GLXSUP_MASK                   0x0000C000
>>  
>> -#define IOMMU_EXT_FEATURE_PASMAX_SHIFT                  0x0
>> -#define IOMMU_EXT_FEATURE_PASMAX_MASK                   0x0000001F
>> +union amd_iommu_ext_features {
>> +    uint64_t raw;
>> +    struct {
>> +        unsigned int pref_sup:1;
>> +        unsigned int ppr_sup:1;
>> +        unsigned int xt_sup:1;
>> +        unsigned int nx_sup:1;
>> +        unsigned int gt_sup:1;
>> +        unsigned int gappi_sup:1;
>> +        unsigned int ia_sup:1;
>> +        unsigned int ga_sup:1;
>> +        unsigned int he_sup:1;
>> +        unsigned int pc_sup:1;
>> +        unsigned int hats:2;
>> +        unsigned int gats:2;
>> +        unsigned int glx_sup:2;
>> +        unsigned int smif_sup:2;
>> +        unsigned int smif_rc:3;
>> +        unsigned int gam_sup:3;
>> +        unsigned int dual_ppr_log_sup:2;
>> +        unsigned int :2;
>> +        unsigned int dual_event_log_sup:2;
> 
>> +        unsigned int sat_sup:1;
>> +        unsigned int :1;
> I think these might be flipped.

Oh, indeed. And I've also omitted an 's' from the name. Thanks for
noticing.

Jan
diff mbox series

Patch

--- a/xen/drivers/passthrough/amd/iommu_detect.c
+++ b/xen/drivers/passthrough/amd/iommu_detect.c
@@ -60,43 +60,72 @@  static int __init get_iommu_capabilities
 
 void __init get_iommu_features(struct amd_iommu *iommu)
 {
-    u32 low, high;
-    int i = 0 ;
-    static const char *__initdata feature_str[] = {
-        "- Prefetch Pages Command", 
-        "- Peripheral Page Service Request", 
-        "- X2APIC Supported", 
-        "- NX bit Supported", 
-        "- Guest Translation", 
-        "- Reserved bit [5]",
-        "- Invalidate All Command", 
-        "- Guest APIC supported", 
-        "- Hardware Error Registers", 
-        "- Performance Counters", 
-        NULL
-    };
-
     ASSERT( iommu->mmio_base );
 
     if ( !iommu_has_cap(iommu, PCI_CAP_EFRSUP_SHIFT) )
     {
-        iommu->features = 0;
+        iommu->features.raw = 0;
         return;
     }
 
-    low = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
-    high = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET + 4);
-
-    iommu->features = ((u64)high << 32) | low;
+    iommu->features.raw =
+        readq(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
 
     printk("AMD-Vi: IOMMU Extended Features:\n");
 
-    while ( feature_str[i] )
+#define MASK(fld) ((union amd_iommu_ext_features){ .flds.fld = ~0 }).raw
+#define FEAT(fld, str) do { \
+    if ( MASK(fld) & (MASK(fld) - 1) ) \
+        printk( "- " str ": %#x\n", iommu->features.flds.fld); \
+    else if ( iommu->features.raw & MASK(fld) ) \
+        printk( "- " str "\n"); \
+} while ( false )
+
+    FEAT(pref_sup,           "Prefetch Pages Command");
+    FEAT(ppr_sup,            "Peripheral Page Service Request");
+    FEAT(xt_sup,             "x2APIC");
+    FEAT(nx_sup,             "NX bit");
+    FEAT(gappi_sup,          "Guest APIC Physical Processor Interrupt");
+    FEAT(ia_sup,             "Invalidate All Command");
+    FEAT(ga_sup,             "Guest APIC");
+    FEAT(he_sup,             "Hardware Error Registers");
+    FEAT(pc_sup,             "Performance Counters");
+    FEAT(hats,               "Host Address Translation Size");
+
+    if ( iommu->features.flds.gt_sup )
     {
-        if ( amd_iommu_has_feature(iommu, i) )
-            printk( " %s\n", feature_str[i]);
-        i++;
+        FEAT(gats,           "Guest Address Translation Size");
+        FEAT(glx_sup,        "Guest CR3 Root Table Level");
+        FEAT(pas_max,        "Maximum PASID");
     }
+
+    FEAT(smif_sup,           "SMI Filter Register");
+    FEAT(smif_rc,            "SMI Filter Register Count");
+    FEAT(gam_sup,            "Guest Virtual APIC Modes");
+    FEAT(dual_ppr_log_sup,   "Dual PPR Log");
+    FEAT(dual_event_log_sup, "Dual Event Log");
+    FEAT(sat_sup,            "Secure ATS");
+    FEAT(us_sup,             "User / Supervisor Page Protection");
+    FEAT(dev_tbl_seg_sup,    "Device Table Segmentation");
+    FEAT(ppr_early_of_sup,   "PPR Log Overflow Early Warning");
+    FEAT(ppr_auto_rsp_sup,   "PPR Automatic Response");
+    FEAT(marc_sup,           "Memory Access Routing and Control");
+    FEAT(blk_stop_mrk_sup,   "Block StopMark Message");
+    FEAT(perf_opt_sup ,      "Performance Optimization");
+    FEAT(msi_cap_mmio_sup,   "MSI Capability MMIO Access");
+    FEAT(gio_sup,            "Guest I/O Protection");
+    FEAT(ha_sup,             "Host Access");
+    FEAT(eph_sup,            "Enhanced PPR Handling");
+    FEAT(attr_fw_sup,        "Attribute Forward");
+    FEAT(hd_sup,             "Host Dirty");
+    FEAT(inv_iotlb_type_sup, "Invalidate IOTLB Type");
+    FEAT(viommu_sup,         "Virtualized IOMMU");
+    FEAT(vm_guard_io_sup,    "VMGuard I/O Support");
+    FEAT(vm_table_size,      "VM Table Size");
+    FEAT(ga_update_dis_sup,  "Guest Access Bit Update Disable");
+
+#undef FEAT
+#undef MASK
 }
 
 int __init amd_iommu_detect_one_acpi(
--- a/xen/drivers/passthrough/amd/iommu_guest.c
+++ b/xen/drivers/passthrough/amd/iommu_guest.c
@@ -638,7 +638,7 @@  static uint64_t iommu_mmio_read64(struct
         val = reg_to_u64(iommu->reg_status);
         break;
     case IOMMU_EXT_FEATURE_MMIO_OFFSET:
-        val = reg_to_u64(iommu->reg_ext_feature);
+        val = iommu->reg_ext_feature.raw;
         break;
 
     default:
@@ -802,39 +802,26 @@  int guest_iommu_set_base(struct domain *
 /* Initialize mmio read only bits */
 static void guest_iommu_reg_init(struct guest_iommu *iommu)
 {
-    uint32_t lower, upper;
+    union amd_iommu_ext_features ef = {
+        /* Support prefetch */
+        .flds.pref_sup = 1,
+        /* Support PPR log */
+        .flds.ppr_sup = 1,
+        /* Support guest translation */
+        .flds.gt_sup = 1,
+        /* Support invalidate all command */
+        .flds.ia_sup = 1,
+        /* Host translation size has 6 levels */
+        .flds.hats = HOST_ADDRESS_SIZE_6_LEVEL,
+        /* Guest translation size has 6 levels */
+        .flds.gats = GUEST_ADDRESS_SIZE_6_LEVEL,
+        /* Single level gCR3 */
+        .flds.glx_sup = GUEST_CR3_1_LEVEL,
+        /* 9 bit PASID */
+        .flds.pas_max = PASMAX_9_bit,
+    };
 
-    lower = upper = 0;
-    /* Support prefetch */
-    iommu_set_bit(&lower,IOMMU_EXT_FEATURE_PREFSUP_SHIFT);
-    /* Support PPR log */
-    iommu_set_bit(&lower,IOMMU_EXT_FEATURE_PPRSUP_SHIFT);
-    /* Support guest translation */
-    iommu_set_bit(&lower,IOMMU_EXT_FEATURE_GTSUP_SHIFT);
-    /* Support invalidate all command */
-    iommu_set_bit(&lower,IOMMU_EXT_FEATURE_IASUP_SHIFT);
-
-    /* Host translation size has 6 levels */
-    set_field_in_reg_u32(HOST_ADDRESS_SIZE_6_LEVEL, lower,
-                         IOMMU_EXT_FEATURE_HATS_MASK,
-                         IOMMU_EXT_FEATURE_HATS_SHIFT,
-                         &lower);
-    /* Guest translation size has 6 levels */
-    set_field_in_reg_u32(GUEST_ADDRESS_SIZE_6_LEVEL, lower,
-                         IOMMU_EXT_FEATURE_GATS_MASK,
-                         IOMMU_EXT_FEATURE_GATS_SHIFT,
-                         &lower);
-    /* Single level gCR3 */
-    set_field_in_reg_u32(GUEST_CR3_1_LEVEL, lower,
-                         IOMMU_EXT_FEATURE_GLXSUP_MASK,
-                         IOMMU_EXT_FEATURE_GLXSUP_SHIFT, &lower);
-    /* 9 bit PASID */
-    set_field_in_reg_u32(PASMAX_9_bit, upper,
-                         IOMMU_EXT_FEATURE_PASMAX_MASK,
-                         IOMMU_EXT_FEATURE_PASMAX_SHIFT, &upper);
-
-    iommu->reg_ext_feature.lo = lower;
-    iommu->reg_ext_feature.hi = upper;
+    iommu->reg_ext_feature = ef;
 }
 
 static int guest_iommu_mmio_range(struct vcpu *v, unsigned long addr)
--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -883,7 +883,7 @@  static void enable_iommu(struct amd_iomm
     register_iommu_event_log_in_mmio_space(iommu);
     register_iommu_exclusion_range(iommu);
 
-    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
+    if ( iommu->features.flds.ppr_sup )
         register_iommu_ppr_log_in_mmio_space(iommu);
 
     desc = irq_to_desc(iommu->msi.irq);
@@ -897,15 +897,15 @@  static void enable_iommu(struct amd_iomm
     set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_ENABLED);
     set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
 
-    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
+    if ( iommu->features.flds.ppr_sup )
         set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_ENABLED);
 
-    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_GTSUP_SHIFT) )
+    if ( iommu->features.flds.gt_sup )
         set_iommu_guest_translation_control(iommu, IOMMU_CONTROL_ENABLED);
 
     set_iommu_translation_control(iommu, IOMMU_CONTROL_ENABLED);
 
-    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_IASUP_SHIFT) )
+    if ( iommu->features.flds.ia_sup )
         amd_iommu_flush_all_caches(iommu);
 
     iommu->enabled = 1;
@@ -928,10 +928,10 @@  static void disable_iommu(struct amd_iom
     set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_DISABLED);
     set_iommu_event_log_control(iommu, IOMMU_CONTROL_DISABLED);
 
-    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
+    if ( iommu->features.flds.ppr_sup )
         set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_DISABLED);
 
-    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_GTSUP_SHIFT) )
+    if ( iommu->features.flds.gt_sup )
         set_iommu_guest_translation_control(iommu, IOMMU_CONTROL_DISABLED);
 
     set_iommu_translation_control(iommu, IOMMU_CONTROL_DISABLED);
@@ -1027,7 +1027,7 @@  static int __init amd_iommu_init_one(str
 
     get_iommu_features(iommu);
 
-    if ( iommu->features )
+    if ( iommu->features.raw )
         iommuv2_enabled = 1;
 
     if ( allocate_cmd_buffer(iommu) == NULL )
@@ -1036,9 +1036,8 @@  static int __init amd_iommu_init_one(str
     if ( allocate_event_log(iommu) == NULL )
         goto error_out;
 
-    if ( amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
-        if ( allocate_ppr_log(iommu) == NULL )
-            goto error_out;
+    if ( iommu->features.flds.ppr_sup && !allocate_ppr_log(iommu) )
+        goto error_out;
 
     if ( !set_iommu_interrupt_handler(iommu) )
         goto error_out;
@@ -1389,7 +1388,7 @@  void amd_iommu_resume(void)
     }
 
     /* flush all cache entries after iommu re-enabled */
-    if ( !amd_iommu_has_feature(iommu, IOMMU_EXT_FEATURE_IASUP_SHIFT) )
+    if ( !iommu->features.flds.ia_sup )
     {
         invalidate_all_devices();
         invalidate_all_domain_pages();
--- a/xen/include/asm-x86/amd-iommu.h
+++ b/xen/include/asm-x86/amd-iommu.h
@@ -83,7 +83,7 @@  struct amd_iommu {
     iommu_cap_t cap;
 
     u8 ht_flags;
-    u64 features;
+    union amd_iommu_ext_features features;
 
     void *mmio_base;
     unsigned long mmio_base_phys;
@@ -174,7 +174,7 @@  struct guest_iommu {
     /* MMIO regs */
     struct mmio_reg         reg_ctrl;              /* MMIO offset 0018h */
     struct mmio_reg         reg_status;            /* MMIO offset 2020h */
-    struct mmio_reg         reg_ext_feature;       /* MMIO offset 0030h */
+    union amd_iommu_ext_features reg_ext_feature;  /* MMIO offset 0030h */
 
     /* guest interrupt settings */
     struct guest_iommu_msi  msi;
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
@@ -346,26 +346,57 @@  struct amd_iommu_dte {
 #define IOMMU_EXCLUSION_LIMIT_HIGH_MASK		0xFFFFFFFF
 #define IOMMU_EXCLUSION_LIMIT_HIGH_SHIFT	0
 
-/* Extended Feature Register*/
+/* Extended Feature Register */
 #define IOMMU_EXT_FEATURE_MMIO_OFFSET                   0x30
-#define IOMMU_EXT_FEATURE_PREFSUP_SHIFT                 0x0
-#define IOMMU_EXT_FEATURE_PPRSUP_SHIFT                  0x1
-#define IOMMU_EXT_FEATURE_XTSUP_SHIFT                   0x2
-#define IOMMU_EXT_FEATURE_NXSUP_SHIFT                   0x3
-#define IOMMU_EXT_FEATURE_GTSUP_SHIFT                   0x4
-#define IOMMU_EXT_FEATURE_IASUP_SHIFT                   0x6
-#define IOMMU_EXT_FEATURE_GASUP_SHIFT                   0x7
-#define IOMMU_EXT_FEATURE_HESUP_SHIFT                   0x8
-#define IOMMU_EXT_FEATURE_PCSUP_SHIFT                   0x9
-#define IOMMU_EXT_FEATURE_HATS_SHIFT                    0x10
-#define IOMMU_EXT_FEATURE_HATS_MASK                     0x00000C00
-#define IOMMU_EXT_FEATURE_GATS_SHIFT                    0x12
-#define IOMMU_EXT_FEATURE_GATS_MASK                     0x00003000
-#define IOMMU_EXT_FEATURE_GLXSUP_SHIFT                  0x14
-#define IOMMU_EXT_FEATURE_GLXSUP_MASK                   0x0000C000
 
-#define IOMMU_EXT_FEATURE_PASMAX_SHIFT                  0x0
-#define IOMMU_EXT_FEATURE_PASMAX_MASK                   0x0000001F
+union amd_iommu_ext_features {
+    uint64_t raw;
+    struct {
+        unsigned int pref_sup:1;
+        unsigned int ppr_sup:1;
+        unsigned int xt_sup:1;
+        unsigned int nx_sup:1;
+        unsigned int gt_sup:1;
+        unsigned int gappi_sup:1;
+        unsigned int ia_sup:1;
+        unsigned int ga_sup:1;
+        unsigned int he_sup:1;
+        unsigned int pc_sup:1;
+        unsigned int hats:2;
+        unsigned int gats:2;
+        unsigned int glx_sup:2;
+        unsigned int smif_sup:2;
+        unsigned int smif_rc:3;
+        unsigned int gam_sup:3;
+        unsigned int dual_ppr_log_sup:2;
+        unsigned int :2;
+        unsigned int dual_event_log_sup:2;
+        unsigned int sat_sup:1;
+        unsigned int :1;
+        unsigned int pas_max:5;
+        unsigned int us_sup:1;
+        unsigned int dev_tbl_seg_sup:2;
+        unsigned int ppr_early_of_sup:1;
+        unsigned int ppr_auto_rsp_sup:1;
+        unsigned int marc_sup:2;
+        unsigned int blk_stop_mrk_sup:1;
+        unsigned int perf_opt_sup:1;
+        unsigned int msi_cap_mmio_sup:1;
+        unsigned int :1;
+        unsigned int gio_sup:1;
+        unsigned int ha_sup:1;
+        unsigned int eph_sup:1;
+        unsigned int attr_fw_sup:1;
+        unsigned int hd_sup:1;
+        unsigned int :1;
+        unsigned int inv_iotlb_type_sup:1;
+        unsigned int viommu_sup:1;
+        unsigned int vm_guard_io_sup:1;
+        unsigned int vm_table_size:4;
+        unsigned int ga_update_dis_sup:1;
+        unsigned int :2;
+    } flds;
+};
 
 /* Status Register*/
 #define IOMMU_STATUS_MMIO_OFFSET		0x2020
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -219,13 +219,6 @@  static inline int iommu_has_cap(struct a
     return !!(iommu->cap.header & (1u << bit));
 }
 
-static inline int amd_iommu_has_feature(struct amd_iommu *iommu, uint32_t bit)
-{
-    if ( !iommu_has_cap(iommu, PCI_CAP_EFRSUP_SHIFT) )
-        return 0;
-    return !!(iommu->features & (1U << bit));
-}
-
 /* access tail or head pointer of ring buffer */
 static inline uint32_t iommu_get_rb_pointer(uint32_t reg)
 {