diff -r e8ebbe7635c5 xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Thu Nov 29 20:03:51 2007 +0100 +++ b/xen/arch/x86/domain.c Fri Nov 30 12:04:37 2007 +0100 @@ -46,6 +46,7 @@ #include #include #include +#include #ifdef CONFIG_COMPAT #include #endif @@ -518,11 +519,15 @@ int arch_domain_create(struct domain *d) if ( (rc = iommu_domain_init(d)) != 0 ) goto fail; + if ( (rc = amd_iommu_domain_init(d)) != 0 ) + goto fail; + if ( is_hvm_domain(d) ) { if ( (rc = hvm_domain_initialise(d)) != 0 ) { iommu_domain_destroy(d); + amd_iommu_domain_destroy(d); goto fail; } } @@ -555,6 +560,8 @@ void arch_domain_destroy(struct domain * hvm_domain_destroy(d); iommu_domain_destroy(d); + + amd_iommu_domain_destroy(d); paging_final_teardown(d); diff -r e8ebbe7635c5 xen/arch/x86/domctl.c --- a/xen/arch/x86/domctl.c Thu Nov 29 20:03:51 2007 +0100 +++ b/xen/arch/x86/domctl.c Fri Nov 30 12:04:37 2007 +0100 @@ -27,6 +27,7 @@ #include #include #include +#include long arch_do_domctl( struct xen_domctl *domctl, @@ -532,7 +533,7 @@ long arch_do_domctl( u8 bus, devfn; ret = -EINVAL; - if ( !vtd_enabled ) + if ( !vtd_enabled && !amd_iommu_enabled ) break; if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) ) @@ -548,7 +549,11 @@ long arch_do_domctl( if ( device_assigned(bus, devfn) ) break; - ret = assign_device(d, bus, devfn); + if ( vtd_enabled ) + ret = assign_device(d, bus, devfn); + else if ( amd_iommu_enabled ) + ret = amd_iommu_assign_device(d, bus, devfn); + gdprintk(XENLOG_INFO, "XEN_DOMCTL_assign_device: bdf = %x:%x:%x\n", bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); put_domain(d); @@ -564,7 +569,7 @@ long arch_do_domctl( if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; bind = &(domctl->u.bind_pt_irq); - if (vtd_enabled) + if ( vtd_enabled || amd_iommu_enabled ) ret = pt_irq_create_bind_vtd(d, bind); if (ret < 0) gdprintk(XENLOG_ERR, "pt_irq_create_bind failed!\n"); diff -r e8ebbe7635c5 xen/arch/x86/hvm/svm/intr.c --- a/xen/arch/x86/hvm/svm/intr.c Thu Nov 29 20:03:51 2007 +0100 +++ b/xen/arch/x86/hvm/svm/intr.c Fri Nov 30 12:04:37 2007 +0100 @@ -94,6 +94,46 @@ static void enable_intr_window(struct vc vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR; } +static void svm_dirq_assist(struct vcpu *v) +{ + unsigned int irq; + uint32_t device, intx; + struct domain *d = v->domain; + struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; + struct dev_intx_gsi_link *digl; + + if ( !amd_iommu_enabled || (v->vcpu_id != 0) || (hvm_irq_dpci == NULL) ) + return; + + for ( irq = find_first_bit(hvm_irq_dpci->dirq_mask, NR_IRQS); + irq < NR_IRQS; + irq = find_next_bit(hvm_irq_dpci->dirq_mask, NR_IRQS, irq + 1) ) + { + stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)]); + clear_bit(irq, &hvm_irq_dpci->dirq_mask); + + list_for_each_entry ( digl, &hvm_irq_dpci->mirq[irq].digl_list, list ) + { + device = digl->device; + intx = digl->intx; + hvm_pci_intx_assert(d, device, intx); + spin_lock(&hvm_irq_dpci->dirq_lock); + hvm_irq_dpci->mirq[irq].pending++; + spin_unlock(&hvm_irq_dpci->dirq_lock); + } + + /* + * Set a timer to see if the guest can finish the interrupt or not. For + * example, the guest OS may unmask the PIC during boot, before the + * guest driver is loaded. hvm_pci_intx_assert() may succeed, but the + * guest will never deal with the irq, then the physical interrupt line + * will never be deasserted. + */ + set_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)], + NOW() + PT_IRQ_TIME_OUT); + } +} + asmlinkage void svm_intr_assist(void) { struct vcpu *v = current; @@ -102,6 +142,7 @@ asmlinkage void svm_intr_assist(void) /* Crank the handle on interrupt state. */ pt_update_irq(v); + svm_dirq_assist(v); hvm_set_callback_irq_level(); do { diff -r e8ebbe7635c5 xen/arch/x86/hvm/vioapic.c --- a/xen/arch/x86/hvm/vioapic.c Thu Nov 29 20:03:51 2007 +0100 +++ b/xen/arch/x86/hvm/vioapic.c Fri Nov 30 12:04:37 2007 +0100 @@ -458,7 +458,7 @@ void vioapic_update_EOI(struct domain *d ent->fields.remote_irr = 0; - if ( vtd_enabled ) + if ( vtd_enabled || amd_iommu_enabled ) { spin_unlock(&d->arch.hvm_domain.irq_lock); hvm_dpci_eoi(current->domain, gsi, ent); diff -r e8ebbe7635c5 xen/arch/x86/hvm/vmx/vtd/io.c --- a/xen/arch/x86/hvm/vmx/vtd/io.c Thu Nov 29 20:03:51 2007 +0100 +++ b/xen/arch/x86/hvm/vmx/vtd/io.c Fri Nov 30 12:04:37 2007 +0100 @@ -141,7 +141,7 @@ int hvm_do_IRQ_dpci(struct domain *d, un { struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; - if ( !vtd_enabled || (d == dom0) || (hvm_irq->dpci == NULL) || + if ( (!vtd_enabled && !amd_iommu_enabled) || (d == dom0) || (hvm_irq->dpci == NULL) || !hvm_irq->dpci->mirq[mirq].valid ) return 0; @@ -167,7 +167,7 @@ static void hvm_dpci_isairq_eoi(struct d int i; ASSERT(isairq < NR_ISAIRQS); - if ( !vtd_enabled || !dpci || + if ( (!vtd_enabled && !amd_iommu_enabled) || !dpci || !test_bit(isairq, dpci->isairq_map) ) return; @@ -205,7 +205,7 @@ void hvm_dpci_eoi(struct domain *d, unsi struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; uint32_t device, intx, machine_gsi; - if ( !vtd_enabled || (hvm_irq_dpci == NULL) || + if ( (!vtd_enabled && !amd_iommu_enabled) || (hvm_irq_dpci == NULL) || (guest_gsi >= NR_ISAIRQS && !hvm_irq_dpci->girq[guest_gsi].valid) ) return; diff -r e8ebbe7635c5 xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Thu Nov 29 20:03:51 2007 +0100 +++ b/xen/arch/x86/mm/p2m.c Fri Nov 30 12:04:37 2007 +0100 @@ -28,6 +28,7 @@ #include #include #include +#include /* Debugging and auditing of the P2M code? */ #define P2M_AUDIT 0 @@ -257,6 +258,14 @@ set_p2m_entry(struct domain *d, unsigned if ( vtd_enabled && (p2mt == p2m_mmio_direct) && is_hvm_domain(d) ) iommu_flush(d, gfn, (u64*)p2m_entry); + + if ( amd_iommu_enabled && is_hvm_domain(d) && (p2mt != p2m_mmio_direct)) + { + if ( mfn_valid(mfn) ) + amd_iommu_map_page(d, gfn, mfn_x(mfn)); + else + amd_iommu_unmap_page(d, gfn); + } /* Success */ rv = 1;