123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "m8260.h"
- #include "../port/error.h"
- enum{
- IRQ0 = 18,
- Level = 0,
- Edge = 1,
- };
- enum{
- Qdir,
- Qirq1,
- Qirq2,
- Qirq3,
- Qirq4,
- Qirq5,
- Qirq6,
- Qirq7,
- Qmstimer,
- Qfpgareset,
- NIRQ,
- };
- static Dirtab irqdir[]={
- ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
- "irq1", {Qirq1}, 0, 0666,
- "irq2", {Qirq2}, 0, 0666,
- "irq3", {Qirq1}, 0, 0666,
- "irq4", {Qirq1}, 0, 0666,
- "irq5", {Qirq1}, 0, 0666,
- "irq6", {Qirq1}, 0, 0666,
- "irq7", {Qirq1}, 0, 0666,
- "mstimer", {Qmstimer}, 0, 0666,
- "fpgareset", {Qfpgareset}, 0, 0222,
- };
- enum
- {
- CMinterrupt,
- CMmode,
- CMreset,
- CMwait,
- CMdebug,
- };
- Cmdtab irqmsg[] =
- {
- CMinterrupt, "interrupt", 2,
- CMmode, "mode", 2,
- CMreset, "reset", 1,
- CMwait, "wait", 1,
- CMdebug, "debug", 1,
- };
- typedef struct Irqconfig Irqconfig;
- struct Irqconfig {
- int intenable; /* Interrupts are enabled */
- int mode; /* level == 0; edge == 1 */
- ulong interrupts; /* Count interrupts */
- ulong sleepints; /* interrupt count when waiting */
- Rendez r; /* Rendez-vous point for interrupt waiting */
- Irqconfig *next;
- Timer;
- };
- Irqconfig *irqconfig[NIRQ]; /* irqconfig[0] is not used */
- Lock irqlock;
- static void interrupt(Ureg*, void*);
- void dumpvno(void);
- static void
- ticmstimer(Ureg*, Timer *t)
- {
- Irqconfig *ic;
- ic = t->ta;
- ic->interrupts++;
- wakeup(&ic->r);
- }
- void
- irqenable(Irqconfig *ic, int irq)
- {
- /* call with ilock(&irqlock) held */
- if (ic->intenable)
- return;
- if (irq == Qmstimer){
- if (ic->tnext == nil)
- ic->tns = MS2NS(ic->mode);
- ic->tmode = Tperiodic;
- timeradd(&ic->Timer);
- }else{
- if (irqconfig[irq]){
- ic->next = irqconfig[irq];
- irqconfig[irq] = ic;
- }else{
- ic->next = nil;
- irqconfig[irq] = ic;
- intrenable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
- }
- }
- ic->intenable = 1;
- }
- void
- irqdisable(Irqconfig *ic, int irq)
- {
- Irqconfig **pic;
- /* call with ilock(&irqlock) held */
- if (ic->intenable == 0)
- return;
- if (irq == Qmstimer){
- timerdel(&ic->Timer);
- }else{
- for(pic = &irqconfig[irq]; *pic != ic; pic = &(*pic)->next)
- assert(*pic);
- *pic = (*pic)->next;
- if (irqconfig[irq] == nil)
- intrdisable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
- }
- ic->intenable = 0;
- }
- static Chan*
- irqattach(char *spec)
- {
- return devattach('b', spec);
- }
- static Walkqid*
- irqwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name,nname, irqdir, nelem(irqdir), devgen);
- }
- static int
- irqstat(Chan *c, uchar *dp, int n)
- {
- return devstat(c, dp, n, irqdir, nelem(irqdir), devgen);
- }
- static Chan*
- irqopen(Chan *c, int omode)
- {
- Irqconfig *ic;
- int irq;
- irq = (ulong)c->qid.path;
- if(irq != Qdir){
- ic = mallocz(sizeof(Irqconfig), 1);
- ic->tf = ticmstimer;
- ic->ta = ic;
- if (irq == Qmstimer)
- ic->mode = 1000;
- c->aux = ic;
- }
- return devopen(c, omode, irqdir, nelem(irqdir), devgen);
- }
- static void
- irqclose(Chan *c)
- {
- int irq;
- Irqconfig *ic;
- irq = (ulong)c->qid.path;
- if(irq == Qdir)
- return;
- ic = c->aux;
- if (irq > Qmstimer)
- return;
- ilock(&irqlock);
- irqdisable(ic, irq);
- iunlock(&irqlock);
- free(ic);
- }
- static int
- irqtfn(void *arg)
- {
- Irqconfig *ic;
- ic = arg;
- return ic->sleepints != ic->interrupts;
- }
- static long
- irqread(Chan *c, void *buf, long n, vlong)
- {
- int irq;
- Irqconfig *ic;
- char tmp[24];
- if(n <= 0)
- return n;
- irq = (ulong)c->qid.path;
- if(irq == Qdir)
- return devdirread(c, buf, n, irqdir, nelem(irqdir), devgen);
- if(irq > Qmstimer){
- print("irqread 0x%llux\n", c->qid.path);
- error(Egreg);
- }
- ic = c->aux;
- if (ic->intenable == 0)
- error("disabled");
- ic->sleepints = ic->interrupts;
- sleep(&ic->r, irqtfn, ic);
- if (irq == Qmstimer)
- snprint(tmp, sizeof tmp, "%11lud %d", ic->interrupts, ic->mode);
- else
- snprint(tmp, sizeof tmp, "%11lud %s", ic->interrupts, ic->mode ?"edge":"level");
- n = readstr(0, buf, n, tmp);
- return n;
- }
- static long
- irqwrite(Chan *c, void *a, long n, vlong)
- {
- int irq;
- Irqconfig *ic;
- Cmdbuf *cb;
- Cmdtab *ct;
- if(n <= 0)
- return n;
- irq = (ulong)c->qid.path;
- if(irq <= 0 || irq >= nelem(irqdir)){
- print("irqwrite 0x%llux\n", c->qid.path);
- error(Egreg);
- }
- if (irq == Qfpgareset){
- if (strncmp(a, "reset", 5) == 0)
- fpgareset();
- else
- error(Egreg);
- return n;
- }
- ic = c->aux;
- cb = parsecmd(a, n);
- if(waserror()) {
- free(cb);
- nexterror();
- }
- ct = lookupcmd(cb, irqmsg, nelem(irqmsg));
- switch(ct->index) {
- case CMinterrupt:
- /* Turn interrupts on or off */
- if (strcmp(cb->f[1], "on") == 0){
- ilock(&irqlock);
- irqenable(ic, irq);
- iomem->siprr = 0x65009770;
- iunlock(&irqlock);
- }else if (strcmp(cb->f[1], "off") == 0){
- ilock(&irqlock);
- irqdisable(ic, irq);
- iunlock(&irqlock);
- }else
- error(Ebadarg);
- break;
- case CMmode:
- /* Set mode */
- if (irq == Qmstimer){
- ic->mode = strtol(cb->f[1], nil, 0);
- if (ic->mode <= 0){
- ic->tns = MS2NS(1000);
- ic->mode = 1000;
- error(Ebadarg);
- }
- ic->tns = MS2NS(ic->mode);
- }else if (strcmp(cb->f[1], "level") == 0){
- ic->mode = Level;
- iomem->siexr &= ~(0x8000 >> irq);
- }else if (strcmp(cb->f[1], "edge") == 0){
- ic->mode = Edge;
- iomem->siexr |= 0x8000 >> irq;
- }else
- error(Ebadarg);
- break;
- case CMreset:
- ic->interrupts = 0;
- break;
- case CMwait:
- if (ic->intenable == 0)
- error("interrupts are off");
- ic->sleepints = ic->interrupts;
- sleep(&ic->r, irqtfn, ic);
- break;
- case CMdebug:
- print("simr h/l 0x%lux/0x%lux, sipnr h/l 0x%lux/0x%lux, siexr 0x%lux, siprr 0x%lux\n",
- iomem->simr_h, iomem->simr_l,
- iomem->sipnr_h, iomem->sipnr_l,
- iomem->siexr, iomem->siprr);
- dumpvno();
- }
- poperror();
- free(cb);
- /* Irqi */
- return n;
- }
- static void
- interrupt(Ureg*, void *arg)
- {
- Irqconfig **pic, *ic;
- int irq;
- pic = arg;
- irq = pic - irqconfig;
- if (irq <= 0 || irq > nelem(irqdir)){
- print("Unexpected interrupt: %d\n", irq);
- return;
- }
- ilock(&irqlock);
- if (irq <= Qirq7)
- iomem->sipnr_h |= 0x8000 >> irq; /* Clear the interrupt */
- for(ic = *pic; ic; ic = ic->next){
- ic->interrupts++;
- wakeup(&ic->r);
- }
- iunlock(&irqlock);
- }
- Dev irqdevtab = {
- 'b',
- "irq",
- devreset,
- devinit,
- devshutdown,
- irqattach,
- irqwalk,
- irqstat,
- irqopen,
- devcreate,
- irqclose,
- irqread,
- devbread,
- irqwrite,
- devbwrite,
- devremove,
- devwstat,
- };
|