|
|
1.1 root 1: /*
2: * DSA port driver for KDB50 (aka BDA)
3: * called by, e.g., ra.c
4: */
5:
6: #include "sys/param.h"
7: #include "sys/buf.h"
8: #include "sys/biic.h"
9: #include "sys/biaddr.h"
10: #include "sys/map.h"
11: #include "sys/bda.h"
12: #include "sys/mscp.h"
13: #include "sys/pte.h"
14:
15: #define hiword(x) (((long)(x)>>16)&0177777)
16: #define loword(x) ((long)(x)&0177777)
17:
18: extern struct biaddr bdaddr[];
19: extern struct bd bd[];
20: extern int bdcnt;
21: struct ctab {
22: int (*c_seql)();
23: int (*c_dg)();
24: int c_ctype;
25: } bdctab[MSMAXID];
26:
27: /*
28: * bd_flags
29: */
30:
31: #define UINIT 01 /* already did trivial init */
32: #define UIDONE 02 /* initialization all done */
33: #define UPWAIT 04 /* waiting for command packet */
34: #define UFIRST 010 /* let first packet go even if no credits */
35: #define UTIMER 020 /* timer will kick on next go */
36: #define UCWAIT 040 /* waiting for credits */
37: #define UPMWAIT 0100 /* waiting for map */
38:
39: #define NOBACK (-1)
40:
41: /*
42: * bd_cbusy
43: */
44:
45: #define FREE 0
46: #define NABBED 01
47: #define SENT 02
48: #define MAPPED 04
49:
50: /*
51: * bdip is really bigpr0 in struct biic
52: */
53:
54: struct device {
55: short bdxx; /* unused */
56: short bdip;
57: short bdsar;
58: short bdsaw;
59: };
60:
61: #define bdaregs(p) ((struct device *)&((p)->bigpr0))
62:
63: /*
64: * bits in bdsa (variously read and write half)
65: */
66:
67: #define ERR 0100000
68: #define STEP4 040000
69: #define STEP3 020000
70: #define STEP2 010000
71: #define STEP1 04000
72: #define STEPS (STEP1|STEP2|STEP3|STEP4)
73:
74: #define IE 0200 /* step1 interrupt enable */
75: #define PI 01 /* step2 purge intr enab */
76: #define GO 01 /* step4 ok */
77:
78: /*
79: * bda communication area
80: * ring sizes are chosen so that,
81: * with 4K byte buffers,
82: * one bdcomm + CSIZE-sized command packets will
83: * fit in one buffer;
84: * RSIZE-sized response packets
85: * will fit in another
86: *
87: * ring sizes must be powers of 2
88: * (they are passed as such to the port)
89: *
90: * a delicacy:
91: * command packets should not cross 64Kb boundaries.
92: * it is believed that the KDB50 gets it wrong if they do.
93: * hence, make CSIZE+4 evenly divide a page,
94: * and get it aligned sensibly in bdreset
95: */
96:
97: #define NCP2 5
98: #define NRP2 5
99: #define NCMD (1<<NCP2)
100: #define NRSP (1<<NRP2)
101:
102: struct bdcomm {
103: short bd__r0; /* reserved (ugh) */
104: char bd__r1;
105: char bd_bdp; /* path to purge */
106: short bd_cmdint; /* flag for command interrupt */
107: short bd_rspint; /* flag for response interrupt */
108: long bd_rsp[NRSP]; /* response pointer ring */
109: long bd_cmd[NCMD]; /* command pointer ring */
110: };
111:
112: /*
113: * bits in ring pointers
114: */
115:
116: #define DPOWN 0x80000000 /* port owns descriptor */
117: #define DIE 0x40000000 /* ring transition intr enab */
118:
119: #define BDAVIRT 0x80000000 /* in m_buff: mapped transfer */
120: #define V 0x80000000 /* valid bit in page map */
121:
122: #define CSIZE 60 /* max size of command packet */
123: #define RSIZE 60 /* max size of response packet */
124: #define HDRSIZE 4 /* size of the header */
125:
126: struct bdcmd {
127: short uc_len; /* length of message */
128: char uc_tc; /* type, credits */
129: char uc_cid; /* connection id */
130: char uc_data[CSIZE];
131: };
132:
133: struct bdrsp {
134: short ur_len; /* length of message */
135: char ur_tc; /* type, credits */
136: char ur_cid; /* connection id */
137: char ur_data[RSIZE];
138: };
139:
140: /*
141: * message types
142: */
143:
144: #define MTYPE 0xf0 /* where type lives */
145: #define MTSEQL 0x00 /* sequential message */
146: #define MTDG 0x10 /* datagram */
147: #define MTCR 0x20 /* credit notification */
148:
149: #define MTNC 0xf /* credits in tc */
150:
151: /*
152: * etc
153: */
154:
155: #define PRIINI (PZERO-3)
156: #define PRIPKT (PZERO-2)
157: #define PRICRED (PZERO-1)
158:
159: /*
160: * command packet to index
161: */
162: #define bdmptoi(up, mp) ((struct bdcmd *)((char *)(mp) - HDRSIZE) - (up)->bd_cpkt)
163:
164: #define TIMEOUT 10 /* time between checks */
165:
166: int bdinit(), bdsend(), bdmap(), bdunmap();
167: struct mscmd *bdgpkt();
168: struct msportsw bdport = {
169: bdinit, bdgpkt, bdmap, bdsend, bdunmap
170: };
171:
172: /*
173: * init the port
174: * called once only
175: * returns nonzero if probably ok
176: * allowed to sleep
177: */
178:
179: bdinit(dev, type, force, cid, seql, dg)
180: unsigned int dev;
181: unsigned int cid;
182: int force;
183: int (*seql)(), (*dg)();
184: {
185: register struct bd *up;
186: struct buf *geteblk();
187: extern bdtimer();
188:
189: if (dev >= bdcnt)
190: return (0);
191: if (cid >= MSMAXID)
192: return (0);
193: bdctab[cid].c_seql = seql;
194: bdctab[cid].c_dg = dg;
195: bdctab[cid].c_ctype = type;
196: up = &bd[dev];
197: if (up->bd_flags & UINIT && force == 0)
198: return (1);
199: if ((up->bd_addr = (struct biic *)biaddr(&bdaddr[dev])) == 0) {
200: printf("bd%d absent\n", dev);
201: return (0);
202: }
203: bdrundown(dev);
204: if ((up->bd_flags & UINIT) == 0) {
205: up->bd_cbuf = geteblk();
206: clrbuf(up->bd_cbuf);
207: up->bd_rbuf = geteblk();
208: clrbuf(up->bd_rbuf);
209: up->bd_mbuf = geteblk();
210: clrbuf(up->bd_mbuf);
211: up->bd_comm = (struct bdcomm *)up->bd_cbuf->b_un.b_addr;
212: #define BDCOFF (((sizeof(struct bdcomm)/sizeof(struct bdcmd))+1)*sizeof(struct bdcmd))
213: up->bd_cpkt = (struct bdcmd *)(up->bd_cbuf->b_un.b_addr + BDCOFF);
214: up->bd_rpkt = (struct bdrsp *)up->bd_rbuf->b_un.b_addr;
215: up->bd_pmap = (long *)up->bd_mbuf->b_un.b_addr;
216: up->bd_flags |= UINIT;
217: timeout(bdtimer, (caddr_t)dev, TIMEOUT * HZ);
218: }
219: bdreset(dev);
220: return (1);
221: }
222:
223: /*
224: * reset device
225: * initially or after error or power fail
226: *
227: * just kick the device here;
228: * ideally we would get an interrupt when self-test finishes
229: * (step 1 starts) but we don't, so let the timer routine catch it
230: */
231:
232: bdreset(dev)
233: register int dev;
234: {
235: register struct bd *up;
236:
237: up = &bd[dev];
238: up->bd_flags &=~ UIDONE;
239: up->bd_addr->bicsr |= BINRST; /* hard reset */
240: }
241:
242: /*
243: * finish up init, step by step
244: * called from interrupt code
245: */
246:
247: bdinintr(dev)
248: register int dev;
249: {
250: register struct bd *up;
251: register struct device *rp;
252: register struct biic *bi;
253:
254: up = &bd[dev];
255: rp = bdaregs(up->bd_addr);
256: if (up->bd_flags & UIDONE)
257: printf("bd%d: unexpected init: sa %o\n", dev, rp->bdsar);
258: switch (rp->bdsar & STEPS) {
259: case STEP1:
260: up->bd_cnext = 0;
261: up->bd_rnext = 0;
262: up->bd_credits = 0;
263: bi = up->bd_addr;
264: biinit(&bdaddr[dev], 0);
265: bi->biuir = bdaddr[dev].vec;
266: bi->bieir = (bdaddr[dev].vec + sizeof(long))|EIBR5;
267: rp->bdsaw = ERR | IE | (NCP2<<11) | (NRP2<<8);
268: return;
269:
270: case STEP2:
271: rp->bdsaw = PI | loword(physadr(up->bd_comm->bd_rsp));
272: return;
273:
274: case STEP3:
275: rp->bdsaw = hiword(physadr(up->bd_comm->bd_rsp));
276: return;
277:
278: case STEP4:
279: rp->bdsaw = GO;
280: for (dev = 0; dev < NCMD; dev++) {
281: up->bd_comm->bd_cmd[dev] = 0; /* unnecessary */
282: up->bd_cpkt[dev].uc_len = CSIZE;
283: up->bd_back[dev] = NOBACK;
284: }
285: for (dev = 0; dev < NRSP; dev++) {
286: up->bd_rpkt[dev].ur_len = RSIZE;
287: up->bd_comm->bd_rsp[dev] = physadr(up->bd_rpkt[dev].ur_data) | DIE | DPOWN;
288: }
289: up->bd_flags |= UIDONE | UFIRST;
290: rminit(up->bd_map, BDANMAP, (up->bd_mbuf->b_bcount/sizeof(long))-1, 1);
291: wakeup((caddr_t)up);
292: return;
293:
294: default:
295: printf("bd%d init bad: sar %o\n", dev, rp->bdsar);
296: return;
297: }
298: }
299:
300: /*
301: * tell the class drivers that the controller was reset
302: * so they can clean up
303: * called after controller is stopped (so it's safe to unmap things)
304: */
305: bdrundown(dev)
306: int dev;
307: {
308: static struct msend me;
309: register int i;
310:
311: me.m_sts = STRST; /* magic */
312: for (i = 0; i < MSMAXID; i++)
313: if (bdctab[i].c_seql)
314: (*bdctab[i].c_seql)(dev, bdctab[i].c_ctype, &me);
315: }
316:
317: /*
318: * allocate a packet
319: * and sufficient resources to send it
320: * eg credits
321: * may sleep
322: *
323: * somewhat silly assumption:
324: * class driver will allocate a packet, and send it right away or nearly so
325: */
326:
327: struct mscmd *
328: bdgpkt(dev)
329: int dev;
330: {
331: register struct bd *up;
332: register int i;
333: int s;
334:
335: up = &bd[dev];
336: s = spl6();
337: while ((up->bd_flags & UIDONE) == 0)
338: sleep((caddr_t)up, PRIINI);
339: while (up->bd_credits < 2 && (up->bd_flags & UFIRST) == 0) {
340: if (bdpkscan(dev, 1))
341: continue;
342: up->bd_flags |= UCWAIT;
343: sleep((caddr_t)&up->bd_credits, PRICRED);
344: }
345: if ((up->bd_flags & UFIRST) == 0)
346: up->bd_credits--;
347: for (;;) {
348: for (i = 0; i < NCMD; i++)
349: if (up->bd_cbusy[i] == FREE)
350: break;
351: if (i < NCMD)
352: break;
353: if (bdpkscan(dev, 1) == 0 && bdcmdscan(dev) == 0) { /* kludge for hung controller */
354: up->bd_flags |= UPWAIT;
355: sleep((caddr_t)up->bd_cbusy, PRIPKT);
356: }
357: }
358: up->bd_cbusy[i] = NABBED;
359: splx(s);
360: return ((struct mscmd *)up->bd_cpkt[i].uc_data);
361: }
362:
363: /*
364: * map a transfer if need be
365: * and record in the buffer descriptor of a packet
366: * may sleep
367: *
368: * BDA use of m_buff:
369: * first longword is buffer address;
370: * if BDAVIRT clear, physical addr, else virtual
371: * second longword is phys addr of base of page table if virtual
372: *
373: * subtlety: pretend we mapped it even if we didn't,
374: * so it won't be unmapped until someone calls bdunmap
375: * else they may be confused when they call it anyway
376: */
377:
378: bdmap(dev, mp, bp)
379: int dev;
380: struct mscmd *mp;
381: register struct buf *bp;
382: {
383: register int i;
384: register long *b;
385: register struct pte *pt;
386: int s;
387: int base;
388: register int size;
389: register struct bd *up;
390:
391: up = &bd[dev];
392: i = bdmptoi(up, mp);
393: up->bd_cbusy[i] |= MAPPED;
394: if ((bp->b_flags & (B_PHYS|B_UAREA|B_PAGET|B_DIRTY)) == 0) {
395: b = (long *)&mp->m_buff;
396: *b++ = (long)bp->b_un.b_addr|BDAVIRT;
397: *b++ = physadr(Sysmap);
398: *b = 0;
399: return;
400: }
401: size = btoc(bp->b_bcount);
402: if ((long)bp->b_un.b_addr & PGOFSET)
403: size++; /* unaligned */
404: s = spl6();
405: while ((base = rmalloc(up->bd_map, size)) == 0) {
406: up->bd_flags |= UPMWAIT;
407: sleep((caddr_t)up->bd_map, PRIPKT);
408: }
409: splx(s);
410: up->bd_mbase[i] = base;
411: up->bd_msize[i] = size;
412: b = &up->bd_pmap[base];
413: pt = btopte(bp);
414: while (--size >= 0)
415: *b++ = pt++->pg_pfnum | V;
416: b = (long *)&mp->m_buff;
417: *b++ = ctob(base)|((long)bp->b_un.b_addr&PGOFSET)|BDAVIRT;
418: *b++ = physadr(up->bd_pmap);
419: *b = 0;
420: }
421:
422: /*
423: * free a mapped packet
424: */
425:
426: bdunmap(dev, mp)
427: int dev;
428: struct mscmd *mp;
429: {
430: register struct bd *up;
431: register int i;
432:
433: up = &bd[dev];
434: i = bdmptoi(up, mp);
435: if (up->bd_cbusy[i] == FREE)
436: return; /* wasn't mapped, and already freed */
437: if (up->bd_msize[i]) {
438: rmfree(up->bd_map, up->bd_msize[i], up->bd_mbase[i]);
439: up->bd_msize[i] = 0;
440: if (up->bd_flags & UPMWAIT) {
441: up->bd_flags &=~ UPMWAIT;
442: wakeup((caddr_t)up->bd_map);
443: }
444: }
445: up->bd_cbusy[i] = FREE;
446: if (up->bd_flags & UPWAIT) {
447: up->bd_flags &=~ UPWAIT;
448: wakeup((caddr_t)up->bd_cbusy);
449: }
450: }
451:
452: /*
453: * send a packet
454: * may not sleep
455: * call at spl5
456: */
457:
458: bdsend(dev, cid, mp)
459: int dev;
460: int cid;
461: struct mscmd *mp;
462: {
463: register struct bd *up;
464: register int i;
465: register int j;
466:
467: up = &bd[dev];
468: up->bd_flags &=~ UFIRST;
469: i = bdmptoi(up, mp);
470: up->bd_cpkt[i].uc_cid = cid;
471: j = up->bd_cnext++;
472: if (up->bd_cnext >= NCMD)
473: up->bd_cnext = 0;
474: if (up->bd_comm->bd_cmd[j] & DPOWN)
475: panic("bdsend");
476: if (up->bd_back[j] >= 0) { /* ran for a while with no free */
477: bdcmdscan(dev);
478: if (up->bd_back[j] >= 0)
479: panic("bdsend");
480: }
481: up->bd_back[j] = i;
482: up->bd_comm->bd_cmd[j] = DPOWN | DIE | physadr(mp);
483: up->bd_cbusy[i] |= SENT;
484: up->bd_cbusy[i] &=~ NABBED;
485: i = bdaregs(up->bd_addr)->bdip; /* initiate polling */
486: }
487:
488: /*
489: * interrupt routine
490: */
491:
492: long bd_spur;
493: int bdspl;
494:
495: bd0int(dev)
496: int dev;
497: {
498: register struct bd *up;
499: register struct device *rp;
500:
501: bdspl = mfpr(0x12);
502: up = &bd[dev];
503: if (dev >= bdcnt || (up->bd_flags & UINIT) == 0) {
504: printf("bd%d: stray intr\n", dev);
505: return;
506: }
507: rp = bdaregs(up->bd_addr);
508: if (rp->bdsar & ERR) {
509: printf("bd%d: hard error %o\n", dev, rp->bdsar & 0177777);
510: bdreset(dev);
511: return;
512: }
513: if (rp->bdsar & STEPS) {
514: bdinintr(dev);
515: return;
516: }
517: if (up->bd_comm->bd_cmdint == 0
518: && up->bd_comm->bd_rspint == 0)
519: bd_spur++;
520: while (up->bd_comm->bd_cmdint) {
521: up->bd_comm->bd_cmdint = 0;
522: bdcmdscan(dev);
523: }
524: while (up->bd_comm->bd_rspint) {
525: up->bd_comm->bd_rspint = 0;
526: if (bdpkscan(dev, 0))
527: up->bd_flags &=~ UTIMER;
528: }
529: }
530:
531: bd1int(dev)
532: int dev;
533: {
534: printf("bd%d: error intr\n", dev);
535: }
536:
537: /*
538: * free packets which are completely sent
539: * (and which don't have associated map)
540: */
541:
542: bdcmdscan(dev)
543: int dev;
544: {
545: register struct bd *up;
546: register int i, j;
547: register int freed;
548: register struct bdcomm *bdc;
549:
550: up = &bd[dev];
551: bdc = up->bd_comm;
552: freed = 0;
553: for (j = 0; j < NCMD; j++)
554: if (up->bd_back[j] >= 0
555: && (bdc->bd_cmd[j] & DPOWN) == 0) {
556: i = up->bd_back[j];
557: if ((up->bd_cbusy[i] & (SENT|MAPPED)) == SENT) {
558: up->bd_cbusy[i] = FREE;
559: freed++;
560: }
561: up->bd_back[j] = NOBACK;
562: }
563: if (freed && up->bd_flags & UPWAIT)
564: wakeup((caddr_t)up->bd_cbusy);
565: return (freed);
566: }
567:
568: /*
569: * check for responses from the controller
570: * and deal with them
571: * return a count for debugging purposes
572: */
573:
574: int
575: bdpkscan(dev, doall)
576: int dev;
577: int doall;
578: {
579: register struct bd *up;
580: register int i;
581: int nf;
582: register struct bdrsp *pk;
583: register struct ctab *cp;
584: register struct bdcomm *bdc; /* speed */
585: int s;
586:
587: up = &bd[dev];
588: bdc = up->bd_comm;
589: nf = 0;
590: s = spl6();
591: for (i = up->bd_rnext; ; i < NRSP-1 ? i++ : (i = 0)) {
592: if (bdc->bd_rsp[i] & DPOWN) {
593: up->bd_rnext = i;
594: /* don't stop if doall? */
595: break;
596: }
597: nf++;
598: pk = &up->bd_rpkt[i];
599: up->bd_credits += pk->ur_tc & MTNC;
600: if (up->bd_flags & UCWAIT) {
601: wakeup((caddr_t)&up->bd_credits);
602: up->bd_flags &=~ UCWAIT;
603: }
604: if (pk->ur_cid > MSMAXID)
605: printf("bd%d msg id %d\n", dev, pk->ur_cid);
606: else {
607: cp = &bdctab[pk->ur_cid];
608: switch (pk->ur_tc & MTYPE) {
609: case MTSEQL:
610: if (cp->c_seql)
611: (*cp->c_seql)(dev, cp->c_ctype, (struct msend *)pk->ur_data);
612: break;
613:
614: case MTDG:
615: if (cp->c_dg)
616: (*cp->c_dg)(dev, cp->c_ctype, pk->ur_data);
617: break;
618:
619: /* default: ignore */
620: }
621: }
622: pk->ur_len = RSIZE;
623: bdc->bd_rsp[i] |= DPOWN | DIE;
624: }
625: splx(s);
626: return (nf);
627: }
628:
629: /*
630: * timeout routine
631: * return any waiting packets
632: * -- callout routines don't necessarily run at high priority.
633: * hence the spl6, so bdpkscan won't be reentered
634: */
635:
636: int bd_kicked;
637:
638: bdtimer(i)
639: int i;
640: {
641: register struct bd *up;
642: register int s;
643:
644: up = &bd[i];
645: if ((up->bd_flags & UINIT) == 0)
646: return;
647: if ((up->bd_flags & UIDONE) == 0) {
648: if ((bdaregs(up->bd_addr)->bdsar & STEPS) == STEP1)
649: bdinintr(i);
650: }
651: else if ((up->bd_flags & UTIMER) == 0)
652: up->bd_flags |= UTIMER;
653: else {
654: s = spl6();
655: if (bdpkscan(i, 1) && up->bd_flags & UPWAIT) {
656: wakeup((caddr_t)up->bd_cbusy);
657: bd_kicked++;
658: }
659: splx(s);
660: up->bd_flags &=~ UTIMER;
661: }
662: timeout(bdtimer, (caddr_t)i, TIMEOUT * HZ);
663: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.