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

Re: [Xen-devel] [PATCH] VT-d: fix RMRR related error handling


  • To: Jan Beulich <JBeulich@xxxxxxxx>, xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: "Tian, Kevin" <kevin.tian@xxxxxxxxx>
  • Date: Thu, 9 Oct 2014 19:45:17 +0000
  • Accept-language: en-US
  • Cc: "Zhang, Yang Z" <yang.z.zhang@xxxxxxxxx>
  • Delivery-date: Thu, 09 Oct 2014 19:46:13 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xen.org>
  • Thread-index: AQHP4XyrvfK+M36lpUOTLgt4Q+c6upwoMAJg
  • Thread-topic: [Xen-devel] [PATCH] VT-d: fix RMRR related error handling

> From: Jan Beulich
> Sent: Monday, October 06, 2014 8:44 AM
> 
> - reassign_device_ownership() now tears down RMRR mappings (for other
>   than Dom0)
> - to facilitate that, rmrr_identity_mapping() now deals with both
>   establishing and tearing down of these mappings (the open coded
>   equivalent in intel_iommu_remove_device() is being replaced at once)
> - intel_iommu_assign_device() now unrolls the assignment upon RMRR
>   mapping errors
> - intel_iommu_add_device() now returns consistent values upon RMRR
>   mapping failures (was: failure when last iteration ran into a
>   problem, success otherwise)
> - intel_iommu_remove_device() no longer special cases Dom0 (it only
>   ever gets called for devices removed from the _system_, not a domain)
> - rmrr_identity_mapping() now returns a proper error indicator instead
>   of -1 when intel_iommu_map_page() failed
> 
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

Acked-by: Kevin Tian <kevin.tian@xxxxxxxxx>

> 
> --- a/xen/drivers/passthrough/vtd/iommu.c
> +++ b/xen/drivers/passthrough/vtd/iommu.c
> @@ -1661,38 +1661,6 @@ out:
>      return ret;
>  }
> 
> -static int reassign_device_ownership(
> -    struct domain *source,
> -    struct domain *target,
> -    u8 devfn, struct pci_dev *pdev)
> -{
> -    int ret;
> -
> -    /*
> -     * Devices assigned to untrusted domains (here assumed to be any
> domU)
> -     * can attempt to send arbitrary LAPIC/MSI messages. We are
> unprotected
> -     * by the root complex unless interrupt remapping is enabled.
> -     */
> -    if ( (target != hardware_domain) && !iommu_intremap )
> -        untrusted_msi = 1;
> -
> -    ret = domain_context_unmap(source, devfn, pdev);
> -    if ( ret )
> -        return ret;
> -
> -    ret = domain_context_mapping(target, devfn, pdev);
> -    if ( ret )
> -        return ret;
> -
> -    if ( devfn == pdev->devfn )
> -    {
> -        list_move(&pdev->domain_list, &target->arch.pdev_list);
> -        pdev->domain = target;
> -    }
> -
> -    return ret;
> -}
> -
>  static void iommu_domain_teardown(struct domain *d)
>  {
>      struct hvm_iommu *hd = domain_hvm_iommu(d);
> @@ -1839,11 +1807,11 @@ static void iommu_set_pgd(struct domain
>      hd->arch.pgd_maddr =
> pagetable_get_paddr(pagetable_from_mfn(pgd_mfn));
>  }
> 
> -static int rmrr_identity_mapping(struct domain *d,
> -                                 struct acpi_rmrr_unit *rmrr)
> +static int rmrr_identity_mapping(struct domain *d, bool_t map,
> +                                 const struct acpi_rmrr_unit *rmrr)
>  {
> -    u64 base, end;
> -    unsigned long base_pfn, end_pfn;
> +    unsigned long base_pfn = rmrr->base_address >> PAGE_SHIFT_4K;
> +    unsigned long end_pfn = PAGE_ALIGN_4K(rmrr->end_address) >>
> PAGE_SHIFT_4K;
>      struct mapped_rmrr *mrmrr;
>      struct hvm_iommu *hd = domain_hvm_iommu(d);
> 
> @@ -1859,21 +1827,40 @@ static int rmrr_identity_mapping(struct
>          if ( mrmrr->base == rmrr->base_address &&
>               mrmrr->end == rmrr->end_address )
>          {
> -            ++mrmrr->count;
> -            return 0;
> +            int ret = 0;
> +
> +            if ( map )
> +            {
> +                ++mrmrr->count;
> +                return 0;
> +            }
> +
> +            if ( --mrmrr->count )
> +                return 0;
> +
> +            while ( base_pfn < end_pfn )
> +            {
> +                if ( intel_iommu_unmap_page(d, base_pfn) )
> +                    ret = -ENXIO;
> +                base_pfn++;
> +            }
> +
> +            list_del(&mrmrr->list);
> +            xfree(mrmrr);
> +            return ret;
>          }
>      }
> 
> -    base = rmrr->base_address & PAGE_MASK_4K;
> -    base_pfn = base >> PAGE_SHIFT_4K;
> -    end = PAGE_ALIGN_4K(rmrr->end_address);
> -    end_pfn = end >> PAGE_SHIFT_4K;
> +    if ( !map )
> +        return -ENOENT;
> 
>      while ( base_pfn < end_pfn )
>      {
> -        if ( intel_iommu_map_page(d, base_pfn, base_pfn,
> -
> IOMMUF_readable|IOMMUF_writable) )
> -            return -1;
> +        int err = intel_iommu_map_page(d, base_pfn, base_pfn,
> +
> IOMMUF_readable|IOMMUF_writable);
> +
> +        if ( err )
> +            return err;
>          base_pfn++;
>      }
> 
> @@ -1913,14 +1900,14 @@ static int intel_iommu_add_device(u8 dev
>               PCI_BUS(bdf) == pdev->bus &&
>               PCI_DEVFN2(bdf) == devfn )
>          {
> -            ret = rmrr_identity_mapping(pdev->domain, rmrr);
> +            ret = rmrr_identity_mapping(pdev->domain, 1, rmrr);
>              if ( ret )
>                  dprintk(XENLOG_ERR VTDPREFIX, "d%d: RMRR mapping
> failed\n",
>                          pdev->domain->domain_id);
>          }
>      }
> 
> -    return ret;
> +    return 0;
>  }
> 
>  static int intel_iommu_enable_device(struct pci_dev *pdev)
> @@ -1949,52 +1936,12 @@ static int intel_iommu_remove_device(u8
> 
>      for_each_rmrr_device ( rmrr, bdf, i )
>      {
> -        struct hvm_iommu *hd;
> -        struct mapped_rmrr *mrmrr, *tmp;
> -
>          if ( rmrr->segment != pdev->seg ||
>               PCI_BUS(bdf) != pdev->bus ||
>               PCI_DEVFN2(bdf) != devfn )
>              continue;
> 
> -        /*
> -         * If the device belongs to the hardware domain, and it has RMRR,
> don't
> -         * remove it from the hardware domain, because BIOS may use
> RMRR at
> -         * booting time.
> -         */
> -        if ( is_hardware_domain(pdev->domain) )
> -            return 0;
> -
> -        hd = domain_hvm_iommu(pdev->domain);
> -
> -        /*
> -         * No need to acquire hd->mapping_lock: Both insertion and
> removal
> -         * get done while holding pcidevs_lock.
> -         */
> -        ASSERT(spin_is_locked(&pcidevs_lock));
> -        list_for_each_entry_safe ( mrmrr, tmp, &hd->arch.mapped_rmrrs,
> list )
> -        {
> -            unsigned long base_pfn, end_pfn;
> -
> -            if ( rmrr->base_address != mrmrr->base ||
> -                 rmrr->end_address != mrmrr->end )
> -                continue;
> -
> -            if ( --mrmrr->count )
> -                break;
> -
> -            base_pfn = (mrmrr->base & PAGE_MASK_4K) >>
> PAGE_SHIFT_4K;
> -            end_pfn = PAGE_ALIGN_4K(mrmrr->end) >> PAGE_SHIFT_4K;
> -            while ( base_pfn < end_pfn )
> -            {
> -                if ( intel_iommu_unmap_page(pdev->domain, base_pfn) )
> -                    return -ENXIO;
> -                base_pfn++;
> -            }
> -
> -            list_del(&mrmrr->list);
> -            xfree(mrmrr);
> -        }
> +        rmrr_identity_mapping(pdev->domain, 0, rmrr);
>      }
> 
>      return domain_context_unmap(pdev->domain, devfn, pdev);
> @@ -2152,7 +2099,7 @@ static void __hwdom_init setup_hwdom_rmr
>      spin_lock(&pcidevs_lock);
>      for_each_rmrr_device ( rmrr, bdf, i )
>      {
> -        ret = rmrr_identity_mapping(d, rmrr);
> +        ret = rmrr_identity_mapping(d, 1, rmrr);
>          if ( ret )
>              dprintk(XENLOG_ERR VTDPREFIX,
>                       "IOMMU: mapping reserved region failed\n");
> @@ -2262,6 +2209,62 @@ int __init intel_vtd_setup(void)
>      return ret;
>  }
> 
> +static int reassign_device_ownership(
> +    struct domain *source,
> +    struct domain *target,
> +    u8 devfn, struct pci_dev *pdev)
> +{
> +    int ret;
> +
> +    /*
> +     * Devices assigned to untrusted domains (here assumed to be any
> domU)
> +     * can attempt to send arbitrary LAPIC/MSI messages. We are
> unprotected
> +     * by the root complex unless interrupt remapping is enabled.
> +     */
> +    if ( (target != hardware_domain) && !iommu_intremap )
> +        untrusted_msi = 1;
> +
> +    /*
> +     * If the device belongs to the hardware domain, and it has RMRR, don't
> +     * remove it from the hardware domain, because BIOS may use RMRR
> at
> +     * booting time. Also account for the special casing of USB below (in
> +     * intel_iommu_assign_device()).
> +     */
> +    if ( !is_hardware_domain(source) &&
> +         !is_usb_device(pdev->seg, pdev->bus, pdev->devfn) )
> +    {
> +        const struct acpi_rmrr_unit *rmrr;
> +        u16 bdf;
> +        unsigned int i;
> +
> +        for_each_rmrr_device( rmrr, bdf, i )
> +            if ( rmrr->segment == pdev->seg &&
> +                 PCI_BUS(bdf) == pdev->bus &&
> +                 PCI_DEVFN2(bdf) == devfn )
> +            {
> +                ret = rmrr_identity_mapping(source, 0, rmrr);
> +                if ( ret != -ENOENT )
> +                    return ret;
> +            }
> +    }
> +
> +    ret = domain_context_unmap(source, devfn, pdev);
> +    if ( ret )
> +        return ret;
> +
> +    ret = domain_context_mapping(target, devfn, pdev);
> +    if ( ret )
> +        return ret;
> +
> +    if ( devfn == pdev->devfn )
> +    {
> +        list_move(&pdev->domain_list, &target->arch.pdev_list);
> +        pdev->domain = target;
> +    }
> +
> +    return ret;
> +}
> +
>  static int intel_iommu_assign_device(
>      struct domain *d, u8 devfn, struct pci_dev *pdev)
>  {
> @@ -2275,7 +2278,7 @@ static int intel_iommu_assign_device(
> 
>      ret = reassign_device_ownership(hardware_domain, d, devfn, pdev);
>      if ( ret )
> -        goto done;
> +        return ret;
> 
>      /* FIXME: Because USB RMRR conflicts with guest bios region,
>       * ignore USB RMRR temporarily.
> @@ -2283,10 +2286,7 @@ static int intel_iommu_assign_device(
>      seg = pdev->seg;
>      bus = pdev->bus;
>      if ( is_usb_device(seg, bus, pdev->devfn) )
> -    {
> -        ret = 0;
> -        goto done;
> -    }
> +        return 0;
> 
>      /* Setup rmrr identity mapping */
>      for_each_rmrr_device( rmrr, bdf, i )
> @@ -2295,17 +2295,19 @@ static int intel_iommu_assign_device(
>               PCI_BUS(bdf) == bus &&
>               PCI_DEVFN2(bdf) == devfn )
>          {
> -            ret = rmrr_identity_mapping(d, rmrr);
> +            ret = rmrr_identity_mapping(d, 1, rmrr);
>              if ( ret )
>              {
> -                dprintk(XENLOG_ERR VTDPREFIX,
> -                        "IOMMU: mapping reserved region failed\n");
> -                goto done;
> +                reassign_device_ownership(d, hardware_domain, devfn,
> pdev);
> +                printk(XENLOG_G_ERR VTDPREFIX
> +                       " cannot map reserved region
> (%"PRIx64",%"PRIx64"] for Dom%d (%d)\n",
> +                       rmrr->base_address, rmrr->end_address,
> +                       d->domain_id, ret);
> +                break;
>              }
>          }
>      }
> 
> -done:
>      return ret;
>  }
> 
> 


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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