static void i8259_set_irq(void *opaque, int irq, int level) { PicState2 *s = opaque; #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq]) { #if defined(DEBUG_PIC) printf("i8259_set_irq: irq=%d level=%d\n", irq, level); #endif irq_level[irq] = level; #ifdef DEBUG_IRQ_COUNT if (level == 1) irq_count[irq]++; #endif } #endif #ifdef DEBUG_IRQ_LATENCY if (level) { irq_time[irq] = qemu_get_clock(vm_clock); } #endif pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); /* used for IOAPIC irqs */ if (s->alt_irq_func) s->alt_irq_func(s->alt_irq_opaque, irq, level); pic_update_irq(s); }
/* raise irq to CPU if necessary. must be called every time the active irq may change */ static int pic_update_irq(PDEVPIC pThis) { PicState *pics = &pThis->aPics[0]; int irq2, irq; /* first look at slave pic */ irq2 = pic_get_irq(&pics[1]); Log(("pic_update_irq irq2=%d\n", irq2)); if (irq2 >= 0) { /* if irq request by slave pic, signal master PIC */ pic_set_irq1(&pics[0], 2, 1); } else { /* If not, clear the IR on the master PIC. */ pic_set_irq1(&pics[0], 2, 0); } /* look at requested irq */ irq = pic_get_irq(&pics[0]); if (irq >= 0) { /* If irq 2 is pending on the master pic, then there must be one pending on the slave pic too! Otherwise we'll get * spurious slave interrupts in picGetInterrupt. */ if (irq != 2 || irq2 != -1) { #if defined(DEBUG_PIC) int i; for(i = 0; i < 2; i++) { Log(("pic%d: imr=%x irr=%x padd=%d\n", i, pics[i].imr, pics[i].irr, pics[i].priority_add)); } Log(("pic: cpu_interrupt\n")); #endif pThis->CTX_SUFF(pPicHlp)->pfnSetInterruptFF(pThis->CTX_SUFF(pDevIns)); } else { STAM_COUNTER_INC(&pThis->StatClearedActiveIRQ2); Log(("pic_update_irq: irq 2 is active, but no interrupt is pending on the slave pic!!\n")); /* Clear it here, so lower priority interrupts can still be dispatched. */ /* if this was the only pending irq, then we must clear the interrupt ff flag */ pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns)); /** @note Is this correct? */ pics[0].irr &= ~(1 << 2); /* Call ourselves again just in case other interrupts are pending */ return pic_update_irq(pThis); } } else { Log(("pic_update_irq: no interrupt is pending!!\n")); /* we must clear the interrupt ff flag */ pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns)); } return VINF_SUCCESS; }
int kvm_pic_read_irq(struct kvm_pic *s) { int irq, irq2, intno; irq = pic_get_irq(&s->pics[0]); if (irq >= 0) { pic_intack(&s->pics[0], irq); if (irq == 2) { irq2 = pic_get_irq(&s->pics[1]); if (irq2 >= 0) pic_intack(&s->pics[1], irq2); else /* * spurious IRQ on slave controller */ irq2 = 7; intno = s->pics[1].irq_base + irq2; irq = irq2 + 8; } else intno = s->pics[0].irq_base + irq; } else { /* * spurious IRQ on host controller */ irq = 7; intno = s->pics[0].irq_base + irq; } pic_update_irq(s); return intno; }
void kvm_pic_set_irq(void *opaque, int irq, int level) { struct kvm_pic *s = opaque; pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); pic_update_irq(s); }
int pic_read_irq(PicState2 *s) { int irq, irq2, intno; irq = pic_get_irq(&s->pics[0]); if (irq >= 0) { pic_intack(&s->pics[0], irq); #ifndef TARGET_IA64 if (time_drift_fix && irq == 0) { extern int64_t timer_acks, timer_ints_to_push; timer_acks++; if (timer_ints_to_push > 0) { timer_ints_to_push--; /* simulate an edge irq0, like the one generated by i8254 */ pic_set_irq1(&s->pics[0], 0, 0); pic_set_irq1(&s->pics[0], 0, 1); } } #endif if (irq == 2) { irq2 = pic_get_irq(&s->pics[1]); if (irq2 >= 0) { pic_intack(&s->pics[1], irq2); } else { /* spurious IRQ on slave controller */ irq2 = 7; } intno = s->pics[1].irq_base + irq2; #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY) irq = irq2 + 8; #endif } else { intno = s->pics[0].irq_base + irq; } } else { /* spurious IRQ on host controller */ irq = 7; intno = s->pics[0].irq_base + irq; } pic_update_irq(s); #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", irq, (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / get_ticks_per_sec()); #endif #if defined(DEBUG_PIC) printf("pic_interrupt: irq=%d\n", irq); #endif return intno; }
/* acknowledge interrupt 'irq' */ static void pic_intack(PICCommonState *s, int irq) { if (s->auto_eoi) { if (s->rotate_on_auto_eoi) { s->priority_add = (irq + 1) & 7; } } else { s->isr |= (1 << irq); } /* We don't clear a level sensitive interrupt here */ if (!(s->elcr & (1 << irq))) { s->irr &= ~(1 << irq); } pic_update_irq(s); }
/* set irq level. If an edge is detected, then the IRR is set to 1 */ static void pic_set_irq(void *opaque, int irq, int level) { PICCommonState *s = opaque; int mask = 1 << irq; #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \ defined(DEBUG_IRQ_LATENCY) int irq_index = s->master ? irq : irq + 8; #endif #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq_index]) { DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level); irq_level[irq_index] = level; #ifdef DEBUG_IRQ_COUNT if (level == 1) { irq_count[irq_index]++; } #endif } #endif #ifdef DEBUG_IRQ_LATENCY if (level) { irq_time[irq_index] = qemu_get_clock_ns(vm_clock); } #endif if (s->elcr & mask) { /* level triggered */ if (level) { s->irr |= mask; s->last_irr |= mask; } else { s->irr &= ~mask; s->last_irr &= ~mask; } } else { /* edge triggered */ if (level) { if ((s->last_irr & mask) == 0) { s->irr |= mask; } s->last_irr |= mask; } else { s->last_irr &= ~mask; } } pic_update_irq(s); }
/* IRQ handling */ int cpu_get_pic_interrupt(CPUState *env) { int intno; intno = apic_get_interrupt(env->apic_state); if (intno >= 0) { /* set irq request if a PIC irq is still pending */ /* XXX: improve that */ pic_update_irq(isa_pic); return intno; } /* read the irq from the PIC */ if (!apic_accept_pic_intr(env->apic_state)) { return -1; } intno = pic_read_irq(isa_pic); return intno; }
static void pic_init_reset(PicState *s) { s->last_irr = 0; s->irr = 0; s->imr = 0; s->isr = 0; s->priority_add = 0; s->irq_base = 0; s->read_reg_select = 0; s->poll = 0; s->special_mask = 0; s->init_state = 0; s->auto_eoi = 0; s->rotate_on_auto_eoi = 0; s->special_fully_nested_mode = 0; s->init4 = 0; s->single_mode = 0; /* Note: ELCR is not reset */ pic_update_irq(s); }
/** * Set the an IRQ. * * @param pDevIns Device instance of the PICs. * @param iIrq IRQ number to set. * @param iLevel IRQ level. * @param uTagSrc The IRQ tag and source ID (for tracing). */ PDMBOTHCBDECL(void) picSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc) { PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC); Assert(pThis->CTX_SUFF(pDevIns) == pDevIns); Assert(pThis->aPics[0].CTX_SUFF(pDevIns) == pDevIns); Assert(pThis->aPics[1].CTX_SUFF(pDevIns) == pDevIns); AssertMsg(iIrq < 16, ("iIrq=%d\n", iIrq)); Log(("picSetIrq %d %d\n", iIrq, iLevel)); DumpPICState(&pThis->aPics[0], "picSetIrq"); DumpPICState(&pThis->aPics[1], "picSetIrq"); STAM_COUNTER_INC(&pThis->CTXSUFF(StatSetIrq)); if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) { /* A flip-flop lowers the IRQ line and immediately raises it, so * that a rising edge is guaranteed to occur. Note that the IRQ * line must be held high for a while to avoid spurious interrupts. */ pic_set_irq1(&pThis->aPics[iIrq >> 3], iIrq & 7, 0, uTagSrc); pic_update_irq(pThis); }
static void i8259_set_irq(void *opaque, int irq, int level) { PicState2 *s = opaque; #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq]) { DPRINTF("i8259_set_irq: irq=%d level=%d\n", irq, level); irq_level[irq] = level; #ifdef DEBUG_IRQ_COUNT if (level == 1) irq_count[irq]++; #endif } #endif #ifdef DEBUG_IRQ_LATENCY if (level) { irq_time[irq] = qemu_get_clock_ns(vm_clock); } #endif pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); pic_update_irq(s); }
int pic_read_irq(PicState2 *s) { int irq, irq2, intno; irq = pic_get_irq(&s->pics[0]); if (irq >= 0) { pic_intack(&s->pics[0], irq); if (irq == 2) { irq2 = pic_get_irq(&s->pics[1]); if (irq2 >= 0) { pic_intack(&s->pics[1], irq2); } else { /* spurious IRQ on slave controller */ irq2 = 7; } intno = s->pics[1].irq_base + irq2; #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY) irq = irq2 + 8; #endif } else { intno = s->pics[0].irq_base + irq; } } else { /* spurious IRQ on host controller */ irq = 7; intno = s->pics[0].irq_base + irq; } pic_update_irq(s); #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", irq, (double)(qemu_get_clock_ns(vm_clock) - irq_time[irq]) * 1000000.0 / get_ticks_per_sec()); #endif DPRINTF("pic_interrupt: irq=%d\n", irq); return intno; }
static void pic_init_reset(PICCommonState *s) { pic_reset_common(s); pic_update_irq(s); }
static void pic_ioport_write(void *opaque, target_phys_addr_t addr64, uint64_t val64, unsigned size) { PicState *s = opaque; uint32_t addr = addr64; uint32_t val = val64; int priority, cmd, irq; DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val); if (addr == 0) { if (val & 0x10) { /* init */ pic_reset(s); /* deassert a pending interrupt */ qemu_irq_lower(s->pics_state->parent_irq); s->init_state = 1; s->init4 = val & 1; s->single_mode = val & 2; if (val & 0x08) hw_error("level sensitive irq not supported"); } else if (val & 0x08) { if (val & 0x04) s->poll = 1; if (val & 0x02) s->read_reg_select = val & 1; if (val & 0x40) s->special_mask = (val >> 5) & 1; } else { cmd = val >> 5; switch(cmd) { case 0: case 4: s->rotate_on_auto_eoi = cmd >> 2; break; case 1: /* end of interrupt */ case 5: priority = get_priority(s, s->isr); if (priority != 8) { irq = (priority + s->priority_add) & 7; s->isr &= ~(1 << irq); if (cmd == 5) s->priority_add = (irq + 1) & 7; pic_update_irq(s->pics_state); } break; case 3: irq = val & 7; s->isr &= ~(1 << irq); pic_update_irq(s->pics_state); break; case 6: s->priority_add = (val + 1) & 7; pic_update_irq(s->pics_state); break; case 7: irq = val & 7; s->isr &= ~(1 << irq); s->priority_add = (irq + 1) & 7; pic_update_irq(s->pics_state); break; default: /* no operation */ break; } } } else {
static void pic_ioport_write(void *opaque, u32 addr, u32 val) { struct kvm_kpic_state *s = opaque; int priority, cmd, irq; addr &= 1; if (addr == 0) { if (val & 0x10) { kvm_pic_reset(s); /* init */ /* * deassert a pending interrupt */ s->pics_state->irq_request(s->pics_state-> irq_request_opaque, 0); s->init_state = 1; s->init4 = val & 1; if (val & 0x02) printk(KERN_ERR "single mode not supported"); if (val & 0x08) printk(KERN_ERR "level sensitive irq not supported"); } else if (val & 0x08) { if (val & 0x04) s->poll = 1; if (val & 0x02) s->read_reg_select = val & 1; if (val & 0x40) s->special_mask = (val >> 5) & 1; } else { cmd = val >> 5; switch (cmd) { case 0: case 4: s->rotate_on_auto_eoi = cmd >> 2; break; case 1: /* end of interrupt */ case 5: priority = get_priority(s, s->isr); if (priority != 8) { irq = (priority + s->priority_add) & 7; s->isr &= ~(1 << irq); if (cmd == 5) s->priority_add = (irq + 1) & 7; pic_update_irq(s->pics_state); } break; case 3: irq = val & 7; s->isr &= ~(1 << irq); pic_update_irq(s->pics_state); break; case 6: s->priority_add = (val + 1) & 7; pic_update_irq(s->pics_state); break; case 7: irq = val & 7; s->isr &= ~(1 << irq); s->priority_add = (irq + 1) & 7; pic_update_irq(s->pics_state); break; default: break; /* no operation */ } } } else
void kvm_pic_update_irq(struct kvm_pic *s) { pic_update_irq(s); }