예제 #1
0
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;
}
예제 #2
0
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);
	}
예제 #3
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);
	}
}
예제 #4
0
파일: ioapic.c 프로젝트: mobilipia/iods
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;
	}
}
예제 #5
0
파일: ioapic.c 프로젝트: AshishNamdev/linux
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;
		}
	}
}
예제 #6
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);
}
예제 #7
0
파일: ioapic.c 프로젝트: AshishNamdev/linux
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;
}
예제 #8
0
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;
	}
}
예제 #9
0
파일: ioapic.c 프로젝트: ddk50/ibkvm
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);
	}
}
예제 #10
0
파일: ioapic.c 프로젝트: AshishNamdev/linux
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);
}
예제 #11
0
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;
	}
}
예제 #12
0
파일: ioapic.c 프로젝트: mobilipia/iods
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);
		}
	}
}
예제 #13
0
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;
	}
}
예제 #14
0
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;
}
예제 #15
0
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);
	}
}