devirq.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "m8260.h"
  7. #include "../port/error.h"
  8. enum{
  9. IRQ0 = 18,
  10. Level = 0,
  11. Edge = 1,
  12. };
  13. enum{
  14. Qdir,
  15. Qirq1,
  16. Qirq2,
  17. Qirq3,
  18. Qirq4,
  19. Qirq5,
  20. Qirq6,
  21. Qirq7,
  22. Qmstimer,
  23. Qfpgareset,
  24. NIRQ,
  25. };
  26. static Dirtab irqdir[]={
  27. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  28. "irq1", {Qirq1}, 0, 0666,
  29. "irq2", {Qirq2}, 0, 0666,
  30. "irq3", {Qirq1}, 0, 0666,
  31. "irq4", {Qirq1}, 0, 0666,
  32. "irq5", {Qirq1}, 0, 0666,
  33. "irq6", {Qirq1}, 0, 0666,
  34. "irq7", {Qirq1}, 0, 0666,
  35. "mstimer", {Qmstimer}, 0, 0666,
  36. "fpgareset", {Qfpgareset}, 0, 0222,
  37. };
  38. enum
  39. {
  40. CMinterrupt,
  41. CMmode,
  42. CMreset,
  43. CMwait,
  44. CMdebug,
  45. };
  46. Cmdtab irqmsg[] =
  47. {
  48. CMinterrupt, "interrupt", 2,
  49. CMmode, "mode", 2,
  50. CMreset, "reset", 1,
  51. CMwait, "wait", 1,
  52. CMdebug, "debug", 1,
  53. };
  54. typedef struct Irqconfig Irqconfig;
  55. struct Irqconfig {
  56. int intenable; /* Interrupts are enabled */
  57. int mode; /* level == 0; edge == 1 */
  58. ulong interrupts; /* Count interrupts */
  59. ulong sleepints; /* interrupt count when waiting */
  60. Rendez r; /* Rendez-vous point for interrupt waiting */
  61. Irqconfig *next;
  62. Timer;
  63. };
  64. Irqconfig *irqconfig[NIRQ]; /* irqconfig[0] is not used */
  65. Lock irqlock;
  66. static void interrupt(Ureg*, void*);
  67. void dumpvno(void);
  68. static void
  69. ticmstimer(Ureg*, Timer *t)
  70. {
  71. Irqconfig *ic;
  72. ic = t->ta;
  73. ic->interrupts++;
  74. wakeup(&ic->r);
  75. }
  76. void
  77. irqenable(Irqconfig *ic, int irq)
  78. {
  79. /* call with ilock(&irqlock) held */
  80. if (ic->intenable)
  81. return;
  82. if (irq == Qmstimer){
  83. if (ic->tnext == nil)
  84. ic->tns = MS2NS(ic->mode);
  85. ic->tmode = Tperiodic;
  86. timeradd(&ic->Timer);
  87. }else{
  88. if (irqconfig[irq]){
  89. ic->next = irqconfig[irq];
  90. irqconfig[irq] = ic;
  91. }else{
  92. ic->next = nil;
  93. irqconfig[irq] = ic;
  94. intrenable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
  95. }
  96. }
  97. ic->intenable = 1;
  98. }
  99. void
  100. irqdisable(Irqconfig *ic, int irq)
  101. {
  102. Irqconfig **pic;
  103. /* call with ilock(&irqlock) held */
  104. if (ic->intenable == 0)
  105. return;
  106. if (irq == Qmstimer){
  107. timerdel(&ic->Timer);
  108. }else{
  109. for(pic = &irqconfig[irq]; *pic != ic; pic = &(*pic)->next)
  110. assert(*pic);
  111. *pic = (*pic)->next;
  112. if (irqconfig[irq] == nil)
  113. intrdisable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
  114. }
  115. ic->intenable = 0;
  116. }
  117. static Chan*
  118. irqattach(char *spec)
  119. {
  120. return devattach('b', spec);
  121. }
  122. static Walkqid*
  123. irqwalk(Chan *c, Chan *nc, char **name, int nname)
  124. {
  125. return devwalk(c, nc, name,nname, irqdir, nelem(irqdir), devgen);
  126. }
  127. static int
  128. irqstat(Chan *c, uchar *dp, int n)
  129. {
  130. return devstat(c, dp, n, irqdir, nelem(irqdir), devgen);
  131. }
  132. static Chan*
  133. irqopen(Chan *c, int omode)
  134. {
  135. Irqconfig *ic;
  136. int irq;
  137. irq = (ulong)c->qid.path;
  138. if(irq != Qdir){
  139. ic = mallocz(sizeof(Irqconfig), 1);
  140. ic->tf = ticmstimer;
  141. ic->ta = ic;
  142. if (irq == Qmstimer)
  143. ic->mode = 1000;
  144. c->aux = ic;
  145. }
  146. return devopen(c, omode, irqdir, nelem(irqdir), devgen);
  147. }
  148. static void
  149. irqclose(Chan *c)
  150. {
  151. int irq;
  152. Irqconfig *ic;
  153. irq = (ulong)c->qid.path;
  154. if(irq == Qdir)
  155. return;
  156. ic = c->aux;
  157. if (irq > Qmstimer)
  158. return;
  159. ilock(&irqlock);
  160. irqdisable(ic, irq);
  161. iunlock(&irqlock);
  162. free(ic);
  163. }
  164. static int
  165. irqtfn(void *arg)
  166. {
  167. Irqconfig *ic;
  168. ic = arg;
  169. return ic->sleepints != ic->interrupts;
  170. }
  171. static long
  172. irqread(Chan *c, void *buf, long n, vlong)
  173. {
  174. int irq;
  175. Irqconfig *ic;
  176. char tmp[24];
  177. if(n <= 0)
  178. return n;
  179. irq = (ulong)c->qid.path;
  180. if(irq == Qdir)
  181. return devdirread(c, buf, n, irqdir, nelem(irqdir), devgen);
  182. if(irq > Qmstimer){
  183. print("irqread 0x%llux\n", c->qid.path);
  184. error(Egreg);
  185. }
  186. ic = c->aux;
  187. if (ic->intenable == 0)
  188. error("disabled");
  189. ic->sleepints = ic->interrupts;
  190. sleep(&ic->r, irqtfn, ic);
  191. if (irq == Qmstimer)
  192. snprint(tmp, sizeof tmp, "%11lud %d", ic->interrupts, ic->mode);
  193. else
  194. snprint(tmp, sizeof tmp, "%11lud %s", ic->interrupts, ic->mode ?"edge":"level");
  195. n = readstr(0, buf, n, tmp);
  196. return n;
  197. }
  198. static long
  199. irqwrite(Chan *c, void *a, long n, vlong)
  200. {
  201. int irq;
  202. Irqconfig *ic;
  203. Cmdbuf *cb;
  204. Cmdtab *ct;
  205. if(n <= 0)
  206. return n;
  207. irq = (ulong)c->qid.path;
  208. if(irq <= 0 || irq >= nelem(irqdir)){
  209. print("irqwrite 0x%llux\n", c->qid.path);
  210. error(Egreg);
  211. }
  212. if (irq == Qfpgareset){
  213. if (strncmp(a, "reset", 5) == 0)
  214. fpgareset();
  215. else
  216. error(Egreg);
  217. return n;
  218. }
  219. ic = c->aux;
  220. cb = parsecmd(a, n);
  221. if(waserror()) {
  222. free(cb);
  223. nexterror();
  224. }
  225. ct = lookupcmd(cb, irqmsg, nelem(irqmsg));
  226. switch(ct->index) {
  227. case CMinterrupt:
  228. /* Turn interrupts on or off */
  229. if (strcmp(cb->f[1], "on") == 0){
  230. ilock(&irqlock);
  231. irqenable(ic, irq);
  232. iomem->siprr = 0x65009770;
  233. iunlock(&irqlock);
  234. }else if (strcmp(cb->f[1], "off") == 0){
  235. ilock(&irqlock);
  236. irqdisable(ic, irq);
  237. iunlock(&irqlock);
  238. }else
  239. error(Ebadarg);
  240. break;
  241. case CMmode:
  242. /* Set mode */
  243. if (irq == Qmstimer){
  244. ic->mode = strtol(cb->f[1], nil, 0);
  245. if (ic->mode <= 0){
  246. ic->tns = MS2NS(1000);
  247. ic->mode = 1000;
  248. error(Ebadarg);
  249. }
  250. ic->tns = MS2NS(ic->mode);
  251. }else if (strcmp(cb->f[1], "level") == 0){
  252. ic->mode = Level;
  253. iomem->siexr &= ~(0x8000 >> irq);
  254. }else if (strcmp(cb->f[1], "edge") == 0){
  255. ic->mode = Edge;
  256. iomem->siexr |= 0x8000 >> irq;
  257. }else
  258. error(Ebadarg);
  259. break;
  260. case CMreset:
  261. ic->interrupts = 0;
  262. break;
  263. case CMwait:
  264. if (ic->intenable == 0)
  265. error("interrupts are off");
  266. ic->sleepints = ic->interrupts;
  267. sleep(&ic->r, irqtfn, ic);
  268. break;
  269. case CMdebug:
  270. print("simr h/l 0x%lux/0x%lux, sipnr h/l 0x%lux/0x%lux, siexr 0x%lux, siprr 0x%lux\n",
  271. iomem->simr_h, iomem->simr_l,
  272. iomem->sipnr_h, iomem->sipnr_l,
  273. iomem->siexr, iomem->siprr);
  274. dumpvno();
  275. }
  276. poperror();
  277. free(cb);
  278. /* Irqi */
  279. return n;
  280. }
  281. static void
  282. interrupt(Ureg*, void *arg)
  283. {
  284. Irqconfig **pic, *ic;
  285. int irq;
  286. pic = arg;
  287. irq = pic - irqconfig;
  288. if (irq <= 0 || irq > nelem(irqdir)){
  289. print("Unexpected interrupt: %d\n", irq);
  290. return;
  291. }
  292. ilock(&irqlock);
  293. if (irq <= Qirq7)
  294. iomem->sipnr_h |= 0x8000 >> irq; /* Clear the interrupt */
  295. for(ic = *pic; ic; ic = ic->next){
  296. ic->interrupts++;
  297. wakeup(&ic->r);
  298. }
  299. iunlock(&irqlock);
  300. }
  301. Dev irqdevtab = {
  302. 'b',
  303. "irq",
  304. devreset,
  305. devinit,
  306. devshutdown,
  307. irqattach,
  308. irqwalk,
  309. irqstat,
  310. irqopen,
  311. devcreate,
  312. irqclose,
  313. irqread,
  314. devbread,
  315. irqwrite,
  316. devbwrite,
  317. devremove,
  318. devwstat,
  319. };