[Use the new kvm list address]

On Thursday 22 May 2008 18:22:43 Ben-Ami Yassour wrote:
> Amit,
>
> Attached is a fix for pvdma interrupt injection, and it seems to work fine
> with an e1000 NIC.

The interrupt injection is generic for pci-passthrough and not just for pvdma 
(it'll work the same for vt-d as well).

> From d4c3326ae55f9b474673e5308394182551bb4fee Mon Sep 17 00:00:00 2001
> From: Ben-Ami Yassour <[EMAIL PROTECTED]>
> Date: Thu, 22 May 2008 15:33:19 +0300
> Subject: [PATCH 16/16] KVM: PCI Passthrough: fix interrupt injection
>
> Signed-off-by: Ben-Ami Yassour <[EMAIL PROTECTED]>
> ---
>   arch/x86/kvm/x86.c         |   48
> +++++++++++++++++++++++++++---------------- include/asm-x86/kvm_host.h |   
> 7 +++++-
>   virt/kvm/ioapic.c          |   11 ++++++++-
>   3 files changed, 45 insertions(+), 21 deletions(-)
>
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index ac807a0..cee5be1 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -276,7 +276,7 @@ static int pv_unmap_hypercall(struct kvm_vcpu *vcpu,
> dma_addr_t dma) * Used to find a registered host PCI device (a
> "passthrough" device) * during hypercalls, ioctls or interrupts or EOI
>    */
> -static struct kvm_pci_pt_dev_list *
> +struct kvm_pci_pt_dev_list *
>   find_pci_pt_dev(struct list_head *head,
>               struct kvm_pci_pt_info *pt_pci_info, int irq, int source)
>   {
> @@ -348,7 +348,7 @@ static int pv_mapped_pci_device_hypercall(struct
> kvm_vcpu *vcpu, static DECLARE_BITMAP(pt_irq_pending, NR_IRQS);
>   static DECLARE_BITMAP(pt_irq_handled, NR_IRQS);
>
> -static void kvm_pci_pt_work_fn(struct work_struct *work)
> +static void kvm_pci_pt_intr_work_fn(struct work_struct *work)
>   {
>       struct kvm_pci_pt_dev_list *match;
>       struct kvm_pci_pt_work *int_work;
> @@ -359,18 +359,16 @@ static void kvm_pci_pt_work_fn(struct work_struct
> *work) source = int_work->source ? KVM_PT_SOURCE_IRQ_ACK :
> KVM_PT_SOURCE_IRQ; match =
> find_pci_pt_dev(&int_work->kvm->arch.pci_pt_dev_head, NULL, int_work->irq,
> source);
> -     if (!match)
> -             return;
>       mutex_lock(&int_work->kvm->lock);
>       if (source == KVM_PT_SOURCE_IRQ)
>               kvm_set_irq(int_work->kvm, match->pt_dev.guest.irq, 1);
>       else if (test_bit(match->pt_dev.host.irq, pt_irq_pending)) {
> -             kvm_set_irq(int_work->kvm, int_work->irq, 0);
> -             clear_bit(match->pt_dev.host.irq, pt_irq_pending);
> -             enable_irq(match->pt_dev.host.irq);
> -     } else
> -             goto out;
> +             kvm_set_irq(int_work->kvm, int_work->irq, 0);
> +             clear_bit(match->pt_dev.host.irq, pt_irq_pending);
> +             enable_irq(match->pt_dev.host.irq);
> +     } else
> +             goto out;

With this rework, the else should also call kvm_put_kvm. Avi also says the 
kvm_put_kvm should happen after the mutex_unlock.

>       /* We only put the reference to the kvm struct if we
>        * successfully found the assigned device and injected the
> @@ -387,6 +385,7 @@ out:
>   static irqreturn_t kvm_pci_pt_dev_intr(int irq, void *dev_id)
>   {
>       struct kvm *kvm = (struct kvm *) dev_id;
> +     struct kvm_pci_pt_dev_list *match;
>
>       if (!test_bit(irq, pt_irq_handled))
>               return IRQ_NONE;
> @@ -394,13 +393,18 @@ static irqreturn_t kvm_pci_pt_dev_intr(int irq, void
> *dev_id) if (test_bit(irq, pt_irq_pending))
>               return IRQ_HANDLED;
>
> +     match = find_pci_pt_dev(&kvm->arch.pci_pt_dev_head, NULL,
> +                             irq, KVM_PT_SOURCE_IRQ);
> +     if (!match)
> +             return IRQ_NONE;
> +
>       set_bit(irq, pt_irq_pending);
> -     kvm->arch.pci_pt_int_work.irq = irq;
> -     kvm->arch.pci_pt_int_work.kvm = kvm;
> -     kvm->arch.pci_pt_int_work.source = 0;
> +     kvm->arch.pci_pt_int_work_intr.irq = irq;
> +     kvm->arch.pci_pt_int_work_intr.kvm = kvm;
> +     kvm->arch.pci_pt_int_work_intr.source = 0;
>
>       kvm_get_kvm(kvm);
> -     schedule_work(&kvm->arch.pci_pt_int_work.work);
> +     schedule_work(&kvm->arch.pci_pt_int_work_intr.work);
>
>       disable_irq_nosync(irq);
>       return IRQ_HANDLED;
> @@ -410,15 +414,21 @@ static irqreturn_t kvm_pci_pt_dev_intr(int irq, void
> *dev_id) void kvm_pci_pt_ack_irq(struct kvm *kvm, int vector)
>   {
>       int irq;
> +     struct kvm_pci_pt_dev_list *match;
>
>       irq = kvm_get_eoi_gsi(kvm->arch.vioapic, vector);
>
> -     kvm->arch.pci_pt_int_work.irq = irq;
> -     kvm->arch.pci_pt_int_work.kvm = kvm;
> -     kvm->arch.pci_pt_int_work.source = 1;
> +     match = find_pci_pt_dev(&kvm->arch.pci_pt_dev_head, NULL,
> +                             irq, KVM_PT_SOURCE_IRQ_ACK);
> +     if (!match)
> +             return;
> +
> +     kvm->arch.pci_pt_int_work_ack.irq = irq;
> +     kvm->arch.pci_pt_int_work_ack.kvm = kvm;
> +     kvm->arch.pci_pt_int_work_ack.source = 1;
>
>       kvm_get_kvm(kvm);
> -     schedule_work(&kvm->arch.pci_pt_int_work.work);
> +     schedule_work(&kvm->arch.pci_pt_int_work_ack.work);
>   }
>
>   static int kvm_vm_ioctl_pci_pt_dev(struct kvm *kvm,
> @@ -4322,7 +4332,8 @@ 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.pci_pv_dmap_head);
> -     INIT_WORK(&kvm->arch.pci_pt_int_work.work, kvm_pci_pt_work_fn);
> +     INIT_WORK(&kvm->arch.pci_pt_int_work_intr.work, 
> kvm_pci_pt_intr_work_fn);
> +     INIT_WORK(&kvm->arch.pci_pt_int_work_ack.work, kvm_pci_pt_intr_work_fn);

They can be called pci_pt_int_work and pci_pt_ack_work.

>
>       return kvm;
>   }
> @@ -4449,3 +4460,4 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
>               smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
>       put_cpu();
>   }
> +

Extra whitespace

> diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
> index dc46287..ef11f48 100644
> --- a/include/asm-x86/kvm_host.h
> +++ b/include/asm-x86/kvm_host.h
> @@ -345,7 +345,8 @@ struct kvm_arch{
>       struct list_head active_mmu_pages;
>       struct list_head pci_pt_dev_head;
>       struct list_head pci_pv_dmap_head;
> -     struct kvm_pci_pt_work pci_pt_int_work;
> +     struct kvm_pci_pt_work pci_pt_int_work_intr;
> +     struct kvm_pci_pt_work pci_pt_int_work_ack;
>       struct kvm_pic *vpic;
>       struct kvm_ioapic *vioapic;
>       struct kvm_pit *vpit;
> @@ -593,6 +594,10 @@ void kvm_enable_tdp(void);
>   int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
>   int complete_pio(struct kvm_vcpu *vcpu);
>
> +struct kvm_pci_pt_dev_list *
> +find_pci_pt_dev(struct list_head *head,
> +             struct kvm_pci_pt_info *pt_pci_info, int irq, int source);
> +

This can go into include/asm-x86/kvm_host.h

>   static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
>   {
>       struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
> diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
> index 4c41a00..da041c0 100644
> --- a/virt/kvm/ioapic.c
> +++ b/virt/kvm/ioapic.c
> @@ -299,6 +299,7 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
>       struct kvm_ioapic *ioapic = kvm->arch.vioapic;
>       union ioapic_redir_entry *ent;
>       int gsi;
> +     struct kvm_pci_pt_dev_list *match;

This too can go into the header

>       gsi = kvm_get_eoi_gsi(ioapic, vector);
>       if (gsi == -1) {
> @@ -311,8 +312,14 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int
> vector) ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
>
>       ent->fields.remote_irr = 0;
> -     if (!ent->fields.mask && (ioapic->irr & (1 << gsi)))
> -             ioapic_deliver(ioapic, gsi);
> +
> +     match = find_pci_pt_dev(&kvm->arch.pci_pt_dev_head, NULL,
> +                             gsi, KVM_PT_SOURCE_IRQ_ACK);
> +
> +     if (!match) {
> +             if (!ent->fields.mask && (ioapic->irr & (1 << gsi)))
> +                     ioapic_deliver(ioapic, gsi);
> +     }

The problem with all this is we'll have to introduce a new spinlock for the 
pci_pt structures. We need to take this lock in all the various contexts we 
get called, which means we might have to worry about lock ordering.
--
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