devirq.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. Rendez r; /* Rendez-vous point for interrupt waiting */
  60. Irqconfig *next;
  61. Timer;
  62. };
  63. Irqconfig *irqconfig[NIRQ]; /* irqconfig[0] is not used */
  64. Lock irqlock;
  65. static void interrupt(Ureg*, void*);
  66. static void ticmstimer(Ureg*, Timer*);
  67. static void
  68. ticmstimer(Ureg*, Timer *t)
  69. {
  70. Irqconfig *ic;
  71. ic = t->ta;
  72. ic->interrupts++;
  73. wakeup(&ic->r);
  74. }
  75. void
  76. irqenable(Irqconfig *ic, int irq)
  77. {
  78. /* call with ilock(&irqlock) held */
  79. if (ic->intenable)
  80. return;
  81. if (irq == Qmstimer){
  82. if (ic->tnext == nil)
  83. ic->tns = MS2NS(ic->mode);
  84. ic->tmode = Tperiodic;
  85. timeradd(&ic->Timer);
  86. }else{
  87. if (irqconfig[irq]){
  88. ic->next = irqconfig[irq];
  89. irqconfig[irq] = ic;
  90. }else{
  91. ic->next = nil;
  92. irqconfig[irq] = ic;
  93. intrenable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
  94. }
  95. }
  96. ic->intenable = 1;
  97. }
  98. void
  99. irqdisable(Irqconfig *ic, int irq)
  100. {
  101. Irqconfig **pic;
  102. /* call with ilock(&irqlock) held */
  103. if (ic->intenable == 0)
  104. return;
  105. if (irq == Qmstimer){
  106. timerdel(&ic->Timer);
  107. }else{
  108. for(pic = &irqconfig[irq]; *pic != ic; pic = &(*pic)->next)
  109. assert(*pic);
  110. *pic = (*pic)->next;
  111. if (irqconfig[irq] == nil)
  112. intrdisable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
  113. }
  114. ic->intenable = 0;
  115. }
  116. static Chan*
  117. irqattach(char *spec)
  118. {
  119. return devattach('b', spec);
  120. }
  121. static Walkqid*
  122. irqwalk(Chan *c, Chan *nc, char **name, int nname)
  123. {
  124. return devwalk(c, nc, name,nname, irqdir, nelem(irqdir), devgen);
  125. }
  126. static int
  127. irqstat(Chan *c, uchar *dp, int n)
  128. {
  129. return devstat(c, dp, n, irqdir, nelem(irqdir), devgen);
  130. }
  131. static Chan*
  132. irqopen(Chan *c, int omode)
  133. {
  134. Irqconfig *ic;
  135. int irq;
  136. irq = (ulong)c->qid.path;
  137. if(irq != Qdir){
  138. ic = mallocz(sizeof(Irqconfig), 1);
  139. ic->tf = ticmstimer;
  140. ic->ta = ic;
  141. if (irq == Qmstimer)
  142. ic->mode = 1000;
  143. c->aux = ic;
  144. }
  145. return devopen(c, omode, irqdir, nelem(irqdir), devgen);
  146. }
  147. static void
  148. irqclose(Chan *c)
  149. {
  150. int irq;
  151. Irqconfig *ic;
  152. irq = (ulong)c->qid.path;
  153. if(irq == Qdir)
  154. return;
  155. ic = c->aux;
  156. if (irq > Qmstimer)
  157. return;
  158. ilock(&irqlock);
  159. irqdisable(ic, irq);
  160. iunlock(&irqlock);
  161. free(ic);
  162. }
  163. static long
  164. irqread(Chan *c, void *buf, long n, vlong)
  165. {
  166. int irq;
  167. Irqconfig *ic;
  168. char tmp[24];
  169. if(n <= 0)
  170. return n;
  171. irq = (ulong)c->qid.path;
  172. if(irq == Qdir)
  173. return devdirread(c, buf, n, irqdir, nelem(irqdir), devgen);
  174. if(irq >= Qmstimer){
  175. print("irqread 0x%llux\n", c->qid.path);
  176. error(Egreg);
  177. }
  178. ic = c->aux;
  179. if (ic->intenable == 0)
  180. error("disabled");
  181. sleep(&ic->r, return0, 0);
  182. if (irq == Qmstimer)
  183. snprint(tmp, sizeof tmp, "%11lud %d", ic->interrupts, ic->mode);
  184. else
  185. snprint(tmp, sizeof tmp, "%11lud %s", ic->interrupts, ic->mode?"edge":"level");
  186. n = readstr(0, buf, n, tmp);
  187. return n;
  188. }
  189. static long
  190. irqwrite(Chan *c, void *a, long n, vlong)
  191. {
  192. int irq;
  193. Irqconfig *ic;
  194. Cmdbuf *cb;
  195. Cmdtab *ct;
  196. if(n <= 0)
  197. return n;
  198. irq = (ulong)c->qid.path;
  199. if(irq <= 0 || irq >= nelem(irqdir)){
  200. print("irqwrite 0x%llux\n", c->qid.path);
  201. error(Egreg);
  202. }
  203. if (irq == Qfpgareset){
  204. if (strncmp(a, "reset", 5) == 0)
  205. fpgareset();
  206. else
  207. error(Egreg);
  208. return n;
  209. }
  210. ic = c->aux;
  211. cb = parsecmd(a, n);
  212. if(waserror()) {
  213. free(cb);
  214. nexterror();
  215. }
  216. ct = lookupcmd(cb, irqmsg, nelem(irqmsg));
  217. switch(ct->index) {
  218. case CMinterrupt:
  219. /* Turn interrupts on or off */
  220. if (strcmp(cb->f[1], "on") == 0){
  221. ilock(&irqlock);
  222. irqenable(ic, irq);
  223. iunlock(&irqlock);
  224. }else if (strcmp(cb->f[1], "off") == 0){
  225. ilock(&irqlock);
  226. irqdisable(ic, irq);
  227. iunlock(&irqlock);
  228. }else
  229. error(Ebadarg);
  230. break;
  231. case CMmode:
  232. /* Set mode */
  233. if (irq == Qmstimer){
  234. ic->mode = strtol(cb->f[1], nil, 0);
  235. if (ic->mode <= 0){
  236. ic->tns = MS2NS(1000);
  237. ic->mode = 1000;
  238. error(Ebadarg);
  239. }
  240. ic->tns = MS2NS(ic->mode);
  241. }else if (strcmp(cb->f[1], "level") == 0){
  242. ic->mode = 0;
  243. iomem->siexr &= ~(0x8000 >> irq);
  244. }else if (strcmp(cb->f[1], "edge") == 0){
  245. ic->mode = 1;
  246. iomem->siexr |= 0x8000 >> irq;
  247. }else
  248. error(Ebadarg);
  249. break;
  250. case CMreset:
  251. ic->interrupts = 0;
  252. break;
  253. case CMwait:
  254. if (ic->intenable == 0)
  255. error("interrupts are off");
  256. sleep(&ic->r, return0, 0);
  257. break;
  258. case CMdebug:
  259. print("simr h/l 0x%lux/0x%lux, sipnr h/l 0x%lux/0x%lux, siexr 0x%lux\n",
  260. iomem->simr_h, iomem->simr_l,
  261. iomem->sipnr_h, iomem->sipnr_l,
  262. iomem->siexr);
  263. }
  264. poperror();
  265. free(cb);
  266. /* Irqi */
  267. return n;
  268. }
  269. static void
  270. interrupt(Ureg*, void *arg)
  271. {
  272. Irqconfig **pic, *ic;
  273. int irq;
  274. pic = arg;
  275. irq = pic - irqconfig;
  276. if (irq <= 0 || irq > nelem(irqdir)){
  277. print("Unexpected interrupt: %d\n", irq);
  278. return;
  279. }
  280. ilock(&irqlock);
  281. if (irq <= Qirq7)
  282. iomem->sipnr_h |= 0x8000 >> irq; /* Clear the interrupt */
  283. for(ic = *pic; ic; ic = ic->next){
  284. ic->interrupts++;
  285. wakeup(&ic->r);
  286. }
  287. iunlock(&irqlock);
  288. }
  289. Dev irqdevtab = {
  290. 'b',
  291. "irq",
  292. devreset,
  293. devinit,
  294. devshutdown,
  295. irqattach,
  296. irqwalk,
  297. irqstat,
  298. irqopen,
  299. devcreate,
  300. irqclose,
  301. irqread,
  302. devbread,
  303. irqwrite,
  304. devbwrite,
  305. devremove,
  306. devwstat,
  307. };