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;
multi-assign.patch
Description: multi-assign.patch
