aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2008-12-02 07:16:33 -0500
committerAvi Kivity <avi@redhat.com>2008-12-31 09:55:47 -0500
commitdefaf1587c5d7dff828f6f11c8941e5bcef00f50 (patch)
treefe4bcf162e203ee80916a5d168d838ef8aa62d25
parenteb64f1e8cd5c3cae912db30a77d062367f7a11a6 (diff)
KVM: fix handling of ACK from shared guest IRQ
If an assigned device shares a guest irq with an emulated device then we currently interpret an ack generated by the emulated device as originating from the assigned device leading to e.g. "Unbalanced enable for IRQ 4347" from the enable_irq() in kvm_assigned_dev_ack_irq(). The fix is fairly simple - don't enable the physical device irq unless it was previously disabled. Of course, this can still lead to a situation where a non-assigned device ACK can cause the physical device irq to be reenabled before the device was serviced. However, being level sensitive, the interrupt will merely be regenerated. Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--include/linux/kvm_host.h1
-rw-r--r--virt/kvm/kvm_main.c15
2 files changed, 15 insertions, 1 deletions
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 8091a4d90ddf..eafabd5c66b2 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -307,6 +307,7 @@ struct kvm_assigned_dev_kernel {
307 int host_busnr; 307 int host_busnr;
308 int host_devfn; 308 int host_devfn;
309 int host_irq; 309 int host_irq;
310 bool host_irq_disabled;
310 int guest_irq; 311 int guest_irq;
311 struct msi_msg guest_msi; 312 struct msi_msg guest_msi;
312#define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0) 313#define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index eb70ca6c7145..fc6127cbea1f 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -170,6 +170,7 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
170 KVM_ASSIGNED_DEV_GUEST_MSI) { 170 KVM_ASSIGNED_DEV_GUEST_MSI) {
171 assigned_device_msi_dispatch(assigned_dev); 171 assigned_device_msi_dispatch(assigned_dev);
172 enable_irq(assigned_dev->host_irq); 172 enable_irq(assigned_dev->host_irq);
173 assigned_dev->host_irq_disabled = false;
173 } 174 }
174 mutex_unlock(&assigned_dev->kvm->lock); 175 mutex_unlock(&assigned_dev->kvm->lock);
175 kvm_put_kvm(assigned_dev->kvm); 176 kvm_put_kvm(assigned_dev->kvm);
@@ -181,8 +182,12 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
181 (struct kvm_assigned_dev_kernel *) dev_id; 182 (struct kvm_assigned_dev_kernel *) dev_id;
182 183
183 kvm_get_kvm(assigned_dev->kvm); 184 kvm_get_kvm(assigned_dev->kvm);
185
184 schedule_work(&assigned_dev->interrupt_work); 186 schedule_work(&assigned_dev->interrupt_work);
187
185 disable_irq_nosync(irq); 188 disable_irq_nosync(irq);
189 assigned_dev->host_irq_disabled = true;
190
186 return IRQ_HANDLED; 191 return IRQ_HANDLED;
187} 192}
188 193
@@ -196,8 +201,16 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
196 201
197 dev = container_of(kian, struct kvm_assigned_dev_kernel, 202 dev = container_of(kian, struct kvm_assigned_dev_kernel,
198 ack_notifier); 203 ack_notifier);
204
199 kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0); 205 kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
200 enable_irq(dev->host_irq); 206
207 /* The guest irq may be shared so this ack may be
208 * from another device.
209 */
210 if (dev->host_irq_disabled) {
211 enable_irq(dev->host_irq);
212 dev->host_irq_disabled = false;
213 }
201} 214}
202 215
203static void kvm_free_assigned_irq(struct kvm *kvm, 216static void kvm_free_assigned_irq(struct kvm *kvm,