提交 defaf158 编写于 作者: M Mark McLoughlin 提交者: Avi Kivity

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: NMark McLoughlin <markmc@redhat.com>
Signed-off-by: NAvi Kivity <avi@redhat.com>
上级 eb64f1e8
...@@ -307,6 +307,7 @@ struct kvm_assigned_dev_kernel { ...@@ -307,6 +307,7 @@ struct kvm_assigned_dev_kernel {
int host_busnr; int host_busnr;
int host_devfn; int host_devfn;
int host_irq; int host_irq;
bool host_irq_disabled;
int guest_irq; int guest_irq;
struct msi_msg guest_msi; struct msi_msg guest_msi;
#define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0) #define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0)
......
...@@ -170,6 +170,7 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) ...@@ -170,6 +170,7 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
KVM_ASSIGNED_DEV_GUEST_MSI) { KVM_ASSIGNED_DEV_GUEST_MSI) {
assigned_device_msi_dispatch(assigned_dev); assigned_device_msi_dispatch(assigned_dev);
enable_irq(assigned_dev->host_irq); enable_irq(assigned_dev->host_irq);
assigned_dev->host_irq_disabled = false;
} }
mutex_unlock(&assigned_dev->kvm->lock); mutex_unlock(&assigned_dev->kvm->lock);
kvm_put_kvm(assigned_dev->kvm); kvm_put_kvm(assigned_dev->kvm);
...@@ -181,8 +182,12 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id) ...@@ -181,8 +182,12 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
(struct kvm_assigned_dev_kernel *) dev_id; (struct kvm_assigned_dev_kernel *) dev_id;
kvm_get_kvm(assigned_dev->kvm); kvm_get_kvm(assigned_dev->kvm);
schedule_work(&assigned_dev->interrupt_work); schedule_work(&assigned_dev->interrupt_work);
disable_irq_nosync(irq); disable_irq_nosync(irq);
assigned_dev->host_irq_disabled = true;
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -196,8 +201,16 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian) ...@@ -196,8 +201,16 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
dev = container_of(kian, struct kvm_assigned_dev_kernel, dev = container_of(kian, struct kvm_assigned_dev_kernel,
ack_notifier); ack_notifier);
kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0); kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
enable_irq(dev->host_irq);
/* The guest irq may be shared so this ack may be
* from another device.
*/
if (dev->host_irq_disabled) {
enable_irq(dev->host_irq);
dev->host_irq_disabled = false;
}
} }
static void kvm_free_assigned_irq(struct kvm *kvm, static void kvm_free_assigned_irq(struct kvm *kvm,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册