/* Sun4d interrupts fall roughly into two categories. SBUS and * cpu local. CPU local interrupts cover the timer interrupts * and whatnot, and we encode those as normal PILs between * 0 and 15. * SBUS interrupts are encodes as a combination of board, level and slot.
*/
/* Exported for sun4d_smp.c */
DEFINE_SPINLOCK(sun4d_imsk_lock);
/* SBUS interrupts are encoded integers including the board number * (plus one), the SBUS level, and the SBUS slot number. Sun4D * IRQ dispatch is done by: * * 1) Reading the BW local interrupt table in order to get the bus * interrupt mask. * * This table is indexed by SBUS interrupt level which can be * derived from the PIL we got interrupted on. * * 2) For each bus showing interrupt pending from #1, read the * SBI interrupt state register. This will indicate which slots * have interrupts pending for that SBUS interrupt level. * * 3) Call the genreric IRQ support.
*/ staticvoid sun4d_sbus_handler_irq(int sbusl)
{ unsignedint bus_mask; unsignedint sbino, slot; unsignedint sbil;
sbil = (sbusl << 2); /* Loop for each pending SBI */ for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) { unsignedint idx, mask;
if (!(bus_mask & 1)) continue; /* XXX This seems to ACK the irq twice. acquire_sbi() * XXX uses swap, therefore this writes 0xf << sbil, * XXX then later release_sbi() will write the individual * XXX bits which were set again.
*/
mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
mask &= (0xf << sbil);
/* Loop for each pending SBI slot */
slot = (1 << sbil); for (idx = 0; mask != 0; idx++, slot <<= 1) { unsignedint pil; struct irq_bucket *p;
#ifdef CONFIG_SMP /* * Check IPI data structures after IRQ has been cleared. Hard and Soft * IRQ can happen at the same time, so both cases are always handled.
*/ if (pil == SUN4D_IPI_IRQ)
sun4d_ipi_interrupt(); #endif
old_regs = set_irq_regs(regs);
irq_enter(); if (sbusl == 0) { /* cpu interrupt */ struct irq_bucket *p;
p = irq_map[pil]; while (p) { struct irq_bucket *next;
next = p->next;
generic_handle_irq(p->irq);
p = next;
}
} else { /* SBUS interrupt */
sun4d_sbus_handler_irq(sbusl);
}
irq_exit();
set_irq_regs(old_regs);
}
irq = real_irq; while (bus) { if (of_node_name_eq(bus, "sbi")) {
bus_connection = "io-unit"; break;
}
if (of_node_name_eq(bus, "bootbus")) {
bus_connection = "cpu-unit"; break;
}
bus = bus->parent;
} if (!bus) goto err_out;
regs = of_get_property(dp, "reg", NULL); if (!regs) goto err_out;
slot = regs->which_io;
/* * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit * lacks a "board#" property, something is very wrong.
*/ if (!of_node_name_eq(bus->parent, bus_connection)) {
printk(KERN_ERR "%pOF: Error, parent is not %s.\n",
bus, bus_connection); goto err_out;
}
board_parent = bus->parent;
board = of_getintprop_default(board_parent, "board#", -1); if (board == -1) {
printk(KERN_ERR "%pOF: Error, lacks board# property.\n",
board_parent); goto err_out;
}
/* Adjust so that we jump directly to smp4d_ticker */
lvl14_save[2] += smp4d_ticker - real_irq_entry;
/* For SMP we use the level 14 ticker, however the bootup code * has copied the firmware's level 14 vector into the boot cpu's * trap table, we must fix this now or we get squashed.
*/
local_irq_save(flags);
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
trap_table->inst_one = lvl14_save[0];
trap_table->inst_two = lvl14_save[1];
trap_table->inst_three = lvl14_save[2];
trap_table->inst_four = lvl14_save[3];
local_ops->cache_all();
local_irq_restore(flags); #endif
}
staticvoid __init sun4d_init_timers(void)
{ struct device_node *dp; struct resource res; unsignedint irq; const u32 *reg; int err; int board;
dp = of_find_node_by_name(NULL, "cpu-unit"); if (!dp) {
prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
prom_halt();
}
/* Which cpu-unit we use is arbitrary, we can view the bootbus timer * registers via any cpu's mapping. The first 'reg' property is the * bootbus.
*/
reg = of_get_property(dp, "reg", NULL); if (!reg) {
prom_printf("sun4d_init_timers: No reg property\n");
prom_halt();
}
board = of_getintprop_default(dp, "board#", -1); if (board == -1) {
prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
prom_halt();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.