Weidong,

There seems to be line wrapping issues with the patch.
Please resend it.

Thanks,
Ben

On Thu, 2008-07-03 at 17:05 +0800, Han, Weidong wrote:
> Multiple devices may under different IOMMUs, so one dmar_domain cannot
> cover this. This patch abstracts a structure kvm_vtd_domain, which let
> devices under the same IOMMU share the same dmar_domain. Then use a
> kvm_vtd_domain list to contain the all assigned devices. 
> 
> This patch is on top of vtd branch of amit's tree. I will rebase it if
> VT-d patches sent by Ben are merged into KVM main tree.
> 
> Signed-off-by: Weidong Han <[EMAIL PROTECTED]>
> ---
>  arch/x86/kvm/vtd.c         |  260
> +++++++++++++++++++++++++++++---------------
>  arch/x86/kvm/x86.c         |    4 +-
>  include/asm-x86/kvm_host.h |   14 ++-
>  3 files changed, 185 insertions(+), 93 deletions(-)
> 
> diff --git a/arch/x86/kvm/vtd.c b/arch/x86/kvm/vtd.c
> index 4387c25..2365509 100644
> --- a/arch/x86/kvm/vtd.c
> +++ b/arch/x86/kvm/vtd.c
> @@ -26,29 +26,32 @@
>  #include <linux/intel-iommu.h>
>  #include "vtd.h"
>  
> -int kvm_iommu_map_pages(struct kvm *kvm,
> -     gfn_t base_gfn, unsigned long npages)
> +DEFINE_SPINLOCK(kvm_vtd_domain_lock);
> +
> +static int kvm_iommu_map_domain_pages(struct kvm *kvm,
> +                                   struct dmar_domain *domain,
> +                                   gfn_t base_gfn, unsigned long
> npages)
>  {
>       gfn_t gfn = base_gfn;
>       pfn_t pfn;
>       struct page *page;
>       int i, rc;
>  
> -     if (!kvm->arch.intel_iommu_domain)
> +     if (!domain)
>               return -EFAULT;
>  
> -     printk(KERN_DEBUG "kvm_iommu_map_page: gpa = %lx\n",
> +     printk(KERN_DEBUG "kvm_iommu_map_domain_page: gpa = %lx\n",
>               gfn << PAGE_SHIFT);
> -     printk(KERN_DEBUG "kvm_iommu_map_page: hpa = %lx\n",
> +     printk(KERN_DEBUG "kvm_iommu_map_domain_page: hpa = %lx\n",
>               gfn_to_pfn(kvm, base_gfn) << PAGE_SHIFT);
> -     printk(KERN_DEBUG "kvm_iommu_map_page: size = %lx\n",
> +     printk(KERN_DEBUG "kvm_iommu_map_domain_page: size = %lx\n",
>               npages*PAGE_SIZE);
>  
>       for (i = 0; i < npages; i++) {
>               pfn = gfn_to_pfn(kvm, gfn);
>               if (pfn_valid(pfn)) {
>                       rc = kvm_intel_iommu_page_mapping(
> -                             kvm->arch.intel_iommu_domain,
> +                             domain,
>                               gfn << PAGE_SHIFT, pfn << PAGE_SHIFT,
>                               PAGE_SIZE, DMA_PTE_READ |
> DMA_PTE_WRITE);
>                       if (rc) {
> @@ -64,25 +67,146 @@ int kvm_iommu_map_pages(struct kvm *kvm,
>       }
>       return 0;
>  }
> +
> +int kvm_iommu_map_pages(struct kvm *kvm,
> +                     gfn_t base_gfn, unsigned long npages)
> +{
> +     struct kvm_vtd_domain *vtd_dom = NULL;
> +
> +     list_for_each_entry(vtd_dom, &kvm->arch.vtd_domains, list)
> +             kvm_iommu_map_domain_pages(kvm, vtd_dom->domain,
> +                                        base_gfn, npages);
> +
> +     return 0;
> +}
>  EXPORT_SYMBOL_GPL(kvm_iommu_map_pages);
>  
> -static int kvm_iommu_map_memslots(struct kvm *kvm)
> +static int kvm_iommu_put_domain_pages(struct kvm *kvm,
> +                                   struct dmar_domain *domain,
> +                                   gfn_t base_gfn, unsigned long
> npages)
> +{
> +     gfn_t gfn = base_gfn;
> +     struct page *page;
> +     int i;
> +
> +     if (!domain)
> +             return -EFAULT;
> +
> +     printk(KERN_DEBUG "kvm_iommu_put_domain_pages: gpa = %lx\n",
> +             gfn << PAGE_SHIFT);
> +     printk(KERN_DEBUG "kvm_iommu_put_domain_pages: hpa = %lx\n",
> +             gfn_to_pfn(kvm, gfn) << PAGE_SHIFT);
> +     printk(KERN_DEBUG "kvm_iommu_put_domain_pages: size = %lx\n",
> +             npages*PAGE_SIZE);
> +
> +     for (i = 0; i < npages; i++) {
> +             page = gfn_to_page(kvm, gfn);
> +             put_page(page);
> +             gfn++;
> +     }
> +     return 0;
> +}
> +
> +int kvm_iommu_put_pages(struct kvm *kvm,
> +                     gfn_t base_gfn, unsigned long npages)
> +{
> +     struct kvm_vtd_domain *vtd_dom = NULL;
> +
> +     list_for_each_entry(vtd_dom, &kvm->arch.vtd_domains, list)
> +             kvm_iommu_put_domain_pages(kvm, vtd_dom->domain,
> +                                        base_gfn, npages);
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL_GPL(kvm_iommu_put_pages);
> +
> +static int kvm_iommu_map_domain_memslots(struct kvm *kvm,
> +                                      struct dmar_domain *domain)
>  {
>       int i, rc;
>       for (i = 0; i < kvm->nmemslots; i++) {
> -             rc = kvm_iommu_map_pages(kvm, kvm->memslots[i].base_gfn,
> -                             kvm->memslots[i].npages);
> +             rc = kvm_iommu_map_domain_pages(kvm, domain,
> +                      kvm->memslots[i].base_gfn,
> kvm->memslots[i].npages);
>               if (rc)
>                       return rc;
>       }
>       return 0;
>  }
>  
> -static int kvm_iommu_unmap_memslots(struct kvm *kvm);
> +static int kvm_iommu_unmap_domain_memslots(struct kvm *kvm,
> +                                        struct dmar_domain *domain)
> +{
> +     int i, rc;
> +     for (i = 0; i < kvm->nmemslots; i++) {
> +             rc = kvm_iommu_put_domain_pages(kvm, domain,
> +                     kvm->memslots[i].base_gfn,
> kvm->memslots[i].npages);
> +             if (rc)
> +                     return rc;
> +     }
> +     return 0;
> +}
> +
> +static struct kvm_vtd_domain *find_kvm_vtd_domain(struct kvm *kvm,
> +                                               struct pci_dev *pdev)
> +{
> +     struct kvm_vtd_domain *vtd_dom;
> +     struct kvm_vtd_pt_dev_list *vtd_dev;
> +
> +     list_for_each_entry(vtd_dom, &kvm->arch.vtd_domains, list) {
> +             list_for_each_entry(vtd_dev, &vtd_dom->pci_pt_devices,
> list) {
> +                     if (vtd_dev->dev_info.busnr == pdev->bus->number
> &&
> +                         vtd_dev->dev_info.devfn == pdev->devfn)
> +                             return vtd_dom;
> +             }
> +     }
> +
> +     return NULL;
> +}
> +
> +static struct kvm_vtd_domain *get_kvm_vtd_domain(struct kvm *kvm,
> +                                              struct pci_dev *pdev)
> +{
> +     struct kvm_vtd_domain *vtd_dom;
> +
> +     vtd_dom = find_kvm_vtd_domain(kvm, pdev);
> +     if (!vtd_dom) {
> +             vtd_dom = kzalloc(sizeof(struct kvm_vtd_domain),
> GFP_KERNEL);
> +             if (!vtd_dom)
> +                     return NULL;
> +
> +             INIT_LIST_HEAD(&vtd_dom->pci_pt_devices);
> +             if (!vtd_dom->domain) {
> +                     vtd_dom->domain =
> kvm_intel_iommu_domain_alloc(pdev);
> +                     if (!vtd_dom->domain) {
> +                             kfree(vtd_dom);
> +                             return NULL;
> +                     }
> +
> +                     if (kvm_iommu_map_domain_memslots(kvm,
> +                                               vtd_dom->domain)) {
> +                             kvm_iommu_unmap_domain_memslots(kvm,
> +                                     vtd_dom->domain);
> +
> kvm_intel_iommu_domain_exit(vtd_dom->domain);
> +                             kfree(vtd_dom);
> +                             return NULL;
> +                     }
> +             }
> +
> +             spin_lock(&kvm_vtd_domain_lock);
> +             list_add(&vtd_dom->list, &kvm->arch.vtd_domains);
> +             spin_unlock(&kvm_vtd_domain_lock);
> +     }
> +
> +     return vtd_dom;
> +}
> +
>  int kvm_iommu_map_guest(struct kvm *kvm,
> -     struct kvm_pci_passthrough_dev *pci_pt_dev)
> +                     struct kvm_pci_passthrough_dev *pci_pt_dev)
>  {
>       struct pci_dev *pdev = NULL;
> +     struct kvm_vtd_domain *vtd_dom = NULL;
> +     struct kvm_vtd_pt_dev_list *vtd_dev = NULL;
> +
>  
>       printk(KERN_DEBUG "kvm_iommu_map_guest: host bdf = %x:%x:%x\n",
>               pci_pt_dev->host.busnr,
> @@ -94,104 +218,62 @@ int kvm_iommu_map_guest(struct kvm *kvm,
>                       (pdev->devfn == pci_pt_dev->host.devfn))
>                       goto found;
>       }
> -     if (kvm->arch.intel_iommu_domain) {
> -
> kvm_intel_iommu_domain_exit(kvm->arch.intel_iommu_domain);
> -             kvm->arch.intel_iommu_domain = NULL;
> -     }
>       return -ENODEV;
>  found:
> -     kvm->arch.intel_iommu_domain =
> kvm_intel_iommu_domain_alloc(pdev);
> -     if (kvm->arch.intel_iommu_domain == NULL)
> -             printk(KERN_ERR "kvm_iommu_map_guest: domain ==
> NULL\n");
> -     else
> -             printk("kvm_iommu_map_guest: domain = %p\n",
> -                    kvm->arch.intel_iommu_domain);
> -
> -     if (kvm_iommu_map_memslots(kvm)) {
> -             kvm_iommu_unmap_memslots(kvm);
> +     vtd_dom = get_kvm_vtd_domain(kvm, pdev);
> +     if (!vtd_dom)
>               return -EFAULT;
> -     }
>  
> -     if (kvm_intel_iommu_context_mapping(
> -             kvm->arch.intel_iommu_domain, pdev)) {
> -             printk(KERN_ERR "Domain context map for %s failed",
> -                    pci_name(pdev));
> -             return -EFAULT;
> -     }
> -     return 0;
> -}
> -EXPORT_SYMBOL_GPL(kvm_iommu_map_guest);
> +     vtd_dev = kzalloc(sizeof(struct kvm_vtd_pt_dev_list),
> GFP_KERNEL);
> +     if (!vtd_dev)
> +             return -ENOMEM;
> +     vtd_dev->dev_info.busnr = pdev->bus->number;
> +     vtd_dev->dev_info.devfn = pdev->devfn;
>  
> -static int kvm_iommu_put_pages(struct kvm *kvm,
> -     gfn_t base_gfn, unsigned long npages)
> -{
> -     gfn_t gfn = base_gfn;
> -     struct page *page;
> -     int i;
> +     spin_lock(&kvm_vtd_domain_lock);
> +     list_add(&vtd_dev->list, &vtd_dom->pci_pt_devices);
> +     spin_unlock(&kvm_vtd_domain_lock);
>  
> -     if (!kvm->arch.intel_iommu_domain)
> +     /* detach device, because it may be used by host */
> +     kvm_intel_iommu_detach_dev(vtd_dom->domain,
> +                                pdev->bus->number, pdev->devfn);
> +     if (kvm_intel_iommu_context_mapping(vtd_dom->domain, pdev)) {
> +             printk(KERN_ERR "Domain context map for %s failed",
> +                    pci_name(pdev));
>               return -EFAULT;
> -
> -     printk(KERN_DEBUG "kvm_iommu_put_pages: gpa = %lx\n",
> -             gfn << PAGE_SHIFT);
> -     printk(KERN_DEBUG "kvm_iommu_put_pages: hpa = %lx\n",
> -             gfn_to_pfn(kvm, gfn) << PAGE_SHIFT);
> -     printk(KERN_DEBUG "kvm_iommu_put_pages: size = %lx\n",
> -             npages*PAGE_SIZE);
> -
> -     for (i = 0; i < npages; i++) {
> -             page = gfn_to_page(kvm, gfn);
> -             put_page(page);
> -             gfn++;
>       }
> -     return 0;
> -}
>  
> -static int kvm_iommu_unmap_memslots(struct kvm *kvm)
> -{
> -     int i, rc;
> -     for (i = 0; i < kvm->nmemslots; i++) {
> -             rc = kvm_iommu_put_pages(kvm, kvm->memslots[i].base_gfn,
> -                             kvm->memslots[i].npages);
> -             if (rc)
> -                     return rc;
> -     }
>       return 0;
>  }
> +EXPORT_SYMBOL_GPL(kvm_iommu_map_guest);
>  
>  int kvm_iommu_unmap_guest(struct kvm *kvm)
>  {
> -     struct kvm_pci_pt_dev_list *entry;
> -     struct pci_dev *pdev = NULL;
> +     struct kvm_vtd_domain *vtd_dom;
> +     struct kvm_vtd_pt_dev_list *vtd_dev;
> +     struct list_head *pdev1, *pdev2;
>  
> -     if (!kvm->arch.intel_iommu_domain)
> +     if (list_empty(&kvm->arch.vtd_domains))
>               return 0;
>  
> -     list_for_each_entry(entry, &kvm->arch.pci_pt_dev_head, list) {
> -             printk(KERN_DEBUG "kvm_iommu_unmap_guest: %x:%x:%x\n",
> -                     entry->pt_dev.host.busnr,
> -                     PCI_SLOT(entry->pt_dev.host.devfn),
> -                     PCI_FUNC(entry->pt_dev.host.devfn));
> +     spin_lock(&kvm_vtd_domain_lock);
>  
> -             for_each_pci_dev(pdev) {
> -                     if ((pdev->bus->number ==
> entry->pt_dev.host.busnr) &&
> -                             (pdev->devfn ==
> entry->pt_dev.host.devfn))
> -                             goto found;
> -             }
> -             return -ENODEV;
> -found:
> -             if (pdev == NULL) {
> -                     printk("kvm_iommu_unmap_guest: pdev == NULL\n");
> -                     return -EFAULT;
> +     list_for_each_entry(vtd_dom, &kvm->arch.vtd_domains, list) {
> +             list_for_each_safe(pdev1, pdev2,
> &vtd_dom->pci_pt_devices) {
> +                     vtd_dev = list_entry(pdev1,
> +                             struct kvm_vtd_pt_dev_list, list);
> +                     kvm_intel_iommu_detach_dev(vtd_dom->domain,
> +                             vtd_dev->dev_info.busnr,
> +                             vtd_dev->dev_info.devfn);
> +                     list_del(&vtd_dev->list);
> +                     kfree(vtd_dev);
>               }
>  
> -             /* detach kvm dmar domain */
> -             kvm_intel_iommu_detach_dev(
> -                             kvm->arch.intel_iommu_domain,
> -                             pdev->bus->number, pdev->devfn);
> +             kvm_iommu_unmap_domain_memslots(kvm, vtd_dom->domain);
> +             kvm_intel_iommu_domain_exit(vtd_dom->domain);
>       }
> -     kvm_iommu_unmap_memslots(kvm);
> -     kvm_intel_iommu_domain_exit(kvm->arch.intel_iommu_domain);
> +
> +     spin_unlock(&kvm_vtd_domain_lock);
>       return 0;
>  }
>  EXPORT_SYMBOL_GPL(kvm_iommu_unmap_guest);
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 37e3a66..1bc41d9 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -386,9 +386,6 @@ static void kvm_free_pci_passthrough(struct kvm
> *kvm)
>               kfree(pci_pt_dev);
>       }
>       write_unlock_irqrestore(&kvm_pci_pt_lock, flags);
> -
> -     if (kvm_intel_iommu_found())
> -             kvm->arch.intel_iommu_domain = NULL;
>  }
>  
>  unsigned long segment_base(u16 selector)
> @@ -4251,6 +4248,7 @@ struct  kvm *kvm_arch_create_vm(void)
>  
>       INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
>       INIT_LIST_HEAD(&kvm->arch.pci_pt_dev_head);
> +     INIT_LIST_HEAD(&kvm->arch.vtd_domains);
>  
>       return kvm;
>  }
> diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
> index a2f1e3e..00b43a3 100644
> --- a/include/asm-x86/kvm_host.h
> +++ b/include/asm-x86/kvm_host.h
> @@ -343,6 +343,18 @@ struct kvm_pci_pt_dev_list {
>       struct kvm_pci_passthrough_dev_kernel pt_dev;
>  };
>  
> +struct kvm_vtd_pt_dev_list {
> +     struct list_head list;
> +     struct kvm_pci_pt_info dev_info;
> +};
> +
> +/* devices under the same iommu uses the same dmar_domain */
> +struct kvm_vtd_domain {
> +     struct list_head list;
> +     struct list_head pci_pt_devices; /* assigned devices */
> +     struct dmar_domain *domain;      /* pointer to domain */
> +};
> +
>  struct kvm_arch{
>       int naliases;
>       struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
> @@ -356,7 +368,7 @@ struct kvm_arch{
>        */
>       struct list_head active_mmu_pages;
>       struct list_head pci_pt_dev_head;
> -     struct dmar_domain *intel_iommu_domain;
> +     struct list_head vtd_domains;
>       struct kvm_pic *vpic;
>       struct kvm_ioapic *vioapic;
>       struct kvm_pit *vpit;

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to