Ben,

Thanks for your reminder. I attach the patch. 

Randy (Weidong)

Ben-Ami Yassour wrote:
> 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;

Attachment: multi-assign.patch
Description: multi-assign.patch

Reply via email to