changelog shortlog tags branches changeset file revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/bcm/irq.c

revision 7150: 94aebeed6c4a
child 7197: babef06a3de5
     1.1new file mode 100644
     1.2--- /dev/null
     1.3+++ b/sys/src/9/bcm/irq.c
     1.4@@ -0,0 +1,166 @@
     1.5+#include "u.h"
     1.6+#include "../port/lib.h"
     1.7+#include "mem.h"
     1.8+#include "dat.h"
     1.9+#include "fns.h"
    1.10+#include "io.h"
    1.11+#include "ureg.h"
    1.12+#include "../port/error.h"
    1.13+
    1.14+#define INTREGS		(VIRTIO+0xB200)
    1.15+
    1.16+enum {
    1.17+	Fiqenable = 1<<7,
    1.18+
    1.19+	Localtimerint	= 0x40,
    1.20+	Localmboxint	= 0x50,
    1.21+	Localintpending	= 0x60,
    1.22+};
    1.23+
    1.24+/*
    1.25+ * interrupt control registers
    1.26+ */
    1.27+typedef struct Intregs Intregs;
    1.28+struct Intregs {
    1.29+	u32int	ARMpending;
    1.30+	u32int	GPUpending[2];
    1.31+	u32int	FIQctl;
    1.32+	u32int	GPUenable[2];
    1.33+	u32int	ARMenable;
    1.34+	u32int	GPUdisable[2];
    1.35+	u32int	ARMdisable;
    1.36+};
    1.37+
    1.38+typedef struct Vctl Vctl;
    1.39+struct Vctl {
    1.40+	Vctl	*next;
    1.41+	int	irq;
    1.42+	u32int	*reg;
    1.43+	u32int	mask;
    1.44+	void	(*f)(Ureg*, void*);
    1.45+	void	*a;
    1.46+};
    1.47+
    1.48+static Lock vctllock;
    1.49+static Vctl *vctl[MAXMACH], *vfiq;
    1.50+
    1.51+void
    1.52+intrcpushutdown(void)
    1.53+{
    1.54+	u32int *enable;
    1.55+
    1.56+	if(soc.armlocal == 0)
    1.57+		return;
    1.58+	enable = (u32int*)(ARMLOCAL + Localtimerint) + m->machno;
    1.59+	*enable = 0;
    1.60+	if(m->machno){
    1.61+		enable = (u32int*)(ARMLOCAL + Localmboxint) + m->machno;
    1.62+		*enable = 1;
    1.63+	}
    1.64+}
    1.65+
    1.66+void
    1.67+intrsoff(void)
    1.68+{
    1.69+	Intregs *ip;
    1.70+	int disable;
    1.71+
    1.72+	ip = (Intregs*)INTREGS;
    1.73+	disable = ~0;
    1.74+	ip->GPUdisable[0] = disable;
    1.75+	ip->GPUdisable[1] = disable;
    1.76+	ip->ARMdisable = disable;
    1.77+	ip->FIQctl = 0;
    1.78+}
    1.79+
    1.80+/*
    1.81+ *  called by trap to handle irq interrupts.
    1.82+ *  returns true iff a clock interrupt, thus maybe reschedule.
    1.83+ */
    1.84+int
    1.85+irq(Ureg* ureg)
    1.86+{
    1.87+	Vctl *v;
    1.88+	int clockintr;
    1.89+
    1.90+	clockintr = 0;
    1.91+	for(v = vctl[m->machno]; v != nil; v = v->next)
    1.92+		if((*v->reg & v->mask) != 0){
    1.93+			coherence();
    1.94+			v->f(ureg, v->a);
    1.95+			coherence();
    1.96+			if(v->irq == IRQclock || v->irq == IRQcntps || v->irq == IRQcntpns)
    1.97+				clockintr = 1;
    1.98+		}
    1.99+	return clockintr;
   1.100+}
   1.101+
   1.102+/*
   1.103+ * called direct from lexception.s to handle fiq interrupt.
   1.104+ */
   1.105+void
   1.106+fiq(Ureg *ureg)
   1.107+{
   1.108+	Vctl *v;
   1.109+
   1.110+	v = vfiq;
   1.111+	if(v == nil)
   1.112+		panic("cpu%d: unexpected item in bagging area", m->machno);
   1.113+	m->intr++;
   1.114+	ureg->pc -= 4;
   1.115+	coherence();
   1.116+	v->f(ureg, v->a);
   1.117+	coherence();
   1.118+}
   1.119+
   1.120+void
   1.121+irqenable(int irq, void (*f)(Ureg*, void*), void* a)
   1.122+{
   1.123+	Vctl *v;
   1.124+	Intregs *ip;
   1.125+	u32int *enable;
   1.126+	int cpu;
   1.127+
   1.128+	ip = (Intregs*)INTREGS;
   1.129+	if((v = xalloc(sizeof(Vctl))) == nil)
   1.130+		panic("irqenable: no mem");
   1.131+	cpu = 0;
   1.132+	v->irq = irq;
   1.133+	if(irq >= IRQlocal){
   1.134+		cpu = m->machno;
   1.135+		v->reg = (u32int*)(ARMLOCAL + Localintpending) + cpu;
   1.136+		if(irq >= IRQmbox0)
   1.137+			enable = (u32int*)(ARMLOCAL + Localmboxint) + cpu;
   1.138+		else
   1.139+			enable = (u32int*)(ARMLOCAL + Localtimerint) + cpu;
   1.140+		v->mask = 1 << (irq - IRQlocal);
   1.141+	}else if(irq >= IRQbasic){
   1.142+		enable = &ip->ARMenable;
   1.143+		v->reg = &ip->ARMpending;
   1.144+		v->mask = 1 << (irq - IRQbasic);
   1.145+	}else{
   1.146+		enable = &ip->GPUenable[irq/32];
   1.147+		v->reg = &ip->GPUpending[irq/32];
   1.148+		v->mask = 1 << (irq % 32);
   1.149+	}
   1.150+	v->f = f;
   1.151+	v->a = a;
   1.152+	lock(&vctllock);
   1.153+	if(irq == IRQfiq){
   1.154+		assert((ip->FIQctl & Fiqenable) == 0);
   1.155+		assert((*enable & v->mask) == 0);
   1.156+		vfiq = v;
   1.157+		ip->FIQctl = Fiqenable | irq;
   1.158+	}else{
   1.159+		v->next = vctl[cpu];
   1.160+		vctl[cpu] = v;
   1.161+		if(irq >= IRQmbox0){
   1.162+			if(irq <= IRQmbox3)
   1.163+				*enable |= 1 << (irq - IRQmbox0);
   1.164+		}else if(irq >= IRQlocal)
   1.165+			*enable |= 1 << (irq - IRQlocal);
   1.166+		else
   1.167+			*enable = v->mask;
   1.168+	}
   1.169+	unlock(&vctllock);
   1.170+}