On Mon, 2008-07-07 at 13:08 +0300, Avi Kivity wrote: > Amit Shah wrote: > > This will be useful for acking irqs of assigned devices > > > > > > And also for improving time drift tracking. > > Please make this more generic by having a list of callbacks. There > could also be just one list, rather than one for the ioapic and one for > the pic as implemented now. > > It may also make sense to filter the irq number before calling the > callback rather than relying on the callback to ignore uninteresting irqs. > Avi, Did you mean something like the patch below? How should we protect list accesses, should it be a new lock or an existing one? Regards, Ben >From 102013bdd75e8141027e461ae5834138f561a3c3 Mon Sep 17 00:00:00 2001 From: Ben-Ami Yassour <benami@xxxxxxxxxx> Date: Tue, 8 Jul 2008 13:30:01 +0300 Subject: [PATCH] KVM: interrupt ack notifier list API to get notification when a guest acks an interrupt. Signed-off-by: Ben-Ami Yassour <benami@xxxxxxxxxx> --- arch/x86/kvm/i8259.c | 4 ++- arch/x86/kvm/irq.c | 2 +- arch/x86/kvm/irq.h | 2 +- arch/x86/kvm/x86.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/kvm_host.h | 10 +++++ 5 files changed, 99 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 5857f59..9160343 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -151,9 +151,10 @@ static inline void pic_intack(struct kvm_kpic_state *s, int irq) s->irr &= ~(1 << irq); } -int kvm_pic_read_irq(struct kvm_pic *s) +int kvm_pic_read_irq(struct kvm *kvm) { int irq, irq2, intno; + struct kvm_pic *s = pic_irqchip(kvm); irq = pic_get_irq(&s->pics[0]); if (irq >= 0) { @@ -178,6 +179,7 @@ int kvm_pic_read_irq(struct kvm_pic *s) irq = 7; intno = s->pics[0].irq_base + irq; } + notify_interrupt_ack(kvm, irq); pic_update_irq(s); return intno; diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index 76d736b..cf29c02 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -72,7 +72,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v) if (kvm_apic_accept_pic_intr(v)) { s = pic_irqchip(v->kvm); s->output = 0; /* PIC */ - vector = kvm_pic_read_irq(s); + vector = kvm_pic_read_irq(v->kvm); } } return vector; diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 2a15be2..7657654 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -65,7 +65,7 @@ struct kvm_pic { struct kvm_pic *kvm_create_pic(struct kvm *kvm); void kvm_pic_set_irq(void *opaque, int irq, int level); -int kvm_pic_read_irq(struct kvm_pic *s); +int kvm_pic_read_irq(struct kvm *kvm); void kvm_pic_update_irq(struct kvm_pic *s); static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5a83c3b..6d33f00 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -199,6 +199,88 @@ static void __queue_exception(struct kvm_vcpu *vcpu) vcpu->arch.exception.error_code); } +void notify_interrupt_ack(struct kvm *kvm, int irq) +{ + struct list_head *ptr; + struct interrupt_ack_notifier *notifier; + + list_for_each(ptr, &kvm->arch.interrupt_ack_notifier) { + notifier = list_entry(ptr, struct interrupt_ack_notifier, list); + if (irq == notifier->irq) + notifier->callback(notifier->opaque, irq); + } +} + +static int +register_interrupt_ack_notifier(struct kvm *kvm, + int irq, + void (*callback)(void *opaque, int irq), + void *opaque) +{ + struct interrupt_ack_notifier *notifier; + + notifier = kzalloc(sizeof(struct interrupt_ack_notifier), GFP_KERNEL); + if (notifier == NULL) { + printk(KERN_INFO "%s: Couldn't allocate memory\n", __func__); + return -ENOMEM; + } + + notifier->callback = callback; + notifier->opaque = opaque; + notifier->irq = irq; + list_add(¬ifier->list, &kvm->arch.interrupt_ack_notifier); + + return 0; +} + +static struct interrupt_ack_notifier * +find_interrupt_ack_notifier(struct kvm *kvm, + int irq, + void (*callback)(void *opaque, int irq), + void *opaque) +{ + struct list_head *ptr; + struct interrupt_ack_notifier *notifier; + + list_for_each(ptr, &kvm->arch.interrupt_ack_notifier) { + notifier = list_entry(ptr, struct interrupt_ack_notifier, list); + if ((irq == notifier->irq) && + (callback == notifier->callback) && + (opaque == notifier->opaque)) { + return notifier; + } + } + return NULL; +} + +static void +unregister_interrupt_ack_notifier(struct kvm *kvm, + int irq, + void (*callback)(void *opaque, int irq), + void *opaque) +{ + struct interrupt_ack_notifier *notifier; + + notifier = find_interrupt_ack_notifier(kvm, irq, callback, opaque); + if (notifier) { + list_del(¬ifier->list); + kfree(notifier); + } +} + +static void free_interrupt_ack_notifier_list(struct kvm *kvm) +{ + struct list_head *ptr, *ptr2; + struct interrupt_ack_notifier *notifier; + + list_for_each_safe(ptr, ptr2, &kvm->arch.interrupt_ack_notifier) { + notifier = list_entry(ptr, + struct interrupt_ack_notifier, list); + list_del(¬ifier->list); + kfree(notifier); + } +} + /* * Load the pae pdptrs. Return true is they are all valid. */ @@ -3946,6 +4028,7 @@ struct kvm *kvm_arch_create_vm(void) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&kvm->arch.active_mmu_pages); + INIT_LIST_HEAD(&kvm->arch.interrupt_ack_notifier); return kvm; } @@ -3981,6 +4064,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_free_pit(kvm); kfree(kvm->arch.vpic); kfree(kvm->arch.vioapic); + free_interrupt_ack_notifier_list(kvm); kvm_free_vcpus(kvm); kvm_free_physmem(kvm); if (kvm->arch.apic_access_page) diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index 9391e57..fe35b15 100644 --- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h @@ -302,6 +302,13 @@ struct kvm_vcpu_arch { u64 mtrr[0x100]; }; +struct interrupt_ack_notifier { + struct list_head list; + int irq; + void (*callback)(void *opaque, int irq); + void *opaque; +}; + struct kvm_mem_alias { gfn_t base_gfn; unsigned long npages; @@ -339,6 +346,7 @@ struct kvm_arch{ struct dmar_domain *intel_iommu_domain; struct kvm_pic *vpic; struct kvm_ioapic *vioapic; + struct list_head interrupt_ack_notifier; struct kvm_pit *vpit; int round_robin_prev_vcpu; @@ -582,6 +590,8 @@ void kvm_enable_tdp(void); int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); int complete_pio(struct kvm_vcpu *vcpu); +void notify_interrupt_ack(struct kvm *kvm, int irq); + static inline struct kvm_mmu_page *page_header(hpa_t shadow_page) { struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT); -- 1.5.5.1 _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/virtualization