more reformatting
[unix-history] / usr / src / sys / tahoe / vba / dr.c
CommitLineData
9d61b7ff 1/* dr.c 1.6 86/12/15 */
20340301
SL
2
3#include "dr.h"
4#if NDR > 0
9d61b7ff
SL
5/*
6 * DRV11-W DMA interface driver.
7 *
b5d0006f 8 * UNTESTED WITH 4.3
20340301 9 */
20340301
SL
10#include "../machine/mtpr.h"
11#include "../machine/pte.h"
12
13#include "param.h"
14#include "conf.h"
15#include "dir.h"
16#include "user.h"
17#include "proc.h"
18#include "map.h"
19#include "ioctl.h"
20#include "buf.h"
21#include "vm.h"
22#include "uio.h"
9d61b7ff 23#include "kernel.h"
20340301
SL
24
25#include "../tahoevba/vbavar.h"
26#include "../tahoevba/drreg.h"
27
28#define YES 1
29#define NO 0
30
31struct vba_device *drinfo[NDR];
32struct dr_aux dr_aux[NDR];
33
20340301 34unsigned drminphys();
9d61b7ff
SL
35int drprobe(), drintr(), drattach(), drtimo(), drrwtimo();
36int drstrategy();
37extern struct vba_device *drinfo[];
38static long drstd[] = { 0 };
20340301 39struct vba_driver drdriver =
9d61b7ff 40 { drprobe, 0, drattach, 0, drstd, "rs", drinfo };
20340301
SL
41
42#define RSUNIT(dev) (minor(dev) & 7)
43#define SPL_UP spl5
44
45/* -------- Per-unit data -------- */
46
47extern struct dr_aux dr_aux[];
48
20340301 49#ifdef DR_DEBUG
9d61b7ff 50long DR11 = 0;
20340301
SL
51#endif
52
53drprobe(reg, vi)
9d61b7ff
SL
54 caddr_t reg;
55 struct vba_device *vi;
20340301 56{
9d61b7ff
SL
57 register int br, cvec; /* must be r12, r11 */
58 struct rsdevice *dr;
20340301 59
9d61b7ff
SL
60#ifdef lint
61 br = 0; cvec = br; br = cvec;
62 drintr(0);
20340301 63#endif
9d61b7ff
SL
64 if (badaddr(reg, 2))
65 return (0);
66 dr = (struct rsdevice *)reg;
67 dr->dr_intvect = --vi->ui_hd->vh_lastiv;
20340301 68#ifdef DR_DEBUG
9d61b7ff 69 printf("dprobe: Set interrupt vector %lx and init\n",dr->dr_intvec);
20340301 70#endif
9d61b7ff
SL
71 /* generate interrupt here for autoconfig */
72 dr->dr_cstat = MCLR; /* init board and device */
20340301 73#ifdef DR_DEBUG
9d61b7ff 74 printf("drprobe: Initial status %lx\n", dr->dr_cstat);
20340301 75#endif
9d61b7ff
SL
76 br = 0x18, cvec = dr->dr_intvect; /* XXX */
77 return (sizeof (struct rsdevice)); /* DR11 exist */
20340301
SL
78}
79
80/* ARGSUSED */
81drattach(ui)
9d61b7ff 82 struct vba_device *ui;
20340301 83{
9d61b7ff
SL
84 register struct dr_aux *rsd;
85
86 rsd = &dr_aux[ui->ui_unit];
87 rsd->dr_flags = DR_PRES; /* This dr11 is present */
88 rsd->dr_addr = (struct rsdevice *)ui->ui_addr; /* Save addr of this dr11 */
89 rsd->dr_istat = 0;
90 rsd->dr_bycnt = 0;
91 rsd->dr_cmd = 0;
92 rsd->currenttimo = 0;
20340301
SL
93}
94
9d61b7ff
SL
95/*ARGSUSED*/
96dropen(dev, flag)
97 dev_t dev;
98 int flag;
20340301 99{
9d61b7ff
SL
100 register int unit = RSUNIT(dev);
101 register struct rsdevice *dr;
102 register struct dr_aux *rsd;
103
104 if (drinfo[unit] == 0 || !drinfo[unit]->ui_alive)
105 return (ENXIO);
106 dr = RSADDR(unit);
107 rsd = &dr_aux[unit];
108 if (rsd->dr_flags & DR_OPEN) {
20340301 109#ifdef DR_DEBUG
9d61b7ff 110 printf("\ndropen: dr11 unit %ld already open",unit);
20340301 111#endif
9d61b7ff
SL
112 return (ENXIO); /* DR11 already open */
113 }
114 rsd->dr_flags |= DR_OPEN; /* Mark it OPEN */
115 rsd->dr_istat = 0; /* Clear status of previous interrupt */
116 rsd->rtimoticks = hz; /* Set read no stall timout to 1 sec */
117 rsd->wtimoticks = hz*60; /* Set write no stall timout to 1 min */
118 dr->dr_cstat = DR_ZERO; /* Clear function & latches */
119 dr->dr_pulse = (RDMA | RATN); /* clear leftover attn & e-o-r flags */
120 drtimo(dev); /* start the self kicker */
121 return (0);
20340301
SL
122}
123
124drclose (dev)
9d61b7ff 125 dev_t dev;
20340301 126{
9d61b7ff
SL
127 register int unit = RSUNIT(dev);
128 register struct dr_aux *dra;
129 register struct rsdevice *rs;
130 register short s;
20340301 131
9d61b7ff
SL
132 dra = &dr_aux[unit];
133 if ((dra->dr_flags & DR_OPEN) == 0) {
20340301 134#ifdef DR_DEBUG
9d61b7ff 135 printf("\ndrclose: DR11 device %ld not open",unit);
20340301 136#endif
9d61b7ff
SL
137 return;
138 }
139 dra->dr_flags &= ~(DR_OPEN|DR_ACTV);
140 rs = dra->dr_addr;
141 s = SPL_UP();
142 rs->dr_cstat = DR_ZERO;
143 if (dra->dr_buf.b_flags & B_BUSY) {
144 dra->dr_buf.b_flags &= ~B_BUSY;
145 wakeup((caddr_t)&dra->dr_buf.b_flags);
146 }
147 splx(s);
20340301
SL
148}
149
150
151/* drread() works exactly like drwrite() except that the
152 B_READ flag is used when physio() is called
153*/
154drread (dev, uio)
9d61b7ff
SL
155 dev_t dev;
156 struct uio *uio;
20340301
SL
157{ register struct dr_aux *dra;
158 register struct buf *bp;
9d61b7ff
SL
159 register int spl, err;
160 register int unit = RSUNIT(dev);
20340301 161
9d61b7ff
SL
162 if (uio->uio_iov->iov_len <= 0 || /* Negative count */
163 uio->uio_iov->iov_len & 1 || /* odd count */
164 (int)uio->uio_iov->iov_base & 1) /* odd destination address */
165 return (EINVAL);
20340301 166#ifdef DR_DEBUG
9d61b7ff
SL
167 if (DR11 & 8)
168 printf("\ndrread: (len:%ld)(base:%lx)",
169 uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base);
20340301 170#endif
9d61b7ff
SL
171 dra = &dr_aux[RSUNIT(dev)];
172 dra->dr_op = DR_READ;
173 bp = &dra->dr_buf;
174 bp->b_resid = 0;
175 if (dra->dr_flags & DR_NORSTALL) {
176 /*
177 * We are in no stall mode, start the timer,
178 * raise IPL so nothing can stop us once the
179 * timer's running
180 */
181 spl = SPL_UP();
182 timeout(drrwtimo, (caddr_t)((dra->currenttimo<<8) | unit),
183 (int)dra->rtimoticks);
184 err = physio(drstrategy, bp, dev,B_READ, drminphys, uio);
185 splx(spl);
186 if (err)
187 return (err);
188 dra->currenttimo++; /* Update current timeout number */
189 /* Did we timeout */
190 if (dra->dr_flags & DR_TMDM) {
191 dra->dr_flags &= ~DR_TMDM; /* Clear timeout flag */
192 u.u_error = 0; /* Made the error ourself, ignore it */
193 }
194 return (err);
20340301 195 }
9d61b7ff 196 return (physio(drstrategy, bp, dev,B_READ, drminphys, uio));
20340301
SL
197}
198
9d61b7ff
SL
199drwrite(dev, uio)
200 dev_t dev;
201 struct uio *uio;
20340301
SL
202{ register struct dr_aux *dra;
203 register struct buf *bp;
9d61b7ff
SL
204 register int unit = RSUNIT(dev);
205 int spl, err;
20340301 206
9d61b7ff
SL
207 if (uio->uio_iov->iov_len <= 0 || uio->uio_iov->iov_len & 1 ||
208 (int)uio->uio_iov->iov_base & 1)
209 return (EINVAL);
20340301 210#ifdef DR_DEBUG
9d61b7ff
SL
211 if (DR11 & 4)
212 printf("\ndrwrite: (len:%ld)(base:%lx)",
213 uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base);
20340301 214#endif
9d61b7ff
SL
215 dra = &dr_aux[RSUNIT(dev)];
216 dra->dr_op = DR_WRITE;
217 bp = &dra->dr_buf;
218 bp->b_resid = 0;
219 if (dra->dr_flags & DR_NOWSTALL) {
220 /*
221 * We are in no stall mode, start the timer,
222 * raise IPL so nothing can stop us once the
223 * timer's running
224 */
225 spl = SPL_UP();
226 timeout(drrwtimo,(caddr_t)((dra->currenttimo<<8) | unit),
227 (int)dra->wtimoticks);
228 err = physio (drstrategy, bp, dev,B_WRITE, drminphys, uio);
229 splx(spl);
230 if (err)
231 return (err);
232 dra->currenttimo++; /* Update current timeout number */
233 /* Did we timeout */
234 if (dra->dr_flags & DR_TMDM) {
235 dra->dr_flags &= ~DR_TMDM; /* Clear timeout flag */
236 u.u_error = 0; /* Made the error ourself, ignore it */
237 }
238 return (err);
20340301 239 }
9d61b7ff 240 return (physio(drstrategy, bp, dev,B_WRITE, drminphys, uio));
20340301
SL
241}
242
9d61b7ff
SL
243/*
244 * Routine used by calling program to issue commands to dr11 driver and
245 * through it to the device.
246 * It is also used to read status from the device and driver and to wait
247 * for attention interrupts.
248 * Status is returned in an 8 elements unsigned short integer array, the
249 * first two elements of the array are also used to pass arguments to
250 * drioctl() if required.
251 * The function bits to be written to the dr11 are included in the cmd
252 * argument. Even if they are not being written to the dr11 in a particular
253 * drioctl() call, they will update the copy of cmd that is stored in the
254 * driver. When drstrategy() is called, this updated copy is used if a
255 * deferred function bit write has been specified. The "side effect" of
256 * calls to the drioctl() requires that the last call prior to a read or
257 * write has an appropriate copy of the function bits in cmd if they are
258 * to be used in drstrategy().
259 * When used as command value, the contents of data[0] is the command
260 * parameter.
261 */
262drioctl(dev, cmd, data)
263 dev_t dev;
264 int cmd;
265 long *data;
20340301 266{
9d61b7ff
SL
267 register int unit = RSUNIT(dev);
268 register struct dr_aux *dra;
269 register struct rsdevice *rsaddr = RSADDR(unit);
270 int s;
271 u_short status;
272 long temp;
273
274#ifdef DR_DEBUG
275 if (DR11 & 0x10)
276 printf("\ndrioctl: (dev:%lx)(cmd:%lx)(data:%lx)(data[0]:%lx)",
277 dev,cmd,data,data[0]);
278#endif
279 dra = &dr_aux[unit];
280 dra->dr_cmd = 0; /* Fresh copy; clear all previous flags */
281 switch (cmd) {
20340301 282
9d61b7ff 283 case DRWAIT: /* Wait for attention interrupt */
20340301 284#ifdef DR_DEBUG
9d61b7ff 285 printf("\ndrioctl: wait for attention interrupt");
20340301 286#endif
9d61b7ff
SL
287 s = SPL_UP();
288 /*
289 * If the attention flag in dr_flags is set, it probably
290 * means that an attention has arrived by the time a
291 * previous DMA end-of-range interrupt was serviced. If
292 * ATRX is set, we will return with out sleeping, since
293 * we have received an attention since the last call to
294 * wait on attention. This may not be appropriate for
295 * some applications.
296 */
297 if ((dra->dr_flags & DR_ATRX) == 0) {
298 dra->dr_flags |= DR_ATWT; /* Set waiting flag */
299 /*
300 * Enable interrupt; use pulse reg.
301 * so function bits are not changed
302 */
303 rsaddr->dr_pulse = IENB;
304 sleep((caddr_t)&dra->dr_cmd, DRPRI);
305 }
306 splx(s);
307 break;
308
309 case DRPIOW: /* Write to p-i/o register */
310 rsaddr->dr_data = data[0];
311 break;
312
313 case DRPACL: /* Send pulse to device */
314 rsaddr->dr_pulse = FCN2;
315 break;
316
317 case DRDACL: /* Defer alco pulse until go */
318 dra->dr_cmd |= DR_DACL;
319 break;
320
321 case DRPCYL: /* Set cycle with next go */
322 dra->dr_cmd |= DR_PCYL;
323 break;
324
325 case DRDFCN: /* Update function with next go */
326 dra->dr_cmd |= DR_DFCN;
327 break;
328
329 case DRRATN: /* Reset attention flag */
330 rsaddr->dr_pulse = RATN;
331 break;
332
333 case DRRDMA: /* Reset DMA e-o-r flag */
334 rsaddr->dr_pulse = RDMA;
335 break;
336
337 case DRSFCN: /* Set function bits */
338 temp = data[0] & DR_FMSK;
339 /*
340 * This has a very important side effect -- It clears
341 * the interrupt enable flag. That is fine for this driver,
342 * but if it is desired to leave interrupt enable at all
343 * times, it will be necessary to read the status register
344 * first to get IENB, or carry a software flag that indicates
345 * whether interrupts are set, and or this into the control
346 * register value being written.
347 */
348 rsaddr->dr_cstat = temp;
349 break;
350
351 case DRRPER: /* Clear parity flag */
352 rsaddr->dr_pulse = RPER;
353 break;
354
355 case DRSETRSTALL: /* Set read stall mode. */
356 dra->dr_flags &= (~DR_NORSTALL);
357 break;
358
359 case DRSETNORSTALL: /* Set no stall read mode. */
360 dra->dr_flags |= DR_NORSTALL;
361 break;
362
363 case DRGETRSTALL: /* Returns true if in read stall mode */
364 data[0] = (dra->dr_flags & DR_NORSTALL)? 0 : 1;
365 break;
366
367 case DRSETRTIMEOUT: /* Set read stall timeout (1/10 secs) */
368 if (data[0] < 1) {
369 u.u_error = EINVAL;
370 temp = 1;
371 }
372 dra->rtimoticks = (data[0] * hz )/10;
373 break;
20340301 374
9d61b7ff
SL
375 case DRGETRTIMEOUT: /* Return read stall timeout */
376 data[0] = ((dra->rtimoticks)*10)/hz;
377 break;
20340301 378
9d61b7ff
SL
379 case DRSETWSTALL: /* Set write stall mode. */
380 dra->dr_flags &= (~DR_NOWSTALL);
381 break;
20340301 382
9d61b7ff
SL
383 case DRSETNOWSTALL: /* Set write stall mode. */
384 dra->dr_flags |= DR_NOWSTALL;
385 break;
386
387 case DRGETWSTALL: /* Return true if in write stall mode */
388 data[0] = (dra->dr_flags & DR_NOWSTALL)? 0 : 1;
389 break;
390
391 case DRSETWTIMEOUT: /* Set write stall timeout (1/10's) */
392 if (data[0] < 1) {
393 u.u_error = EINVAL;
394 temp = 1;
395 }
396 dra->wtimoticks = (data[0] * hz )/10;
397 break;
398
399 case DRGETWTIMEOUT: /* Return write stall timeout */
400 data[0] = ((dra->wtimoticks)*10)/hz;
401 break;
402
403 case DRWRITEREADY: /* Return true if can write data */
404 data[0] = (rsaddr->dr_cstat & STTA)? 1 : 0;
405 break;
406
407 case DRREADREADY: /* Return true if data to be read */
408 data[0] = (rsaddr->dr_cstat & STTB)? 1 : 0;
409 break;
410
411 case DRBUSY: /* Return true if device busy */
412 /*
413 * Internally this is the DR11-W
414 * STAT C bit, but there is a bug in the Omega 500/FIFO
415 * interface board that it cannot drive this signal low
416 * for certain DR11-W ctlr such as the Ikon. We use the
417 * REDY signal of the CSR on the Ikon DR11-W instead.
418 */
419#ifdef notdef
420 data[0] = (rsaddr->dr_cstat & STTC)? 1 : 0;
421#else
422 data[0] = ((rsaddr->dr_cstat & REDY)? 0 : 1);
20340301 423#endif
9d61b7ff
SL
424 break;
425
426 case DRRESET: /* Reset device */
427 /* Reset DMA ATN RPER flag */
428 rsaddr->dr_pulse = (MCLR|RDMA|RATN|RPER);
429 DELAY(0x1f000);
430 while ((rsaddr->dr_cstat & REDY) == 0)
431 sleep((caddr_t)dra, DRPRI); /* Wakeup by drtimo() */
432 dra->dr_istat = 0;
433 dra->dr_cmd = 0;
434 dra->currenttimo = 0;
435 break;
436
437 case DR11STAT: { /* Copy back dr11 status to user */
438 register struct dr11io *dr = (struct dr11io *)data;
439 dr->arg[0] = dra->dr_flags;
440 dr->arg[1] = rsaddr->dr_cstat;
441 dr->arg[2] = dra->dr_istat; /* Status at last interrupt */
442 dr->arg[3] = rsaddr->dr_data; /* P-i/o input data */
443 status = (u_short)((rsaddr->dr_addmod << 8) & 0xff00);
444 dr->arg[4] = status | (u_short)(rsaddr->dr_intvect & 0xff);
445 dr->arg[5] = rsaddr->dr_range;
446 dr->arg[6] = rsaddr->dr_rahi;
447 dr->arg[7] = rsaddr->dr_ralo;
448 break;
20340301 449 }
9d61b7ff
SL
450 case DR11LOOP: /* Perform loopback test */
451 /*
452 * NB: MUST HAVE LOOPBACK CABLE ATTACHED --
453 * Test results are printed on system console
454 */
455 if (suser())
456 dr11loop(rsaddr, dra, unit);
457 break;
458
459 default:
460 return (EINVAL);
20340301 461 }
20340301 462#ifdef DR_DEBUG
9d61b7ff
SL
463 if (DR11 & 0x10)
464 printf("**** (data[0]:%lx)",data[0]);
20340301 465#endif
9d61b7ff 466 return (0);
20340301
SL
467}
468
9d61b7ff
SL
469#define NPAT 2
470#define DMATBL 20
471u_short tstpat[DMATBL] = { 0xAAAA, 0x5555};
472long DMAin = 0;
aa4f73e3 473
9d61b7ff
SL
474/*
475 * Perform loopback test -- MUST HAVE LOOPBACK CABLE ATTACHED
476 * Test results are printed on system console
477 */
478dr11loop(dr, dra, unit)
479 struct rsdevice *dr;
480 struct dr_aux *dra;
481 int unit;
482{
483 register long result, ix;
484 long addr, wait;
aa4f73e3
SL
485
486 dr->dr_cstat = MCLR; /* Clear board & device, disable intr */
9d61b7ff 487 printf("\n\t ----- DR11 unit %ld loopback test -----", unit);
aa4f73e3
SL
488 printf("\n\t Program I/O ...");
489 for (ix=0;ix<NPAT;ix++) {
490 dr->dr_data = tstpat[ix]; /* Write to Data out register */
9d61b7ff 491 result = dr->dr_data & 0xFFFF; /* Read it back */
aa4f73e3
SL
492 if (result != tstpat[ix]) {
493 printf("Failed, expected : %lx --- actual : %lx",
9d61b7ff 494 tstpat[ix], result);
aa4f73e3
SL
495 return;
496 }
497 }
aa4f73e3
SL
498 printf("OK\n\t Functions & Status Bits ...");
499 dr->dr_cstat = (FCN1 | FCN3);
500 result = dr->dr_cstat & 0xffff; /* Read them back */
501 if ((result & (STTC | STTA)) != (STTC |STTA)) {
502 printf("Failed, expected : %lx --- actual : %lx, ISR:%lx",
9d61b7ff 503 (STTA|STTC), (result & (STTA|STTC)), result);
aa4f73e3
SL
504 return;
505 }
506 dr->dr_cstat = FCN2;
507 result = dr->dr_cstat & 0xffff; /* Read them back */
508 if ((result & STTB) != STTB) {
509 printf("Failed, expected : %lx --- actual : %lx, ISR:%lx",
9d61b7ff 510 STTB, (result & STTB), result);
aa4f73e3
SL
511 return;
512 }
aa4f73e3 513 printf("OK\n\t DMA output ...");
9d61b7ff
SL
514 if (DMAin)
515 goto dmain;
aa4f73e3 516 /* Initialize DMA data buffer */
9d61b7ff
SL
517 for (ix=0; ix<DMATBL; ix++)
518 tstpat[ix] = 0xCCCC + ix;
aa4f73e3 519 tstpat[DMATBL-1] = 0xCCCC; /* Last word output */
aa4f73e3 520 /* Setup normal DMA */
9d61b7ff
SL
521 addr = (long)vtoph((struct proc *)0, (unsigned)tstpat);
522 dr->dr_walo = (addr >> 1) & 0xffff;
523 dr->dr_wahi = (addr >> 17) & 0x7fff;
524 /* Set DMA range count: (number of words - 1) */
525 dr->dr_range = DMATBL - 1;
526 /* Set address modifier code to be used for DMA access to memory */
527 dr->dr_addmod = DRADDMOD;
528
529 /*
530 * Clear dmaf and attf to assure a clean dma start, also disable
531 * attention interrupt
532 */
533 dr->dr_pulse = RDMA|RATN|RMSK; /* Use pulse register */
534 dr->dr_cstat = GO|CYCL; /* GO...... */
aa4f73e3
SL
535
536 /* Wait for DMA complete; REDY and DMAF are true in ISR */
537 wait = 0;
9d61b7ff
SL
538 while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) {
539 printf("\n\tWait for DMA complete...ISR : %lx", result);
aa4f73e3
SL
540 if (++wait > 5) {
541 printf("\n\t DMA output fails...timeout!!, ISR:%lx",
542 result);
543 return;
544 }
545 }
aa4f73e3
SL
546 result = dr->dr_data & 0xffff; /* Read last word output */
547 if (result != 0xCCCC) {
548 printf("\n\t Fails, expected : %lx --- actual : %lx",
9d61b7ff 549 0xCCCC, result);
aa4f73e3
SL
550 return;
551 }
aa4f73e3 552 printf("OK\n\t DMA input ...");
aa4f73e3
SL
553dmain:
554 dr->dr_data = 0x1111; /* DMA input data */
555 /* Setup normal DMA */
9d61b7ff
SL
556 addr = (long)vtoph((struct proc *)0, (unsigned)tstpat);
557 dr->dr_walo = (addr >> 1) & 0xffff;
558 dr->dr_wahi = (addr >> 17) & 0x7fff;
559 dr->dr_range = DMATBL - 1;
560 dr->dr_addmod = (char)DRADDMOD;
561 dr->dr_cstat = FCN1; /* Set FCN1 in ICR to DMA in*/
562 if ((dra->dr_flags & DR_LOOPTST) == 0) {
aa4f73e3 563 /* Use pulse reg */
9d61b7ff 564 dr->dr_pulse = RDMA|RATN|RMSK|CYCL|GO;
aa4f73e3
SL
565 /* Wait for DMA complete; REDY and DMAF are true in ISR */
566 wait = 0;
9d61b7ff 567 while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) {
aa4f73e3
SL
568 printf("\n\tWait for DMA to complete...ISR:%lx",result);
569 if (++wait > 5) {
570 printf("\n\t DMA input timeout!!, ISR:%lx",
571 result);
572 return;
573 }
574 }
9d61b7ff 575 } else {
aa4f73e3 576 /* Enable DMA e-o-r interrupt */
9d61b7ff 577 dr->dr_pulse = IENB|RDMA|RATN|CYCL|GO;
aa4f73e3
SL
578 /* Wait for DMA complete; DR_LOOPTST is false in dra->dr_flags*/
579 wait = 0;
580 while (dra->dr_flags & DR_LOOPTST) {
581 result = dr->dr_cstat & 0xffff;
9d61b7ff 582 printf("\n\tWait for DMA e-o-r intr...ISR:%lx", result);
aa4f73e3
SL
583 if (++wait > 7) {
584 printf("\n\t DMA e-o-r timeout!!, ISR:%lx",
585 result);
586 dra->dr_flags &= ~DR_LOOPTST;
587 return;
588 }
589 }
590 dra->dr_flags |= DR_LOOPTST;
591 }
9d61b7ff
SL
592 mtpr(P1DC, tstpat); /* Purge cache */
593 mtpr(P1DC, 0x3ff+tstpat);
594 for (ix=0; ix<DMATBL; ix++) {
aa4f73e3 595 if (tstpat[ix] != 0x1111) {
9d61b7ff
SL
596 printf("\n\t Fails, ix:%d, expected:%x --- actual:%x",
597 ix, 0x1111, tstpat[ix]);
aa4f73e3
SL
598 return;
599 }
600 }
9d61b7ff 601 if ((dra->dr_flags & DR_LOOPTST) == 0) {
aa4f73e3
SL
602 dra->dr_flags |= DR_LOOPTST;
603 printf(" OK..\n\tDMA end of range interrupt...");
604 goto dmain;
605 }
aa4f73e3 606 printf(" OK..\n\tAttention interrupt....");
9d61b7ff
SL
607 dr->dr_pulse = IENB|RDMA;
608 dr->dr_pulse = FCN2;
aa4f73e3
SL
609 /* Wait for ATTN interrupt; DR_LOOPTST is false in dra->dr_flags*/
610 wait = 0;
611 while (dra->dr_flags & DR_LOOPTST) {
612 result = dr->dr_cstat & 0xffff;
613 printf("\n\tWait for Attention intr...ISR:%lx",result);
614 if (++wait > 7) {
615 printf("\n\t Attention interrupt timeout!!, ISR:%lx",
616 result);
617 dra->dr_flags &= ~DR_LOOPTST;
618 return;
619 }
620 }
621 dra->dr_flags &= ~DR_LOOPTST;
622 printf(" OK..\n\tDone...");
623}
624
20340301 625/* Reset state on Unibus reset */
9d61b7ff 626/*ARGSUSED*/
20340301 627drreset(uban)
9d61b7ff 628 int uban;
20340301 629{
9d61b7ff 630
20340301
SL
631}
632
633/*
634 * An interrupt is caused either by an error,
635 * base address overflow, or transfer complete
636 */
9d61b7ff
SL
637drintr(dr11)
638 int dr11;
20340301 639{
9d61b7ff
SL
640 register struct dr_aux *dra = &dr_aux[dr11];
641 register struct rsdevice *rsaddr = RSADDR(dr11);
642 register struct buf *bp;
643 register short status;
20340301 644
9d61b7ff
SL
645 status = rsaddr->dr_cstat & 0xffff; /* get board status register */
646 dra->dr_istat = status;
20340301 647#ifdef DR_DEBUG
9d61b7ff
SL
648 if (DR11 & 2)
649 printf("\ndrintr: dr11 status : %lx",status & 0xffff);
20340301 650#endif
9d61b7ff
SL
651 if (dra->dr_flags & DR_LOOPTST) { /* doing loopback test */
652 dra->dr_flags &= ~DR_LOOPTST;
653 return;
654 }
655 /*
656 * Make sure this is not a stray interrupt; at least one of dmaf or attf
657 * must be set. Note that if the dr11 interrupt enable latch is reset
658 * during a hardware interrupt ack sequence, and by the we get to this
659 * point in the interrupt code it will be 0. This is done to give the
660 * programmer some control over how the two more-or-less independent
661 * interrupt sources on the board are handled.
662 * If the attention flag is set when drstrategy() is called to start a
663 * dma read or write an interrupt will be generated as soon as the
664 * strategy routine enables interrupts for dma end-of-range. This will
665 * cause execution of the interrupt routine (not necessarily bad) and
666 * will cause the interrupt enable mask to be reset (very bad since the
667 * dma end-of-range condition will not be able to generate an interrupt
668 * when it occurs) causing the dma operation to time-out (even though
669 * the dma transfer will be done successfully) or hang the process if a
670 * software time-out capability is not implemented. One way to avoid
671 * this situation is to check for a pending attention interrupt (attf
672 * set) by calling drioctl() before doing a read or a write. For the
673 * time being this driver will solve the problem by clearing the attf
674 * flag in the status register before enabling interrupts in
675 * drstrategy().
676 *
677 * **** The IKON 10084 for which this driver is written will set both
678 * attf and dmaf if dma is terminated by an attention pulse. This will
679 * cause a wakeup(&dr_aux), which will be ignored since it is not being
680 * waited on, and an iodone(bp) which is the desired action. Some other
681 * dr11 emulators, in particular the IKON 10077 for the Multibus, donot
682 * dmaf in this case. This may require some addtional code in the inter-
683 * rupt routine to ensure that en iodone(bp) is issued when dma is term-
684 * inated by attention.
685 */
686 bp = dra->dr_actf;
687 if ((status & (ATTF | DMAF)) == 0) {
688 printf("dr%d: stray interrupt, status=%x", dr11, status);
689 return;
690 }
691 if (status & DMAF) { /* End-of-range interrupt */
692 dra->dr_flags |= DR_DMAX;
20340301
SL
693
694#ifdef DR_DEBUG
9d61b7ff
SL
695 if (DR11 & 2)
696 printf("\ndrintr: e-o-r interrupt,cstat:%lx,dr_flags:%lx",
697 status&0xffff, dra->dr_flags & DR_ACTV);
20340301 698#endif
9d61b7ff
SL
699 if ((dra->dr_flags & DR_ACTV) == 0) {
700 /* We are not doing DMA !! */
701 bp->b_flags |= B_ERROR;
702 } else {
703 if (dra->dr_op == DR_READ)
704 mtpr(P1DC, bp->b_un.b_addr);
705 dra->dr_bycnt -= bp->b_bcount;
706 if (dra->dr_bycnt >0) {
707 bp->b_un.b_addr += bp->b_bcount;
708 bp->b_bcount = (dra->dr_bycnt > NBPG) ? NBPG:
20340301 709 dra->dr_bycnt;
9d61b7ff
SL
710 drstart(rsaddr, dra, bp);
711 return;
712 }
20340301 713 }
9d61b7ff
SL
714 dra->dr_flags &= ~DR_ACTV;
715 wakeup((caddr_t)dra); /* Wakeup waiting in drwait() */
716 rsaddr->dr_pulse = (RPER|RDMA|RATN); /* reset dma e-o-r flag */
717 }
718 /*
719 * Now test for attention interrupt -- It may be set in addition to
720 * the dma e-o-r interrupt. If we get one we will issue a wakeup to
721 * the drioctl() routine which is presumable waiting for one.
722 * The program may have to monitor the attention interrupt received
723 * flag in addition to doing waits for the interrupt. Futhermore,
724 * interrupts are not enabled unless dma is in progress or drioctl()
725 * has been called to wait for attention -- this may produce some
726 * strange results if attf is set on the dr11 when a read or a write
727 * is initiated, since that will enables interrupts.
728 * **** The appropriate code for this interrupt routine will probably
729 * be rather application dependent.
730 */
731 if (status & ATTF) {
732 dra->dr_flags |= DR_ATRX;
733 dra->dr_flags &= ~DR_ATWT;
734 rsaddr->dr_cstat = RATN; /* reset attention flag */
735 /*
736 * Some applications which use attention to terminate
737 * dma may also want to issue an iodone() here to
738 * wakeup physio().
739 */
740 wakeup((caddr_t)&dra->dr_cmd);
20340301 741 }
20340301
SL
742}
743
744unsigned
745drminphys(bp)
9d61b7ff 746 struct buf *bp;
20340301 747{
9d61b7ff
SL
748
749 if (bp->b_bcount > 65536)
750 bp->b_bcount = 65536;
20340301
SL
751}
752
753/*
9d61b7ff
SL
754 * This routine performs the device unique operations on the DR11W
755 * it is passed as an argument to and invoked by physio
20340301
SL
756 */
757drstrategy (bp)
9d61b7ff 758 register struct buf *bp;
20340301 759{
9d61b7ff
SL
760 register int s;
761 int unit = RSUNIT(bp->b_dev);
762 register struct rsdevice *rsaddr = RSADDR(unit);
763 register struct dr_aux *dra = &dr_aux[unit];
764 register int ok;
20340301 765#ifdef DR_DEBUG
9d61b7ff
SL
766 register char *caddr;
767 long drva();
20340301
SL
768#endif
769
9d61b7ff
SL
770 if ((dra->dr_flags & DR_OPEN) == 0) { /* Device not open */
771 bp->b_error = ENXIO;
772 bp->b_flags |= B_ERROR;
773 iodone (bp);
774 return;
775 }
776 while (dra->dr_flags & DR_ACTV)
777 /* Device is active; should never be in here... */
778 sleep((caddr_t)&dra->dr_flags,DRPRI);
779 dra->dr_actf = bp;
20340301 780#ifdef DR_DEBUG
9d61b7ff 781 drva(dra, bp->b_proc, bp->b_un.b_addr, bp->b_bcount);
20340301 782#endif
9d61b7ff
SL
783 dra->dr_oba = bp->b_un.b_addr; /* Save original addr, count */
784 dra->dr_obc = bp->b_bcount;
785 dra->dr_bycnt = bp->b_bcount; /* Save xfer count used by drintr() */
786 if ((((long)bp->b_un.b_addr & 0x3fffffff) >> PGSHIFT) !=
787 ((((long)bp->b_un.b_addr & 0x3fffffff) + bp->b_bcount) >> PGSHIFT))
788 bp->b_bcount = NBPG - (((long)bp->b_un.b_addr) & PGOFSET);
789 dra->dr_flags |= DR_ACTV; /* Mark active (use in intr handler) */
790 s = SPL_UP();
791 drstart(rsaddr,dra,bp);
792 splx(s);
793 ok = drwait(rsaddr,dra);
20340301 794#ifdef DR_DEBUG
9d61b7ff
SL
795 if (DR11 & 0x40) {
796 caddr = (char *)dra->dr_oba;
797 if (dra->dr_op == DR_READ)
798 printf("\nAfter read: (%lx)(%lx)",
799 caddr[0]&0xff, caddr[1]&0xff);
800 }
20340301 801#endif
9d61b7ff
SL
802 dra->dr_flags &= ~DR_ACTV; /* Clear active flag */
803 bp->b_un.b_addr = dra->dr_oba; /* Restore original addr, count */
804 bp->b_bcount = dra->dr_obc;
805 if (!ok)
806 bp->b_flags |= B_ERROR;
807 /* Mark buffer B_DONE,so physstrat() in ml/machdep.c won't sleep */
808 iodone(bp);
809 wakeup((caddr_t)&dra->dr_flags);
810 /*
811 * Return to the calling program (physio()). Physio() will sleep
812 * until awaken by a call to iodone() in the interupt handler --
813 * which will be called by the dispatcher when it receives dma
814 * end-of-range interrupt.
815 */
20340301
SL
816}
817
9d61b7ff
SL
818drwait(rs, dr)
819 register struct rsdevice *rs;
820 register struct dr_aux *dr;
20340301 821{
9d61b7ff 822 int s;
20340301
SL
823
824 s = SPL_UP();
9d61b7ff
SL
825 while (dr->dr_flags & DR_ACTV)
826 sleep((caddr_t)dr, DRPRI);
20340301 827 splx(s);
9d61b7ff 828 if (dr->dr_flags & DR_TMDM) { /* DMA timed out */
20340301 829 dr->dr_flags &= ~DR_TMDM;
9d61b7ff 830 return (0);
20340301 831 }
9d61b7ff
SL
832 if (rs->dr_cstat & (PERR|BERR|TERR)) {
833 dr->dr_actf->b_flags |= B_ERROR;
834 return (0);
20340301
SL
835 }
836 dr->dr_flags &= ~DR_DMAX;
9d61b7ff 837 return (1);
20340301
SL
838}
839
20340301 840/*
9d61b7ff
SL
841 *
842 * The lower 8-bit of tinfo is the minor device number, the
843 * remaining higher 8-bit is the current timout number
844 */
845drrwtimo(tinfo)
846 register u_long tinfo;
847{
848 register long unit = tinfo & 0xff;
20340301
SL
849 register struct dr_aux *dr = &dr_aux[unit];
850 register struct rsdevice *rs = dr->dr_addr;
851
9d61b7ff
SL
852 /*
853 * If this is not the timeout that drwrite/drread is waiting
854 * for then we should just go away
855 */
856 if ((tinfo &~ 0xff) != (dr->currenttimo << 8))
857 return;
20340301
SL
858 /* Mark the device timed out */
859 dr->dr_flags |= DR_TMDM;
860 dr->dr_flags &= ~DR_ACTV;
861 rs->dr_pulse = RMSK; /* Inihibit interrupt */
862 rs->dr_pulse = (RPER|RDMA|RATN|IENB); /* Clear DMA logic */
9d61b7ff
SL
863 /*
864 * Some applications will not issue a master after dma timeout,
865 * since doing so sends an INIT H pulse to the external device,
866 * which may produce undesirable side-effects.
867 */
20340301 868 /* Wake up process waiting in drwait() and flag the error */
9d61b7ff 869 dr->dr_actf->b_flags |= B_ERROR;
20340301
SL
870 wakeup((caddr_t)dr->dr_cmd);
871}
872
20340301 873/*
9d61b7ff
SL
874 * Kick the driver every second
875 */
20340301 876drtimo(dev)
9d61b7ff 877 dev_t dev;
20340301 878{
9d61b7ff 879 register int unit = RSUNIT(dev);
20340301
SL
880 register struct dr_aux *dr;
881
9d61b7ff 882 dr = &dr_aux[unit];
20340301 883 if (dr->dr_flags & DR_OPEN)
9d61b7ff 884 timeout(drtimo, (caddr_t)dev, hz);
20340301
SL
885 wakeup((caddr_t)dr); /* Wakeup any process waiting for interrupt */
886}
887
20340301 888#ifdef DR_DEBUG
9d61b7ff
SL
889drva(dra, p, va, bcnt)
890 struct dr_aux *dra;
891 struct proc *p;
892 char *va;
893 long bcnt;
894{
895 register long first, last , np;
20340301
SL
896
897 if (DR11 & 0x20) {
9d61b7ff
SL
898 first = ((long)(vtoph(p, (unsigned)va))) >> 10;
899 last = ((long)(vtoph(p, (unsigned)va+bcnt))) >> 10;
20340301
SL
900 np = bcnt / 0x3ff;
901 printf("\ndrva: (op:%ld)(first:%ld)(last:%ld)(np:%ld)(cnt:%ld)",
902 dra->dr_op,first,last,np,bcnt);
903 }
904}
905#endif
906
9d61b7ff
SL
907drstart(rsaddr, dra, bp)
908 register struct rsdevice *rsaddr;
909 register struct dr_aux *dra;
910 register struct buf *bp;
911{
912 register long addr;
913 u_short go;
20340301
SL
914
915#ifdef DR_DEBUG
9d61b7ff
SL
916 if (dra->dr_op == DR_READ && (DR11 & 8)) {
917 char *caddr = (char *)bp->b_un.b_addr;
20340301 918 printf("\ndrstart: READ, bcnt:%ld",bp->b_bcount);
20340301
SL
919 printf(",(%lx)(%lx)",caddr[0]&0xff,caddr[1]&0xff);
920 }
921#endif
9d61b7ff
SL
922 /* we are doing raw IO, bp->b_un.b_addr is user's address */
923 addr = (long)vtoph(bp->b_proc, (unsigned)bp->b_un.b_addr);
924 /*
925 * Set DMA address into DR11 interace registers: DR11 requires that
926 * the address be right shifted 1 bit position before it is written
927 * to the board (The board will left shift it one bit position before
928 * it places the address on the bus
929 */
930 rsaddr->dr_walo = (addr >> 1) & 0xffff;
931 rsaddr->dr_wahi = (addr >> 17) & 0x7fff;
932 /* Set DMA range count: (number of words - 1) */
933 rsaddr->dr_range = (bp->b_bcount >> 1) - 1;
934 /* Set address modifier code to be used for DMA access to memory */
935 rsaddr->dr_addmod = DRADDMOD;
936 /*
937 * Now determine whether this is a read or a write. ***** This is
938 * probably only usefull for link mode operation, since dr11 doesnot
939 * controll the direction of data transfer. The C1 control input
940 * controls whether the hardware is doing a read or a write. In link
941 * mode this is controlled by function 1 latch (looped back by the
942 * cable) and could be set the program. In the general case, the dr11
943 * doesnot know in advance what the direction of transfer is - although
944 * the program and protocol logic probably is
945 */
20340301 946#ifdef DR_DEBUG
9d61b7ff
SL
947 if (DR11 & 1)
948 printf(
949"\ndrstrat: about to GO..,dr_cmd:%lx,drstat:%lx,drcnt:%ld,cdata:%lx,OP:%ld",
950 dra->dr_cmd, rsaddr->dr_cstat, rsaddr->dr_range,
951 rsaddr->dr_data, dra->dr_op);
20340301 952#endif
9d61b7ff
SL
953 /*
954 * Update function latches may have been done already by drioctl() if
955 * request from drioctl()
956 */
957 if (dra->dr_cmd & DR_DFCN) { /* deferred function write */
958 dra->dr_cmd &= ~DR_DFCN; /* Clear request */
959 go = dra->dr_cmd & DR_FMSK; /* mask out fcn bits */
960 rsaddr->dr_cstat = go; /* Write it to the board */
961 }
962 /* Clear dmaf and attf to assure a clean dma start */
963 rsaddr->dr_pulse = RATN|RDMA|RPER;
964 rsaddr->dr_cstat = IENB|GO|CYCL|dra->dr_op; /* GO...... */
965 /*
966 * Now check for software cycle request -- usually
967 * by transmitter in link mode.
968 */
969 if (dra->dr_cmd & DR_PCYL) {
970 dra->dr_cmd &= ~DR_PCYL; /* Clear request */
971 rsaddr->dr_pulse = CYCL; /* Use pulse register again */
972 }
973 /*
974 * Now check for deferred ACLO FCNT2 pulse request -- usually to tell
975 * the transmitter (via its attention) that we have enabled dma.
976 */
977 if (dra->dr_cmd & DR_DACL) {
978 dra->dr_cmd &= ~DR_DACL; /* Clear request */
979 rsaddr->dr_pulse = FCN2; /* Use pulse register again */
980 }
20340301 981}
20340301 982#endif NDR