Hi Sheng,

On Wed, Jan 07, 2009 at 06:42:37PM +0800, Sheng Yang wrote:
> Avi's purpose, to use single kvm_set_irq() to deal with all interrupt, 
> including
> MSI. So here is it.
> 
> struct gsi_route_entry is a mapping from a special gsi(with KVM_GSI_MSG_MASK) 
> to
> MSI/MSI-X message address/data. And the struct can also be extended for other
> purpose.
> 
> Now we support up to 256 gsi_route_entry mapping, and gsi is allocated by 
> kernel and
> provide two ioctls to userspace, which is more flexiable.
> 
> Signed-off-by: Sheng Yang <[email protected]>
> ---
>  include/linux/kvm.h      |   26 +++++++++++
>  include/linux/kvm_host.h |   20 +++++++++
>  virt/kvm/irq_comm.c      |   70 ++++++++++++++++++++++++++++++
>  virt/kvm/kvm_main.c      |  106 
> ++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 222 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/kvm.h b/include/linux/kvm.h
> index 71c150f..bbefce6 100644
> --- a/include/linux/kvm.h
> +++ b/include/linux/kvm.h
> @@ -399,6 +399,9 @@ struct kvm_trace_rec {
>  #if defined(CONFIG_X86)
>  #define KVM_CAP_REINJECT_CONTROL 24
>  #endif
> +#if defined(CONFIG_X86)
> +#define KVM_CAP_GSI_ROUTE 25
> +#endif
>  
>  /*
>   * ioctls for VM fds
> @@ -433,6 +436,8 @@ struct kvm_trace_rec {
>  #define KVM_ASSIGN_IRQ _IOR(KVMIO, 0x70, \
>                           struct kvm_assigned_irq)
>  #define KVM_REINJECT_CONTROL      _IO(KVMIO, 0x71)
> +#define KVM_REQUEST_GSI_ROUTE          _IOWR(KVMIO, 0x72, void *)
> +#define KVM_FREE_GSI_ROUTE     _IOR(KVMIO, 0x73, void *)
>  
>  /*
>   * ioctls for vcpu fds
> @@ -553,4 +558,25 @@ struct kvm_assigned_irq {
>  #define KVM_DEV_IRQ_ASSIGN_MSI_ACTION        KVM_DEV_IRQ_ASSIGN_ENABLE_MSI
>  #define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI        (1 << 0)
>  
> +struct kvm_gsi_route_guest {
> +     __u32 entries_nr;
> +     struct kvm_gsi_route_entry_guest *entries;
> +};
> +
> +#define KVM_GSI_ROUTE_MSI    (1 << 0)
> +struct kvm_gsi_route_entry_guest {
> +     __u32 gsi;
> +     __u32 type;
> +     __u32 flags;
> +     __u32 reserved;
> +     union {
> +             struct {
> +                     __u32 addr_lo;
> +                     __u32 addr_hi;
> +                     __u32 data;
> +             } msi;
> +             __u32 padding[8];
> +     };
> +};
> +
>  #endif
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index a8bcad0..6a00201 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -136,6 +136,9 @@ struct kvm {
>       unsigned long mmu_notifier_seq;
>       long mmu_notifier_count;
>  #endif
> +     struct hlist_head gsi_route_list;
> +#define KVM_NR_GSI_ROUTE_ENTRIES    256
> +     DECLARE_BITMAP(gsi_route_bitmap, KVM_NR_GSI_ROUTE_ENTRIES);
>  };
>  
>  /* The guest did something we don't support. */
> @@ -336,6 +339,19 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, 
> int irq,
>                                     struct kvm_irq_mask_notifier *kimn);
>  void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
>  
> +#define KVM_GSI_ROUTE_MASK    0x1000000ull
> +struct kvm_gsi_route_entry {
> +     u32 gsi;
> +     u32 type;
> +     u32 flags;
> +     u32 reserved;
> +     union {
> +             struct msi_msg msi;
> +             u32 reserved[8];
> +     };
> +     struct hlist_node link;
> +};
> +
>  void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
>  void kvm_notify_acked_irq(struct kvm *kvm, unsigned gsi);
>  void kvm_register_irq_ack_notifier(struct kvm *kvm,
> @@ -343,6 +359,10 @@ void kvm_register_irq_ack_notifier(struct kvm *kvm,
>  void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian);
>  int kvm_request_irq_source_id(struct kvm *kvm);
>  void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
> +int kvm_update_gsi_route(struct kvm *kvm, struct kvm_gsi_route_entry *entry);
> +struct kvm_gsi_route_entry *kvm_find_gsi_route_entry(struct kvm *kvm, u32 
> gsi);
> +void kvm_free_gsi_route(struct kvm *kvm, struct kvm_gsi_route_entry *entry);
> +void kvm_free_gsi_route_list(struct kvm *kvm);
>  
>  #ifdef CONFIG_DMAR
>  int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn,
> diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
> index 5162a41..7460e7f 100644
> --- a/virt/kvm/irq_comm.c
> +++ b/virt/kvm/irq_comm.c
> @@ -123,3 +123,73 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, 
> bool mask)
>                       kimn->func(kimn, mask);
>  }
>  
> +int kvm_update_gsi_route(struct kvm *kvm, struct kvm_gsi_route_entry *entry)
> +{
> +     struct kvm_gsi_route_entry *found_entry, *new_entry;
> +     int r, gsi;
> +
> +     mutex_lock(&kvm->lock);
> +     /* Find whether we need a update or a new entry */
> +     found_entry = kvm_find_gsi_route_entry(kvm, entry->gsi);
> +     if (found_entry)
> +             *found_entry = *entry;
> +     else {

Having a kvm_find_alloc_gsi_route_entry which either returns a present
entry if found or returns a newly allocated one makes the code easier to
read for me. Then just

                entry = kvm_find_alloc_gsi_route_entry
                *entry = *new_entry;

Just style, feel free to ignore the comment.

> +             gsi = find_first_zero_bit(kvm->gsi_route_bitmap,
> +                                       KVM_NR_GSI_ROUTE_ENTRIES);
> +             if (gsi >= KVM_NR_GSI_ROUTE_ENTRIES) {
> +                     r = -ENOSPC;
> +                     goto out;
> +             }
> +             __set_bit(gsi, kvm->gsi_route_bitmap);
> +             entry->gsi = gsi | KVM_GSI_ROUTE_MASK;
> +             new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);

Allocate first, then set the bit in the bitmap?

> +             if (!new_entry) {
> +                     r = -ENOMEM;
> +                     goto out;

Because here you don't clear the state on failure. 

</NITPICK MODE> 

> +             }
> +             *new_entry = *entry;
> +             hlist_add_head(&new_entry->link, &kvm->gsi_route_list);
> +     }
> +     r = 0;
> +out:
> +     mutex_unlock(&kvm->lock);
> +     return r;
> +}
> +
>  
> +static int kvm_vm_ioctl_request_gsi_route(struct kvm *kvm,
> +                     struct kvm_gsi_route_guest *gsi_route,
> +                     struct kvm_gsi_route_entry_guest *guest_entries)
> +{
> +     struct kvm_gsi_route_entry entry;
> +     int r, i;
> +
> +     for (i = 0; i < gsi_route->entries_nr; i++) {
> +             memcpy(&entry, &guest_entries[i], sizeof(entry));
> +             r = kvm_update_gsi_route(kvm, &entry);
> +             if (r == 0)
> +                     guest_entries[i].gsi = entry.gsi;
> +             else
> +                     break;
> +     }
> +     return r;
> +}
> +
> +static int kvm_vm_ioctl_free_gsi_route(struct kvm *kvm,
> +                     struct kvm_gsi_route_guest *gsi_route,
> +                     struct kvm_gsi_route_entry_guest *guest_entries)
> +{
> +     struct kvm_gsi_route_entry *entry;
> +     int r, i;
> +
> +     mutex_lock(&kvm->lock);
> +     for (i = 0; i < gsi_route->entries_nr; i++) {
> +             entry = kvm_find_gsi_route_entry(kvm, guest_entries[i].gsi);
> +             if (!entry ||
> +                 memcmp(entry, &guest_entries[i], sizeof(*entry)) != 0) {
> +                     printk(KERN_WARNING "kvm: illegal gsi mapping!");

Don't think you need that printk?

> +                     r = -EINVAL;
> +                     goto out;
> +             }
> +             kvm_free_gsi_route(kvm, entry);
> +     }
> +out:
> +     mutex_unlock(&kvm->lock);
> +     return r;
> +}
> +
>  static long kvm_vcpu_ioctl(struct file *filp,
>                          unsigned int ioctl, unsigned long arg)
>  {
> @@ -1803,6 +1846,7 @@ static long kvm_vm_ioctl(struct file *filp,
>  {
>       struct kvm *kvm = filp->private_data;
>       void __user *argp = (void __user *)arg;
> +     struct kvm_gsi_route_entry_guest *gsi_entries = NULL;
>       int r;
>  
>       if (kvm->mm != current->mm)
> @@ -1887,10 +1931,72 @@ static long kvm_vm_ioctl(struct file *filp,
>               break;
>       }
>  #endif
> +     case KVM_REQUEST_GSI_ROUTE: {
> +             struct kvm_gsi_route_guest gsi_route;

                r = -EFAULT;
                if (copy_from_user...)
                        goto out;

                etc...
    
To conform with the rest of the code in the function?

> +             r = copy_from_user(&gsi_route, argp, sizeof gsi_route);
> +             if (r)
> +                     goto out;
> +             if (gsi_route.entries_nr == 0) {
> +                     r = -EFAULT;
> +                     goto out;
> +             }

Should check for a max of KVM_NR_GSI_ROUTE_ENTRIES ?

> +             gsi_entries = kmalloc(gsi_route.entries_nr *
> +                                   sizeof(struct kvm_gsi_route_entry_guest),
> +                                   GFP_KERNEL);

And use vmalloc/vfree instead.

> +             if (!gsi_entries) {
> +                     r = -ENOMEM;
> +                     goto out;
> +             }
> +             r = copy_from_user(gsi_entries,
> +                                (void __user *)gsi_route.entries,
> +                                gsi_route.entries_nr *
> +                                sizeof(struct kvm_gsi_route_entry_guest));
> +             if (r)
> +                     goto out;
> +             r = kvm_vm_ioctl_request_gsi_route(kvm, &gsi_route,
> +                                                gsi_entries);
> +             if (r)
> +                     goto out;
> +             r = copy_to_user((void __user *)gsi_route.entries,
> +                             gsi_entries,
> +                             gsi_route.entries_nr *
> +                             sizeof(struct kvm_gsi_route_entry_guest));
> +             if (r)
> +                     goto out;
> +             break;
> +     }
> +     case KVM_FREE_GSI_ROUTE: {
> +             struct kvm_gsi_route_guest gsi_route;
> +             r = copy_from_user(&gsi_route, argp, sizeof gsi_route);
> +             if (r)
> +                     goto out;
> +             if (gsi_route.entries_nr == 0) {
> +                     r = -EFAULT;
> +                     goto out;
> +             }

Check KVM_NR_GSI_ROUTE_ENTRIES and vmalloc.

--
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