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

Re: [Xen-devel] [PATCH v3 12/14] AMD/IOMMU: enable x2APIC mode when available


  • To: Jan Beulich <JBeulich@xxxxxxxx>
  • From: "Woods, Brian" <Brian.Woods@xxxxxxx>
  • Date: Fri, 19 Jul 2019 18:41:33 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1;spf=pass smtp.mailfrom=amd.com;dmarc=pass action=none header.from=amd.com;dkim=pass header.d=amd.com;arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=/i65wpnudHgkxdUOiUMcsYse7R8UlcSvFfiVS7h8dTc=; b=H3g7WLDIRyDt/XPd/8Tc66EvPDLVa9YC+iaCnGI962lfPrIiAOZZVNBurpov24EXQK4tcanF80KnWgWYLnPFYsg5dEIs1eI7fbly0mGCtq1wuNYbfrzmNlQ08s2oMuxT9LU1zvjsAUx/CLOqsi7e3zmrLRKuUoz45tM4jtccTeHs3m3qpp4foAsBU3jT/e0iPj9Q1mctwuFA0ZMZGOgry9TDghq2ILp/HKCuSc+mKhn2p+kww5MUNPntOMN8eHQePBY8NLRXhFdZ/d/cRYEnFFgTZbWbil39uku2tysC1yjA8gqqF/nuuJzHinZe5CmjbUSSD3940V/UStmGm1uwZA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ZUqlZrtzFUma/1UFP6YplQLetk/zRPgp8ZdoUSXGWuF3RHASTZyy3DNTfYp0yn/5xrEqdR341eoiHYXypenpn5xcv0yDRJt4bFpVBWr+eKZox9+kryF3CjnmSiBSnyRHgBF5vX4WkRNMoUaPYXWswDMotwIAgIxuoYr3+O4rpppRaMAM+SKxrUfP7BFLAYrcQ51g0dtglTQB0dJcmNlo9BTSQrCCcNzJd1WwQl3JEIRypWA59xeFRcypHH3mMwtGPvfJ937HQQfAI4vOYNgFeOQnwhE+Y6Z094jFufj5pK4cJblnagk4fZ2VAXjrVftC4HjFhO1eyMp47y1bPXswzg==
  • Authentication-results: spf=none (sender IP is ) smtp.mailfrom=Brian.Woods@xxxxxxx;
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, "Woods, Brian" <Brian.Woods@xxxxxxx>, "Suthikulpanit, Suravee" <Suravee.Suthikulpanit@xxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
  • Delivery-date: Fri, 19 Jul 2019 18:41:42 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHVO/V28qjd4vDB8kKPWy7eOEQWUqbSSz+A
  • Thread-topic: [PATCH v3 12/14] AMD/IOMMU: enable x2APIC mode when available

On Tue, Jul 16, 2019 at 04:40:33PM +0000, Jan Beulich wrote:
> In order for the CPUs to use x2APIC mode, the IOMMU(s) first need to be
> switched into suitable state.
> 
> The post-AP-bringup IRQ affinity adjustment is done also for the non-
> x2APIC case, matching what VT-d does.
> 
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

Acked-by: Brian Woods <brian.woods@xxxxxxx>

> ---
> v3: Set GAEn (and other control register bits) earlier. Also clear the
>      bits enabled here in amd_iommu_init_cleanup(). Re-base. Pass NULL
>      CPU mask to set_{x2apic,msi}_affinity().
> v2: Drop cpu_has_cx16 check. Add comment.
> ---
> TBD: Instead of the system_state check in iov_enable_xt() the function
>       could also zap its own hook pointer, at which point it could also
>       become __init. This would, however, require that either
>       resume_x2apic() be bound to ignore iommu_enable_x2apic() errors
>       forever, or that iommu_enable_x2apic() be slightly re-arranged to
>       not return -EOPNOTSUPP when finding a NULL hook during resume.
> 
> --- a/xen/drivers/passthrough/amd/iommu_init.c
> +++ b/xen/drivers/passthrough/amd/iommu_init.c
> @@ -834,6 +834,30 @@ static bool_t __init set_iommu_interrupt
>       return 1;
>   }
>   
> +int iov_adjust_irq_affinities(void)
> +{
> +    const struct amd_iommu *iommu;
> +
> +    if ( !iommu_enabled )
> +        return 0;
> +
> +    for_each_amd_iommu ( iommu )
> +    {
> +        struct irq_desc *desc = irq_to_desc(iommu->msi.irq);
> +        unsigned long flags;
> +
> +        spin_lock_irqsave(&desc->lock, flags);
> +        if ( iommu->ctrl.int_cap_xt_en )
> +            set_x2apic_affinity(desc, NULL);
> +        else
> +            set_msi_affinity(desc, NULL);
> +        spin_unlock_irqrestore(&desc->lock, flags);
> +    }
> +
> +    return 0;
> +}
> +__initcall(iov_adjust_irq_affinities);
> +
>   /*
>    * Family15h Model 10h-1fh erratum 746 (IOMMU Logging May Stall 
> Translations)
>    * Workaround:
> @@ -1047,7 +1071,7 @@ static void * __init allocate_ppr_log(st
>                                   IOMMU_PPR_LOG_DEFAULT_ENTRIES, "PPR Log");
>   }
>   
> -static int __init amd_iommu_init_one(struct amd_iommu *iommu)
> +static int __init amd_iommu_init_one(struct amd_iommu *iommu, bool intr)
>   {
>       if ( allocate_cmd_buffer(iommu) == NULL )
>           goto error_out;
> @@ -1058,7 +1082,7 @@ static int __init amd_iommu_init_one(str
>       if ( iommu->features.flds.ppr_sup && !allocate_ppr_log(iommu) )
>           goto error_out;
>   
> -    if ( !set_iommu_interrupt_handler(iommu) )
> +    if ( intr && !set_iommu_interrupt_handler(iommu) )
>           goto error_out;
>   
>       /* To make sure that device_table.buffer has been successfully 
> allocated */
> @@ -1087,8 +1111,16 @@ static void __init amd_iommu_init_cleanu
>       list_for_each_entry_safe ( iommu, next, &amd_iommu_head, list )
>       {
>           list_del(&iommu->list);
> +
> +        iommu->ctrl.ga_en = 0;
> +        iommu->ctrl.xt_en = 0;
> +        iommu->ctrl.int_cap_xt_en = 0;
> +
>           if ( iommu->enabled )
>               disable_iommu(iommu);
> +        else if ( iommu->mmio_base )
> +            writeq(iommu->ctrl.raw,
> +                   iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
>   
>           deallocate_ring_buffer(&iommu->cmd_buffer);
>           deallocate_ring_buffer(&iommu->event_log);
> @@ -1290,7 +1322,7 @@ static int __init amd_iommu_prepare_one(
>       return 0;
>   }
>   
> -int __init amd_iommu_init(void)
> +int __init amd_iommu_prepare(bool xt)
>   {
>       struct amd_iommu *iommu;
>       int rc = -ENODEV;
> @@ -1305,9 +1337,14 @@ int __init amd_iommu_init(void)
>       if ( unlikely(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) )
>           goto error_out;
>   
> +    /* Have we been here before? */
> +    if ( ivhd_type )
> +        return 0;
> +
>       rc = amd_iommu_get_supported_ivhd_type();
>       if ( rc < 0 )
>           goto error_out;
> +    BUG_ON(!rc);
>       ivhd_type = rc;
>   
>       rc = amd_iommu_get_ivrs_dev_entries();
> @@ -1323,9 +1360,37 @@ int __init amd_iommu_init(void)
>           rc = amd_iommu_prepare_one(iommu);
>           if ( rc )
>               goto error_out;
> +
> +        rc = -ENODEV;
> +        if ( xt && (!iommu->features.flds.ga_sup || 
> !iommu->features.flds.xt_sup) )
> +            goto error_out;
> +    }
> +
> +    for_each_amd_iommu ( iommu )
> +    {
> +        /* NB: There's no need to actually write these out right here. */
> +        iommu->ctrl.ga_en |= xt;
> +        iommu->ctrl.xt_en = xt;
> +        iommu->ctrl.int_cap_xt_en = xt;
>       }
>   
>       rc = amd_iommu_update_ivrs_mapping_acpi();
> +
> + error_out:
> +    if ( rc )
> +    {
> +        amd_iommu_init_cleanup();
> +        ivhd_type = 0;
> +    }
> +
> +    return rc;
> +}
> +
> +int __init amd_iommu_init(bool xt)
> +{
> +    struct amd_iommu *iommu;
> +    int rc = amd_iommu_prepare(xt);
> +
>       if ( rc )
>           goto error_out;
>   
> @@ -1351,7 +1416,12 @@ int __init amd_iommu_init(void)
>       /* per iommu initialization  */
>       for_each_amd_iommu ( iommu )
>       {
> -        rc = amd_iommu_init_one(iommu);
> +        /*
> +         * Setting up of the IOMMU interrupts cannot occur yet at the (very
> +         * early) time we get here when enabling x2APIC mode. Suppress it
> +         * here, and do it explicitly in amd_iommu_init_interrupt().
> +         */
> +        rc = amd_iommu_init_one(iommu, !xt);
>           if ( rc )
>               goto error_out;
>       }
> @@ -1363,6 +1433,40 @@ error_out:
>       return rc;
>   }
>   
> +int __init amd_iommu_init_interrupt(void)
> +{
> +    struct amd_iommu *iommu;
> +    int rc = 0;
> +
> +    for_each_amd_iommu ( iommu )
> +    {
> +        struct irq_desc *desc;
> +
> +        if ( !set_iommu_interrupt_handler(iommu) )
> +        {
> +            rc = -EIO;
> +            break;
> +        }
> +
> +        desc = irq_to_desc(iommu->msi.irq);
> +
> +        spin_lock(&desc->lock);
> +        ASSERT(iommu->ctrl.int_cap_xt_en);
> +        set_x2apic_affinity(desc, &cpu_online_map);
> +        spin_unlock(&desc->lock);
> +
> +        set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
> +
> +        if ( iommu->features.flds.ppr_sup )
> +            set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_ENABLED);
> +    }
> +
> +    if ( rc )
> +        amd_iommu_init_cleanup();
> +
> +    return rc;
> +}
> +
>   static void invalidate_all_domain_pages(void)
>   {
>       struct domain *d;
> --- a/xen/drivers/passthrough/amd/iommu_intr.c
> +++ b/xen/drivers/passthrough/amd/iommu_intr.c
> @@ -791,6 +791,35 @@ void *__init amd_iommu_alloc_intremap_ta
>       return tb;
>   }
>   
> +bool __init iov_supports_xt(void)
> +{
> +    unsigned int apic;
> +
> +    if ( !iommu_enable || !iommu_intremap )
> +        return false;
> +
> +    if ( amd_iommu_prepare(true) )
> +        return false;
> +
> +    for ( apic = 0; apic < nr_ioapics; apic++ )
> +    {
> +        unsigned int idx = ioapic_id_to_index(IO_APIC_ID(apic));
> +
> +        if ( idx == MAX_IO_APICS )
> +            return false;
> +
> +        if ( !find_iommu_for_device(ioapic_sbdf[idx].seg,
> +                                    ioapic_sbdf[idx].bdf) )
> +        {
> +            AMD_IOMMU_DEBUG("No IOMMU for IO-APIC %#x (ID %x)\n",
> +                            apic, IO_APIC_ID(apic));
> +            return false;
> +        }
> +    }
> +
> +    return true;
> +}
> +
>   int __init amd_setup_hpet_msi(struct msi_desc *msi_desc)
>   {
>       spinlock_t *lock;
> --- a/xen/drivers/passthrough/amd/pci_amd_iommu.c
> +++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c
> @@ -170,7 +170,8 @@ static int __init iov_detect(void)
>       if ( !iommu_enable && !iommu_intremap )
>           return 0;
>   
> -    if ( amd_iommu_init() != 0 )
> +    else if ( (init_done ? amd_iommu_init_interrupt()
> +                         : amd_iommu_init(false)) != 0 )
>       {
>           printk("AMD-Vi: Error initialization\n");
>           return -ENODEV;
> @@ -183,6 +184,25 @@ static int __init iov_detect(void)
>       return scan_pci_devices();
>   }
>   
> +static int iov_enable_xt(void)
> +{
> +    int rc;
> +
> +    if ( system_state >= SYS_STATE_active )
> +        return 0;
> +
> +    if ( (rc = amd_iommu_init(true)) != 0 )
> +    {
> +        printk("AMD-Vi: Error %d initializing for x2APIC mode\n", rc);
> +        /* -ENXIO has special meaning to the caller - convert it. */
> +        return rc != -ENXIO ? rc : -ENODATA;
> +    }
> +
> +    init_done = true;
> +
> +    return 0;
> +}
> +
>   int amd_iommu_alloc_root(struct domain_iommu *hd)
>   {
>       if ( unlikely(!hd->arch.root_table) )
> @@ -559,11 +579,13 @@ static const struct iommu_ops __initcons
>       .free_page_table = deallocate_page_table,
>       .reassign_device = reassign_device,
>       .get_device_group_id = amd_iommu_group_id,
> +    .enable_x2apic = iov_enable_xt,
>       .update_ire_from_apic = amd_iommu_ioapic_update_ire,
>       .update_ire_from_msi = amd_iommu_msi_msg_update_ire,
>       .read_apic_from_ire = amd_iommu_read_ioapic_from_ire,
>       .read_msi_from_ire = amd_iommu_read_msi_from_ire,
>       .setup_hpet_msi = amd_setup_hpet_msi,
> +    .adjust_irq_affinities = iov_adjust_irq_affinities,
>       .suspend = amd_iommu_suspend,
>       .resume = amd_iommu_resume,
>       .share_p2m = amd_iommu_share_p2m,
> @@ -574,4 +596,5 @@ static const struct iommu_ops __initcons
>   static const struct iommu_init_ops __initconstrel _iommu_init_ops = {
>       .ops = &_iommu_ops,
>       .setup = iov_detect,
> +    .supports_x2apic = iov_supports_xt,
>   };
> --- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
> +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
> @@ -48,8 +48,11 @@ int amd_iommu_detect_acpi(void);
>   void get_iommu_features(struct amd_iommu *iommu);
>   
>   /* amd-iommu-init functions */
> -int amd_iommu_init(void);
> +int amd_iommu_prepare(bool xt);
> +int amd_iommu_init(bool xt);
> +int amd_iommu_init_interrupt(void);
>   int amd_iommu_update_ivrs_mapping_acpi(void);
> +int iov_adjust_irq_affinities(void);
>   
>   /* mapping functions */
>   int __must_check amd_iommu_map_page(struct domain *d, dfn_t dfn,
> @@ -96,6 +99,7 @@ void amd_iommu_flush_all_caches(struct a
>   struct amd_iommu *find_iommu_for_device(int seg, int bdf);
>   
>   /* interrupt remapping */
> +bool iov_supports_xt(void);
>   int amd_iommu_setup_ioapic_remapping(void);
>   void *amd_iommu_alloc_intremap_table(
>       const struct amd_iommu *, unsigned long **);
> 

-- 
Brian Woods

_______________________________________________
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®.