int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) { u32 old_irr; u32 mask = 1 << irq; union kvm_ioapic_redirect_entry entry; int ret = 1; spin_lock(&ioapic->lock); old_irr = ioapic->irr; if (irq >= 0 && irq < IOAPIC_NUM_PINS) { entry = ioapic->redirtbl[irq]; level ^= entry.fields.polarity; if (!level) ioapic->irr &= ~mask; else { int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); ioapic->irr |= mask; if ((edge && old_irr != ioapic->irr) || (!edge && !entry.fields.remote_irr)) ret = ioapic_service(ioapic, irq); else ret = 0; } trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0); } spin_unlock(&ioapic->lock); return ret; }
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) { uint32_t old_irr = ioapic->irr; uint32_t mask = 1 << irq; union kvm_ioapic_redirect_entry entry; int ret = 1; mutex_enter(&ioapic->lock); if (irq >= 0 && irq < IOAPIC_NUM_PINS) { entry = ioapic->redirtbl[irq]; level ^= entry.fields.polarity; if (!level) ioapic->irr &= ~mask; else { int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); ioapic->irr |= mask; if ((edge && old_irr != ioapic->irr) || (!edge && !entry.fields.remote_irr)) ret = ioapic_service(ioapic, irq); else ret = 0; /* report coalesced interrupt */ } KVM_TRACE3(ioapic__set__irq, uintptr_t, entry.bits, int, irq, int, ret == 0); }
static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, struct kvm_ioapic *ioapic, int vector, int trigger_mode) { int i; for (i = 0; i < IOAPIC_NUM_PINS; i++) { union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i]; if (ent->fields.vector != vector) continue; if (i == RTC_GSI) rtc_irq_eoi(ioapic, vcpu); /* * We are dropping lock while calling ack notifiers because ack * notifier callbacks for assigned devices call into IOAPIC * recursively. Since remote_irr is cleared only after call * to notifiers if the same vector will be delivered while lock * is dropped it will be put into irr and will be delivered * after ack notifier returns. */ spin_unlock(&ioapic->lock); kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i); spin_lock(&ioapic->lock); if (trigger_mode != IOAPIC_LEVEL_TRIG) continue; ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); ent->fields.remote_irr = 0; if (!ent->fields.mask && (ioapic->irr & (1 << i))) ioapic_service(ioapic, i, false); } }
static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) { unsigned index; switch (ioapic->ioregsel) { case IOAPIC_REG_VERSION: /* Writes are ignored. */ break; case IOAPIC_REG_APIC_ID: ioapic->id = (val >> 24) & 0xf; break; case IOAPIC_REG_ARB_ID: break; default: index = (ioapic->ioregsel - 0x10) >> 1; ioapic_debug("change redir index %x val %x\n", index, val); if (index >= IOAPIC_NUM_PINS) return; if (ioapic->ioregsel & 1) { ioapic->redirtbl[index].bits &= 0xffffffff; ioapic->redirtbl[index].bits |= (u64) val << 32; } else { ioapic->redirtbl[index].bits &= ~0xffffffffULL; ioapic->redirtbl[index].bits |= (u32) val; ioapic->redirtbl[index].fields.remote_irr = 0; } if (ioapic->irr & (1 << index)) ioapic_service(ioapic, index); break; } }
static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, struct kvm_ioapic *ioapic, int vector, int trigger_mode) { struct dest_map *dest_map = &ioapic->rtc_status.dest_map; struct kvm_lapic *apic = vcpu->arch.apic; int i; /* RTC special handling */ if (test_bit(vcpu->vcpu_id, dest_map->map) && vector == dest_map->vectors[vcpu->vcpu_id]) rtc_irq_eoi(ioapic, vcpu); for (i = 0; i < IOAPIC_NUM_PINS; i++) { union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i]; if (ent->fields.vector != vector) continue; /* * We are dropping lock while calling ack notifiers because ack * notifier callbacks for assigned devices call into IOAPIC * recursively. Since remote_irr is cleared only after call * to notifiers if the same vector will be delivered while lock * is dropped it will be put into irr and will be delivered * after ack notifier returns. */ spin_unlock(&ioapic->lock); kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i); spin_lock(&ioapic->lock); if (trigger_mode != IOAPIC_LEVEL_TRIG || kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) continue; ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); ent->fields.remote_irr = 0; if (!ent->fields.mask && (ioapic->irr & (1 << i))) { ++ioapic->irq_eoi[i]; if (ioapic->irq_eoi[i] == IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT) { /* * Real hardware does not deliver the interrupt * immediately during eoi broadcast, and this * lets a buggy guest make slow progress * even if it does not correctly handle a * level-triggered interrupt. Emulate this * behavior if we detect an interrupt storm. */ schedule_delayed_work(&ioapic->eoi_inject, HZ / 100); ioapic->irq_eoi[i] = 0; trace_kvm_ioapic_delayed_eoi_inj(ent->bits); } else { ioapic_service(ioapic, i, false); } } else { ioapic->irq_eoi[i] = 0; } } }
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi) { union ioapic_redir_entry *ent; ent = &ioapic->redirtbl[gsi]; ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); ent->fields.remote_irr = 0; if (!ent->fields.mask && (ioapic->irr & (1 << gsi))) ioapic_service(ioapic, gsi); }
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) ioapic->irr_delivered &= ~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 ioapic_write_indirect(struct kvm_ioapic *ioapic, uint32_t val) { unsigned index; int mask_before, mask_after; union kvm_ioapic_redirect_entry *e; switch (ioapic->ioregsel) { case IOAPIC_REG_VERSION: /* Writes are ignored. */ break; case IOAPIC_REG_APIC_ID: ioapic->id = (val >> 24) & 0xf; break; case IOAPIC_REG_ARB_ID: break; default: index = (ioapic->ioregsel - 0x10) >> 1; if (index >= IOAPIC_NUM_PINS) return; e = &ioapic->redirtbl[index]; mask_before = e->fields.mask; if (ioapic->ioregsel & 1) { e->bits &= 0xffffffff; e->bits |= (uint64_t) val << 32; } else { e->bits &= ~0xffffffffULL; e->bits |= (uint32_t) val; e->fields.remote_irr = 0; } update_handled_vectors(ioapic); mask_after = e->fields.mask; if (mask_before != mask_after) kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after); if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG && ioapic->irr & (1 << index)) ioapic_service(ioapic, index); break; } }
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin, int trigger_mode) { union ioapic_redir_entry *ent; ent = &ioapic->redirtbl[pin]; kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin); if (trigger_mode == IOAPIC_LEVEL_TRIG) { ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); ent->fields.remote_irr = 0; if (!ent->fields.mask && (ioapic->irr & (1 << pin))) ioapic_service(ioapic, pin); } }
static void kvm_ioapic_eoi_inject_work(struct work_struct *work) { int i; struct kvm_ioapic *ioapic = container_of(work, struct kvm_ioapic, eoi_inject.work); spin_lock(&ioapic->lock); for (i = 0; i < IOAPIC_NUM_PINS; i++) { union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i]; if (ent->fields.trig_mode != IOAPIC_LEVEL_TRIG) continue; if (ioapic->irr & (1 << i) && !ent->fields.remote_irr) ioapic_service(ioapic, i, false); } spin_unlock(&ioapic->lock); }
static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) { unsigned index; bool mask_before, mask_after; union kvm_ioapic_redirect_entry *e; switch (ioapic->ioregsel) { case IOAPIC_REG_VERSION: /* Writes are ignored. */ break; case IOAPIC_REG_APIC_ID: ioapic->id = (val >> 24) & 0xf; break; case IOAPIC_REG_ARB_ID: break; default: index = (ioapic->ioregsel - 0x10) >> 1; ioapic_debug("change redir index %x val %x\n", index, val); if (index >= IOAPIC_NUM_PINS) return; e = &ioapic->redirtbl[index]; mask_before = e->fields.mask; if (ioapic->ioregsel & 1) { e->bits &= 0xffffffff; e->bits |= (u64) val << 32; } else { e->bits &= ~0xffffffffULL; e->bits |= (u32) val; e->fields.remote_irr = 0; } update_handled_vectors(ioapic); mask_after = e->fields.mask; if (mask_before != mask_after) kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after); if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG && ioapic->irr & (1 << index)) ioapic_service(ioapic, index, false); kvm_vcpu_request_scan_ioapic(ioapic->kvm); break; } }
void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) { u32 old_irr = ioapic->irr; u32 mask = 1 << irq; union ioapic_redir_entry entry; if (irq >= 0 && irq < IOAPIC_NUM_PINS) { entry = ioapic->redirtbl[irq]; level ^= entry.fields.polarity; if (!level) ioapic->irr &= ~mask; else { ioapic->irr |= mask; if ((!entry.fields.trig_mode && old_irr != ioapic->irr) || !entry.fields.remote_irr) ioapic_service(ioapic, irq); } } }
static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) { unsigned index; bool mask_before, mask_after; switch (ioapic->ioregsel) { case IOAPIC_REG_VERSION: /* Writes are ignored. */ break; case IOAPIC_REG_APIC_ID: ioapic->id = (val >> 24) & 0xf; break; case IOAPIC_REG_ARB_ID: break; default: index = (ioapic->ioregsel - 0x10) >> 1; ioapic_debug("change redir index %x val %x\n", index, val); if (index >= IOAPIC_NUM_PINS) return; mask_before = ioapic->redirtbl[index].fields.mask; if (ioapic->ioregsel & 1) { ioapic->redirtbl[index].bits &= 0xffffffff; ioapic->redirtbl[index].bits |= (u64) val << 32; } else { ioapic->redirtbl[index].bits &= ~0xffffffffULL; ioapic->redirtbl[index].bits |= (u32) val; ioapic->redirtbl[index].fields.remote_irr = 0; } mask_after = ioapic->redirtbl[index].fields.mask; if (mask_before != mask_after) kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after); if (ioapic->redirtbl[index].fields.trig_mode == IOAPIC_LEVEL_TRIG && ioapic->irr & (1 << index)) ioapic_service(ioapic, index); break; } }
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]; irq_level ^= entry.fields.polarity; if (!irq_level) { ioapic->irr &= ~mask; ret = 1; } else { int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); 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; }
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector, int trigger_mode) { int i; for (i = 0; i < IOAPIC_NUM_PINS; i++) { union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i]; if (ent->fields.vector != vector) continue; spin_unlock(&ioapic->lock); kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i); spin_lock(&ioapic->lock); if (trigger_mode != IOAPIC_LEVEL_TRIG) continue; ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); ent->fields.remote_irr = 0; if (!ent->fields.mask && (ioapic->irr & (1 << i))) ioapic_service(ioapic, i); } }