arch/sparc/kernel/sun4d_irq.c

Source file repositories/reference/linux-study-clean/arch/sparc/kernel/sun4d_irq.c

File Facts

System
Linux kernel
Corpus path
arch/sparc/kernel/sun4d_irq.c
Extension
.c
Size
12456 bytes
Lines
520
Domain
Architecture Layer
Bucket
arch/sparc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct sun4d_handler_data {
	unsigned int cpuid;    /* target cpu */
	unsigned int real_irq; /* interrupt level */
};


static unsigned int sun4d_encode_irq(int board, int lvl, int slot)
{
	return (board + 1) << 5 | (lvl << 2) | slot;
}

struct sun4d_timer_regs {
	u32	l10_timer_limit;
	u32	l10_cur_countx;
	u32	l10_limit_noclear;
	u32	ctrl;
	u32	l10_cur_count;
};

static struct sun4d_timer_regs __iomem *sun4d_timers;

#define SUN4D_TIMER_IRQ        10

/* Specify which cpu handle interrupts from which board.
 * Index is board - value is cpu.
 */
static unsigned char board_to_cpu[32];

static int pil_to_sbus[] = {
	0,
	0,
	1,
	2,
	0,
	3,
	0,
	4,
	0,
	5,
	0,
	6,
	0,
	7,
	0,
	0,
};

/* 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.
 */
static void sun4d_sbus_handler_irq(int sbusl)
{
	unsigned int bus_mask;
	unsigned int sbino, slot;
	unsigned int sbil;

	bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
	bw_clear_intr_mask(sbusl, bus_mask);

	sbil = (sbusl << 2);
	/* Loop for each pending SBI */
	for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
		unsigned int 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);

Annotation

Implementation Notes