1094 lines · 23.9 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * arm mpcore generic interrupt controller (gic) v1 * traps, exceptions, interrupts, system calls. * * there are two pieces: the interrupt distributor and the cpu interface. * * memset or memmove on any of the distributor registers generates an * exception like this one: *	panic: external abort 0x28 pc 0xc048bf68 addr 0x50041800 * * we use l1 and l2 cache ops to force vectors to be visible everywhere. * * apparently irqs 0—15 (SGIs) are always enabled. */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" #include "ureg.h"#include "arm.h" #define ISSGI(irq)	((uint)(irq) < Nsgi) enum {	Debug = 0, 	Nvec = 8,		/* # of vectors at start of lexception.s */	Bi2long = BI2BY * sizeof(long),	Nirqs = 1024,	Nsgi =	16,		/* software-generated (inter-processor) intrs */	Nppi =	32,		/* sgis + other private peripheral intrs */}; typedef struct Intrcpuregs Intrcpuregs;typedef struct Intrdistregs Intrdistregs; /* * almost this entire register set is buggered. * the distributor is supposed to be per-system, not per-cpu, * yet some registers are banked per-cpu, as marked. */struct Intrdistregs {			/* distributor */	ulong	ctl;	ulong	ctlrtype;	ulong	distid;	uchar	_pad0[0x80 - 0xc]; 	/* botch: *[0] are banked per-cpu from here */	/* bit maps */	ulong	grp[32];		/* in group 1 (non-secure) */	ulong	setena[32];		/* forward to cpu interfaces */	ulong	clrena[32];	ulong	setpend[32];	ulong	clrpend[32];	ulong	setact[32];		/* active? */	ulong	clract[32];	/* botch: *[0] are banked per-cpu until here */ 	uchar	pri[1020];	/* botch: pri[0] — pri[7] are banked per-cpu */	ulong	_rsrvd1;	/* botch: targ[0] through targ[7] are banked per-cpu and RO */	uchar	targ[1020];	/* byte bit maps: cpu targets indexed by intr */	ulong	_rsrvd2;	/* botch: cfg[1] is banked per-cpu */	ulong	cfg[64];		/* bit pairs: edge? 1-N? */	ulong	_pad1[64];	ulong	nsac[64];		/* bit pairs (v2 only) */ 	/* software-generated intrs (a.k.a. sgi) */	ulong	swgen;			/* intr targets */	uchar	_pad2[0xf10 - 0xf04];	uchar	clrsgipend[16];		/* bit map (v2 only) */	uchar	setsgipend[16];		/* bit map (v2 only) */}; enum {	/* ctl bits */	Forw2cpuif =	1, 	/* ctlrtype bits */	Cpunoshft =	5,	Cpunomask =	MASK(3),	Intrlines =	MASK(5), 	/* cfg bits */	Level =		0<<1,	Edge =		1<<1,		/* edge-, not level-sensitive */	Toall =		0<<0,	To1 =		1<<0,		/* vs. to all */ 	/* swgen bits */	Totargets =	0,	Tonotme =	1<<24,	Tome =		2<<24,}; /* each cpu sees its own registers at the same base address (soc.intr) */struct Intrcpuregs {	ulong	ctl;	ulong	primask; 	ulong	binpt;			/* group pri vs subpri split */	ulong	ack;	ulong	end;	ulong	runpri;	ulong	hipripend; 	/* aliased regs (secure, for group 1) */	ulong	alibinpt;	ulong	aliack;			/* (v2 only) */	ulong	aliend;			/* (v2 only) */	ulong	alihipripend;		/* (v2 only) */ 	uchar	_pad0[0xd0 - 0x2c];	ulong	actpri[4];		/* (v2 only) */	ulong	nsactpri[4];		/* (v2 only) */ 	uchar	_pad0[0xfc - 0xf0];	ulong	ifid;			/* ro */ 	uchar	_pad0[0x1000 - 0x100];	ulong	deact;			/* wo (v2 only) */}; enum {	/* ctl bits */	Enable =	1,	Eoinodeact =	1<<9,		/* (v2 only) */ 	/* (ali) ack/end/hipriend/deact bits */	Intrmask =	MASK(10),	Cpuidshift =	10,	Cpuidmask =	MASK(3), 	/* ifid bits */	Archversshift =	16,	Archversmask =	MASK(4),}; typedef struct Vctl Vctl;typedef struct Vctl {	Vctl*	next;		/* handlers on this vector */	char	*name;		/* of driver, xallocated */	void	(*f)(Ureg*, void*);	/* handler to call */	void*	a;		/* argument to call it with */} Vctl; static Lock vctllock;static Vctl* vctl[Nirqs]; /* *   Layout at virtual address 0. */typedef struct Vpage0 {	void	(*vectors[Nvec])(void);	u32int	vtable[Nvec];} Vpage0; enum{	Ntimevec = 20		/* number of time buckets for each intr */};ulong intrtimes[Nirqs][Ntimevec]; uvlong ninterrupt;uvlong ninterruptticks;int irqtooearly = 1; static ulong shadena[32];	/* copy of enable bits, saved by intcmaskall */static Lock distlock, nintrlock; extern int notify(Ureg*); static void dumpstackwithureg(Ureg *ureg); voidprintrs(int base, ulong word){	int bit; 	for (bit = 0; word; bit++, word >>= 1)		if (word & 1)			iprint(" %d", base + bit);} voiddumpintrs(char *what, ulong *bits){	int i, first, some;	ulong word;	Intrdistregs *idp = (Intrdistregs *)soc.intrdist; 	first = 1;	some = 0;	USED(idp);	for (i = 0; i < nelem(idp->setpend); i++) {		word = bits[i];		if (word) {			if (first) {				first = 0;				iprint("%s", what);			}			some = 1;			printrs(i * Bi2long, word);		}	}	if (!some)		iprint("%s none", what);	iprint("\n");} voiddumpintrpend(void){	Intrdistregs *idp = (Intrdistregs *)soc.intrdist; 	iprint("\ncpu%d gic regs:\n", m->machno);	dumpintrs("group 1", idp->grp);	dumpintrs("enabled", idp->setena);	dumpintrs("pending", idp->setpend);	dumpintrs("active ", idp->setact);} /* *  keep histogram of interrupt service times */voidintrtime(Mach*, int vno){	ulong diff;	ulong x; 	x = perfticks();	diff = x - m->perf.intrts;	m->perf.intrts = x; 	m->perf.inintr += diff;	if(up == nil && m->perf.inidle > diff)		m->perf.inidle -= diff; 	if (m->cpumhz == 0)		return;			/* don't divide by zero */	diff /= m->cpumhz*100;		/* quantum = 100µsec */	if(diff >= Ntimevec)		diff = Ntimevec-1;	if ((uint)vno >= Nirqs)		vno = Nirqs-1;	intrtimes[vno][diff]++;} static ulongintack(Intrcpuregs *icp){	return icp->ack & Intrmask;} static voidintdismiss(Intrcpuregs *icp, ulong ack){	icp->end = ack;	coherence();} static intirqinuse(uint irq){	Intrdistregs *idp = (Intrdistregs *)soc.intrdist; 	return idp->setena[irq / Bi2long] & (1 << (irq % Bi2long));} voidintcunmask(uint irq){	Intrdistregs *idp = (Intrdistregs *)soc.intrdist; 	ilock(&distlock);	idp->setena[irq / Bi2long] = 1 << (irq % Bi2long);	iunlock(&distlock);} voidintcmask(uint irq){	Intrdistregs *idp = (Intrdistregs *)soc.intrdist; 	ilock(&distlock);	idp->clrena[irq / Bi2long] = 1 << (irq % Bi2long);	iunlock(&distlock);} static voidintcmaskall(Intrdistregs *idp)		/* mask all intrs for all cpus */{	int i; 	for (i = 0; i < nelem(idp->setena); i++)		shadena[i] = idp->setena[i];	for (i = 0; i < nelem(idp->clrena); i++)		idp->clrena[i] = ~0;	coherence();} static voidintcunmaskall(Intrdistregs *idp)	/* unused */{	int i; 	for (i = 0; i < nelem(idp->setena); i++)		idp->setena[i] = shadena[i];	coherence();} static ulongpermintrs(Intrdistregs *idp, int base, int r){	ulong perms; 	idp->clrena[r] = ~0;		/* disable all */	coherence();	perms = idp->clrena[r];	if (perms) {		iprint("perm intrs:");		printrs(base, perms);		iprint("\n");	}	return perms;} static voidintrcfg(Intrdistregs *idp){	int i, cpumask;	ulong pat; 	/* set up all interrupts as level-sensitive, to one cpu (0) */	pat = 0;	for (i = 0; i < Bi2long; i += 2)		pat |= (Level | To1) << i; 	if (m->machno == 0) {			/* system-wide & cpu0 cfg */		for (i = 0; i < nelem(idp->grp); i++)			idp->grp[i] = 0;		/* secure */		for (i = 0; i < nelem(idp->pri); i++)			idp->pri[i] = 0;		/* highest priority */		/* set up all interrupts as level-sensitive, to one cpu (0) */		for (i = 0; i < nelem(idp->cfg); i++)			idp->cfg[i] = pat;		/* first Nppi are read-only for SGIs and PPIs */		cpumask = 1<<0;				/* just cpu 0 */		navailcpus = getncpus();		for (i = Nppi; i < sizeof idp->targ; i++)			idp->targ[i] = cpumask;		coherence(); 		intcmaskall(idp);		for (i = 0; i < nelem(idp->clrena); i++) {			// permintrs(idp, i * Bi2long, i);			idp->clrpend[i] = idp->clract[i] = idp->clrena[i] = ~0;		}	} else {				/* per-cpu config */		idp->grp[0] = 0;		/* secure */		for (i = 0; i < 8; i++)			idp->pri[i] = 0;	/* highest priority */		/* idp->targ[0 through Nppi-1] are supposed to be read-only */		for (i = 0; i < Nppi; i++)			idp->targ[i] = 1<<m->machno;		idp->cfg[1] = pat;		coherence(); 		// permintrs(idp, i * Bi2long, i);		idp->clrpend[0] = idp->clract[0] = idp->clrena[0] = ~0;		/* on cpu1, irq Extpmuirq (118) is always pending here */	}	coherence();} voidintrto(int cpu, int irq){	Intrdistregs *idp = (Intrdistregs *)soc.intrdist; 	/* first Nppi are read-only for SGIs and the like */	ilock(&distlock);	idp->targ[irq] = 1 << cpu;	iunlock(&distlock);} voidintrsto(int cpu)			/* unused */{	int i;	Intrdistregs *idp = (Intrdistregs *)soc.intrdist; 	/* first Nppi are read-only for SGIs and the like */	for (i = Nppi; i < sizeof idp->targ; i++)		intrto(cpu, i);	USED(idp);} voidintrcpu(int cpu){	Intrdistregs *idp = (Intrdistregs *)soc.intrdist; 	ilock(&distlock);	idp->swgen = Totargets | 1 << (cpu + 16) | m->machno;	iunlock(&distlock);} /* *  set up for exceptions */voidtrapinit(void){	int s;	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;	Intrcpuregs *icp = (Intrcpuregs *)soc.intr;	Vpage0 *vpage0;	enum { Vecsize = sizeof vpage0->vectors + sizeof vpage0->vtable, }; 	/*	 * set up the exception vectors, high and low.	 *	 * we can't use cache ops on HVECTORS address, since they	 * work on virtual addresses, and only those that have a	 * physical address == PADDR(virtual).	 */	if (m->machno == 0) {		vpage0 = (Vpage0*)HVECTORS;		memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));		memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable)); 		vpage0 = (Vpage0*)KADDR(0);		memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));		memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable)); 		allcache->wbse(vpage0, Vecsize);		cacheiinv();	} 	/*	 * set up the stack pointers for the exception modes for this cpu.	 * they point to small `save areas' in Mach, not actual stacks.	 */	s = splhi();			/* make these modes ignore intrs too */	setr13(PsrMfiq, m->sfiq);	setr13(PsrMirq, m->sirq);	setr13(PsrMmon, m->smon);	setr13(PsrMabt, m->sabt);	setr13(PsrMund, m->sund);	setr13(PsrMsys, m->ssys);	splx(s); 	assert((idp->distid & MASK(12)) == 0x43b);	/* made by arm */	assert((icp->ifid   & MASK(12)) == 0x43b);	/* made by arm */ 	ilock(&distlock);	idp->ctl = 0;	icp->ctl = 0;	coherence(); 	intrcfg(idp);			/* some per-cpu cfg here */ 	icp->ctl = Enable;	icp->primask = (uchar)~0;	/* let all priorities through */	coherence(); 	idp->ctl = Forw2cpuif;	iunlock(&distlock);} voidintrsoff(void){	ilock(&distlock);	intcmaskall((Intrdistregs *)soc.intrdist);	iunlock(&distlock);} voidintrcpushutdown(void){	Intrcpuregs *icp = (Intrcpuregs *)soc.intr; 	icp->ctl = 0;	icp->primask = 0;	/* let no priorities through */

Lines 1–500 of 1094.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t