Skip to content

Commit

Permalink
KVM: ioapic: extract body of kvm_ioapic_set_irq
Browse files Browse the repository at this point in the history
We will reuse it to process a nonzero IRR that is passed to KVM_SET_IRQCHIP.

Reviewed-by: Alex Williamson <[email protected]>
Signed-off-by: Paolo Bonzini <[email protected]>
  • Loading branch information
bonzini committed Mar 21, 2014
1 parent 0bc830b commit 44847de
Showing 1 changed file with 50 additions and 24 deletions.
74 changes: 50 additions & 24 deletions virt/kvm/ioapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,55 @@ static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic)
return false;
}

static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
int irq_level, bool line_status)
{
union kvm_ioapic_redirect_entry entry;
u32 mask = 1 << irq;
u32 old_irr;
int edge, ret;

entry = ioapic->redirtbl[irq];
edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);

if (!irq_level) {
ioapic->irr &= ~mask;
ret = 1;
goto out;
}

/*
* Return 0 for coalesced interrupts; for edge-triggered interrupts,
* this only happens if a previous edge has not been delivered due
* do masking. For level interrupts, the remote_irr field tells
* us if the interrupt is waiting for an EOI.
*
* RTC is special: it is edge-triggered, but userspace likes to know
* if it has been already ack-ed via EOI because coalesced RTC
* interrupts lead to time drift in Windows guests. So we track
* EOI manually for the RTC interrupt.
*/
if (irq == RTC_GSI && line_status &&
rtc_irq_check_coalesced(ioapic)) {
ret = 0;
goto out;
}

old_irr = ioapic->irr;
ioapic->irr |= mask;
if ((edge && old_irr == ioapic->irr) ||
(!edge && entry.fields.remote_irr)) {
ret = 0;
goto out;
}

ret = ioapic_service(ioapic, irq, line_status);

out:
trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
return ret;
}

static void update_handled_vectors(struct kvm_ioapic *ioapic)
{
DECLARE_BITMAP(handled_vectors, 256);
Expand Down Expand Up @@ -308,38 +357,15 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
int level, bool line_status)
{
u32 old_irr;
u32 mask = 1 << irq;
union kvm_ioapic_redirect_entry entry;
int ret, irq_level;

BUG_ON(irq < 0 || irq >= IOAPIC_NUM_PINS);

spin_lock(&ioapic->lock);
old_irr = ioapic->irr;
irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
irq_source_id, level);
entry = ioapic->redirtbl[irq];
if (!irq_level) {
ioapic->irr &= ~mask;
ret = 1;
} else {
int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
ret = ioapic_set_irq(ioapic, irq, irq_level, line_status);

if (irq == RTC_GSI && line_status &&
rtc_irq_check_coalesced(ioapic)) {
ret = 0; /* coalesced */
goto out;
}
ioapic->irr |= mask;
if ((edge && old_irr != ioapic->irr) ||
(!edge && !entry.fields.remote_irr))
ret = ioapic_service(ioapic, irq, line_status);
else
ret = 0; /* report coalesced interrupt */
}
out:
trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
spin_unlock(&ioapic->lock);

return ret;
Expand Down

0 comments on commit 44847de

Please sign in to comment.