diff options
-rw-r--r-- | include/linux/kvm_host.h | 1 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 66 |
2 files changed, 60 insertions, 7 deletions
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 432edc27e82b..3832243625d4 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -319,6 +319,7 @@ struct kvm_irq_ack_notifier { | |||
319 | void (*irq_acked)(struct kvm_irq_ack_notifier *kian); | 319 | void (*irq_acked)(struct kvm_irq_ack_notifier *kian); |
320 | }; | 320 | }; |
321 | 321 | ||
322 | #define KVM_ASSIGNED_MSIX_PENDING 0x1 | ||
322 | struct kvm_guest_msix_entry { | 323 | struct kvm_guest_msix_entry { |
323 | u32 vector; | 324 | u32 vector; |
324 | u16 entry; | 325 | u16 entry; |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 1ceb96901f32..8bd44d6985c7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -95,25 +95,69 @@ static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *h | |||
95 | return NULL; | 95 | return NULL; |
96 | } | 96 | } |
97 | 97 | ||
98 | static int find_index_from_host_irq(struct kvm_assigned_dev_kernel | ||
99 | *assigned_dev, int irq) | ||
100 | { | ||
101 | int i, index; | ||
102 | struct msix_entry *host_msix_entries; | ||
103 | |||
104 | host_msix_entries = assigned_dev->host_msix_entries; | ||
105 | |||
106 | index = -1; | ||
107 | for (i = 0; i < assigned_dev->entries_nr; i++) | ||
108 | if (irq == host_msix_entries[i].vector) { | ||
109 | index = i; | ||
110 | break; | ||
111 | } | ||
112 | if (index < 0) { | ||
113 | printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n"); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | return index; | ||
118 | } | ||
119 | |||
98 | static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) | 120 | static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) |
99 | { | 121 | { |
100 | struct kvm_assigned_dev_kernel *assigned_dev; | 122 | struct kvm_assigned_dev_kernel *assigned_dev; |
123 | struct kvm *kvm; | ||
124 | int irq, i; | ||
101 | 125 | ||
102 | assigned_dev = container_of(work, struct kvm_assigned_dev_kernel, | 126 | assigned_dev = container_of(work, struct kvm_assigned_dev_kernel, |
103 | interrupt_work); | 127 | interrupt_work); |
128 | kvm = assigned_dev->kvm; | ||
104 | 129 | ||
105 | /* This is taken to safely inject irq inside the guest. When | 130 | /* This is taken to safely inject irq inside the guest. When |
106 | * the interrupt injection (or the ioapic code) uses a | 131 | * the interrupt injection (or the ioapic code) uses a |
107 | * finer-grained lock, update this | 132 | * finer-grained lock, update this |
108 | */ | 133 | */ |
109 | mutex_lock(&assigned_dev->kvm->lock); | 134 | mutex_lock(&kvm->lock); |
110 | kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, | 135 | if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) { |
111 | assigned_dev->guest_irq, 1); | 136 | struct kvm_guest_msix_entry *guest_entries = |
112 | 137 | assigned_dev->guest_msix_entries; | |
113 | if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI) { | 138 | for (i = 0; i < assigned_dev->entries_nr; i++) { |
114 | enable_irq(assigned_dev->host_irq); | 139 | if (!(guest_entries[i].flags & |
115 | assigned_dev->host_irq_disabled = false; | 140 | KVM_ASSIGNED_MSIX_PENDING)) |
141 | continue; | ||
142 | guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING; | ||
143 | kvm_set_irq(assigned_dev->kvm, | ||
144 | assigned_dev->irq_source_id, | ||
145 | guest_entries[i].vector, 1); | ||
146 | irq = assigned_dev->host_msix_entries[i].vector; | ||
147 | if (irq != 0) | ||
148 | enable_irq(irq); | ||
149 | assigned_dev->host_irq_disabled = false; | ||
150 | } | ||
151 | } else { | ||
152 | kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, | ||
153 | assigned_dev->guest_irq, 1); | ||
154 | if (assigned_dev->irq_requested_type & | ||
155 | KVM_ASSIGNED_DEV_GUEST_MSI) { | ||
156 | enable_irq(assigned_dev->host_irq); | ||
157 | assigned_dev->host_irq_disabled = false; | ||
158 | } | ||
116 | } | 159 | } |
160 | |||
117 | mutex_unlock(&assigned_dev->kvm->lock); | 161 | mutex_unlock(&assigned_dev->kvm->lock); |
118 | } | 162 | } |
119 | 163 | ||
@@ -122,6 +166,14 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id) | |||
122 | struct kvm_assigned_dev_kernel *assigned_dev = | 166 | struct kvm_assigned_dev_kernel *assigned_dev = |
123 | (struct kvm_assigned_dev_kernel *) dev_id; | 167 | (struct kvm_assigned_dev_kernel *) dev_id; |
124 | 168 | ||
169 | if (assigned_dev->irq_requested_type == KVM_ASSIGNED_DEV_MSIX) { | ||
170 | int index = find_index_from_host_irq(assigned_dev, irq); | ||
171 | if (index < 0) | ||
172 | return IRQ_HANDLED; | ||
173 | assigned_dev->guest_msix_entries[index].flags |= | ||
174 | KVM_ASSIGNED_MSIX_PENDING; | ||
175 | } | ||
176 | |||
125 | schedule_work(&assigned_dev->interrupt_work); | 177 | schedule_work(&assigned_dev->interrupt_work); |
126 | 178 | ||
127 | disable_irq_nosync(irq); | 179 | disable_irq_nosync(irq); |