/*
 * Recalculate the interrupt masks from scratch.
 * We could code special registry and deregistry versions of this function that
 * would be faster, but the code would be nastier, and we don't expect this to
 * happen very much anyway.
 */
void
intr_calculatemasks(void)
{
	int irq, level;
	struct intrq *iq;
	struct intrhand *ih;

	/* First, figure out which levels each IRQ uses. */
	for (irq = 0; irq < ICU_LEN; irq++) {
		int levels = 0;
		iq = &isa_intrq[irq];
		for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
			ih = TAILQ_NEXT(ih, ih_list))
			levels |= (1U << ih->ih_ipl);
		iq->iq_levels = levels;
	}

	/* Then figure out which IRQs use each level. */
	for (level = 0; level < NIPL; level++) {
		int irqs = 0;
		for (irq = 0; irq < ICU_LEN; irq++)
			if (isa_intrq[irq].iq_levels & (1U << level))
				irqs |= (1U << irq);
		imask[level] = irqs;
	}

	imask[IPL_SCHED] |= imask[IPL_VM];
	imask[IPL_HIGH] |= imask[IPL_SCHED];

	/* And eventually calculate the complete masks. */
	for (irq = 0; irq < ICU_LEN; irq++) {
		int irqs = 1 << irq;
		iq = &isa_intrq[irq];
		for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
			ih = TAILQ_NEXT(ih, ih_list))
			irqs |= imask[ih->ih_ipl];
		iq->iq_mask = irqs;
	}

	/* Lastly, determine which IRQs are actually in use. */
	{
		int irqs = 0;
		for (irq = 0; irq < ICU_LEN; irq++)
			if (!TAILQ_EMPTY(&isa_intrq[irq].iq_list))
				irqs |= (1U << irq);
		if (irqs >= 0x100) /* any IRQs >= 8 in use */
			irqs |= 1 << IRQ_SLAVE;
		imen = ~irqs;
		SET_ICUS();
	}
#if 0
	printf("type\tmask\tlevel\thand\n");
	for (irq = 0; irq < ICU_LEN; irq++) {
		printf("%x\t%04x\t%x\t%p\n", intrtype[irq], intrmask[irq],
		intrlevel[irq], intrhand[irq]);
	}
	for (level = 0; level < IPL_LEVELS; ++level)
		printf("%d: %08x\n", level, imask[level]);
#endif
}
Beispiel #2
0
/*
 * Recalculate the interrupt masks from scratch.
 * We could code special registry and deregistry versions of this function that
 * would be faster, but the code would be nastier, and we don't expect this to
 * happen very much anyway.
 */
void
intr_calculatemasks(void)
{
	int irq, level, unusedirqs;
	struct intrhand *q;

	/* First, figure out which levels each IRQ uses. */
	unusedirqs = 0xffff;
	for (irq = 0; irq < ICU_LEN; irq++) {
		int levels = 0;
		for (q = intrhand[irq]; q; q = q->ih_next)
			levels |= 1 << IPL(q->ih_level);
		intrlevel[irq] = levels;
		if (levels)
			unusedirqs &= ~(1 << irq);
	}

	/* Then figure out which IRQs use each level. */
	for (level = 0; level < NIPL; level++) {
		int irqs = 0;
		for (irq = 0; irq < ICU_LEN; irq++)
			if (intrlevel[irq] & (1 << level))
				irqs |= 1 << irq;
		imask[level] = irqs | unusedirqs;
	}

	/*
	 * Initialize soft interrupt masks to block themselves.
	 */
	IMASK(IPL_SOFTAST) |= 1 << SIR_AST;
	IMASK(IPL_SOFTCLOCK) |= 1 << SIR_CLOCK;
	IMASK(IPL_SOFTNET) |= 1 << SIR_NET;
	IMASK(IPL_SOFTTTY) |= 1 << SIR_TTY;

	/*
	 * Enforce a hierarchy that gives slow devices a better chance at not
	 * dropping data.
	 */
	for (level = 0; level < NIPL - 1; level++)
		imask[level + 1] |= imask[level];

	/* And eventually calculate the complete masks. */
	for (irq = 0; irq < ICU_LEN; irq++) {
		int irqs = 1 << irq;
		int minlevel = IPL_NONE;
		int maxlevel = IPL_NONE;

		if (intrhand[irq] == NULL) {
			maxlevel = IPL_HIGH;
			irqs = IMASK(IPL_HIGH);
		} else {
			for (q = intrhand[irq]; q; q = q->ih_next) {
				irqs |= IMASK(q->ih_level);
				if (minlevel == IPL_NONE ||
				    q->ih_level < minlevel)
					minlevel = q->ih_level;
				if (q->ih_level > maxlevel)
					maxlevel = q->ih_level;
			}
		}
		if (irqs != IMASK(maxlevel))
			panic("irq %d level %x mask mismatch: %x vs %x", irq,
			    maxlevel, irqs, IMASK(maxlevel));

		intrmask[irq] = irqs;
		iminlevel[irq] = minlevel;
		imaxlevel[irq] = maxlevel;

#if 0
		printf("irq %d: level %x, mask 0x%x (%x)\n", irq,
		    imaxlevel[irq], intrmask[irq], IMASK(imaxlevel[irq]));
#endif
	}

	/* Lastly, determine which IRQs are actually in use. */
	{
		int irqs = 0;
		for (irq = 0; irq < ICU_LEN; irq++)
			if (intrhand[irq])
				irqs |= 1 << irq;
		if (irqs >= 0x100) /* any IRQs >= 8 in use */
			irqs |= 1 << IRQ_SLAVE;
		imen = ~irqs;
		SET_ICUS();
	}

	/* For speed of splx, provide the inverse of the interrupt masks. */
	for (irq = 0; irq < ICU_LEN; irq++)
		iunmask[irq] = ~imask[irq];
}