1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
29 /* All Rights Reserved */
30
31 /* Copyright (c) 1988, 1989 Intel Corp. */
32 /* All Rights Reserved */
33
34 /*
35 * Set features for each architecture. List of features:
36 * ADDR_32: Address is 32 bits
37 * COUNT_24: Count is 24 bits
38 * DMA_4CSCD: DMA channel 4 is used for cascade of channels 0-3)
39 * DMA_INTR: DMA interrupt is available (always with DMA_BUF_CHAIN)
40 * DMA_BUF_CHAIN: DMA buffer chaining is available (always with DMA_INTR)
41 * MEM_TO_MEM: Memory to memory transfers available
42 * NO_PROG_WIDTH: Channel data width is NOT programmable
43 * SCATER_GATHER Scatter-gather DMA is available (code not implemented)
44 * ISA_MODE Standard ISA modes available
45 * EISA_EXT_MODE: EISA extension modes available
46 */
47
48 /*
49 * Address is 24 bits (default) with no carry between lo word and hi byte
50 * Count is 16 bits (default)
51 */
52 #define DMA_4CSCD
53 #define NO_PROG_WIDTH
54 #define ISA_MODE
55
56 #include <sys/types.h>
57 #include <sys/cpuvar.h>
58 #include <sys/disp.h>
59 #include <sys/sunddi.h>
60 #include <sys/cmn_err.h>
61 #include <sys/dma_engine.h>
62 #include <sys/dma_i8237A.h>
63
64 #if defined(DEBUG)
65 #include <sys/promif.h>
66 static int i8237debug = 0;
67 #define dprintf(x) if (i8237debug) (void)prom_printf x
68 #else
69 #define dprintf(x)
70 #endif /* defined(DEBUG) */
71
72
73 extern int EISA_chaining;
74
75 /*
76 * data structures for maintaining the DMACs
77 */
78 static kmutex_t dma_engine_lock;
79 static struct d37A_chan_reg_addr chan_addr[] = { D37A_BASE_REGS_VALUES };
80 static ushort_t d37A_chnl_path[] = {
81 DMAE_PATH_8, /* first 4 DMA channels default to 8-bit xfers */
82 DMAE_PATH_8,
83 DMAE_PATH_8,
84 DMAE_PATH_8,
85 0,
86 DMAE_PATH_16, /* last 3 DMA channels default to 16-bit xfers */
87 DMAE_PATH_16,
88 DMAE_PATH_16};
89 static ushort_t d37A_chnl_mode[] = {
90 DMAE_TRANS_SNGL, DMAE_TRANS_SNGL, DMAE_TRANS_SNGL, DMAE_TRANS_SNGL,
91 #ifdef DMA_4CSCD
92 DMAE_TRANS_CSCD,
93 #else /* !DMA_4CSCD */
94 DMAE_TRANS_SNGL,
95 #endif /* !DMA_4CSCD */
96 DMAE_TRANS_SNGL, DMAE_TRANS_SNGL, DMAE_TRANS_SNGL};
97 #ifdef DMA_BUF_CHAIN
98 static ddi_dma_cookie_t *d37A_next_cookie[] =
99 {0, 0, 0, 0, 0, 0, 0, 0};
100 #endif /* DMA_BUF_CHAIN */
101
102
103 #ifdef DMA_INTR
104 static uint_t d37A_intr(caddr_t);
105 #endif
106 static int d37A_set_mode(struct ddi_dmae_req *, int);
107 static int d37A_write_addr(ulong_t, int);
108 static ulong_t d37A_read_addr(int);
109 static int d37A_write_count(long, int);
110 static long d37A_read_count(int);
111
112 #ifdef DMA_BUF_CHAIN
113 static void dEISA_setchain(ddi_dma_cookie_t *cp, int chnl);
114 #endif
115
116 /*
117 * Routine: d37A_init()
118 * purpose: initializes the 8237A.
119 * caller: dma_init()
120 * calls: d37A macros, d37A_init()
121 */
122
123 /*ARGSUSED*/
124 int
d37A_init(dev_info_t * dip)125 d37A_init(dev_info_t *dip)
126 {
127 #ifdef DMA_INTR
128 ddi_iblock_cookie_t iblk_cookie = 0;
129 int error;
130
131 if ((error = ddi_add_intr(dip, (uint_t)0, &iblk_cookie,
132 (ddi_idevice_cookie_t *)0, d37A_intr, (caddr_t)NULL)) !=
133 DDI_SUCCESS) {
134 if (error != DDI_INTR_NOTFOUND)
135 cmn_err(CE_WARN, "!d37A_init: cannot add dma intr\n");
136 EISA_chaining = 0;
137 }
138 mutex_init(&dma_engine_lock, NULL, MUTEX_DRIVER, (void *)iblk_cookie);
139 #else /* !DMA_INTR */
140 mutex_init(&dma_engine_lock, NULL, MUTEX_DRIVER, NULL);
141 #endif /* !DMA_INTR */
142
143 return (DDI_SUCCESS);
144 }
145
146 /*
147 * Routine: d37A_valid()
148 * purpose: validates the channel to be acquired.
149 * caller: i_dmae_acquire()
150 * calls:
151 */
152
153 int
d37A_dma_valid(int chnl)154 d37A_dma_valid(int chnl)
155 {
156 #ifdef DMA_4CSCD
157 if (chnl == 4)
158 return (0);
159 #endif /* DMA_4CSCD */
160 return (1);
161 }
162
163 /*
164 * Routine: d37A_release()
165 * purpose: resets the 8237A mode.
166 * caller: i_dmae_free()
167 * calls:
168 */
169
170 void
d37A_dma_release(int chnl)171 d37A_dma_release(int chnl)
172 {
173 #ifdef DMA_4CSCD
174 if (chnl == 4)
175 return;
176 #endif /* DMA_4CSCD */
177 d37A_chnl_mode[chnl] = DMAE_TRANS_SNGL;
178 }
179
180 /*
181 * routine: d37A_dma_disable()
182 * purpose: Prevent the DMAC from responding to external hardware
183 * requests for DMA service on the given channel
184 * caller: dma_disable()
185 * calls: d37A macros
186 */
187 void
d37A_dma_disable(int chnl)188 d37A_dma_disable(int chnl)
189 {
190 dprintf(("d37A_dma_disable: chnl=%d mask_reg=0x%x\n",
191 chnl, chan_addr[chnl].mask_reg));
192
193 outb(chan_addr[chnl].mask_reg, (chnl & 3) | DMA_SETMSK);
194 }
195
196
197 /*
198 * routine: d37A_dma_enable()
199 * purpose: Enable to DMAC to respond to hardware requests for DMA
200 * service on the specified channel.
201 * caller: dma_enable()
202 * calls: d37A macros
203 */
204
205 void
d37A_dma_enable(int chnl)206 d37A_dma_enable(int chnl)
207 {
208 dprintf(("d37A_dma_enable: chnl=%d mask_reg=0x%x val=0x%x\n",
209 chnl, chan_addr[chnl].mask_reg, chnl & 3));
210
211 /* mutex_enter(&dma_engine_lock); */
212 outb(chan_addr[chnl].mask_reg, chnl & 3);
213 /* mutex_exit(&dma_engine_lock); */
214 }
215
216
217 /*
218 * routine: d37A_get_best_mode()
219 * purpose: stub routine - determine optimum transfer method
220 * caller: dma_get_best_mode().
221 * calls:
222 */
223 /* ARGSUSED */
224 uchar_t
d37A_get_best_mode(struct ddi_dmae_req * dmaereqp)225 d37A_get_best_mode(struct ddi_dmae_req *dmaereqp)
226 {
227 return (DMAE_CYCLES_2);
228 }
229
230 #ifdef DMA_INTR
231 /*
232 * routine: d37A_intr()
233 * purpose: stub routine
234 * caller:
235 * calls: dma_intr().
236 */
237 /*ARGSUSED*/
238 static uint_t
d37A_intr(caddr_t arg)239 d37A_intr(caddr_t arg)
240 {
241 int chnl, istate, nstate;
242 uint_t mask;
243
244 if ((istate = (inb(EISA_DMAIS) & 0xef)) != 0) {
245 /* channel 4 can't interrupt */
246 chnl = 0;
247 nstate = istate;
248 mutex_enter(&dma_engine_lock);
249 do {
250 if (istate & 1) {
251 dEISA_setchain(d37A_next_cookie[chnl], chnl);
252 #ifdef DEBUG
253 if (chnl < 4)
254 mask = inb(DMAC1_ALLMASK) >> (chnl);
255 else
256 mask = inb(DMAC2_ALLMASK) >> (chnl - 4);
257 if (mask & 1)
258 prom_printf("eisa: dma buffer chaining failure chnl %d!\n", chnl);
259
260 #endif /* DEBUG */
261 }
262 chnl++;
263 istate >>= 1;
264 } while (istate);
265 chnl = 0;
266 do {
267 if ((nstate & 1) && d37A_next_cookie[chnl])
268 d37A_next_cookie[chnl] = _dmae_nxcookie(chnl);
269 chnl++;
270 nstate >>= 1;
271 } while (nstate);
272 mutex_exit(&dma_engine_lock);
273 return (DDI_INTR_CLAIMED);
274 }
275 return (DDI_INTR_UNCLAIMED);
276 }
277 #endif /* DMA_INTR */
278
279
280 #ifdef DMA_BUF_CHAIN
281 /*
282 * routine: dEISA_setchain()
283 * purpose: Set next buffer address/count from chain
284 * caller: d37A_intr()
285 * calls: d37A macros
286 */
287 static void
dEISA_setchain(ddi_dma_cookie_t * cp,int chnl)288 dEISA_setchain(ddi_dma_cookie_t *cp, int chnl)
289 {
290 if (cp) {
291 dprintf(("dEISA_setchain: chnl=%d next_addr=%x count=%lx\n",
292 chnl, cp->dmac_address, cp->dmac_size));
293 (void) d37A_write_addr(cp->dmac_address, chnl);
294 (void) d37A_write_count(cp->dmac_size, chnl);
295 outb(chan_addr[chnl].scm_reg, chnl | EISA_ENCM | EISA_CMOK);
296 } else {
297 /*
298 * clear chain enable bit
299 */
300 outb(chan_addr[chnl].scm_reg, chnl);
301 dprintf(("dEISA_setchain: chnl=%d end\n", chnl));
302 }
303 }
304 #endif /* DMA_BUF_CHAIN */
305
306
307 /*
308 * routine: d37A_prog_chan()
309 * purpose: program the Mode registers and the Base registers of a
310 * DMA channel for a subsequent hardware-initiated transfer.
311 * caller: dma_prog_chan()
312 * calls: d37A_write_addr(), d37A_write_count(), d37A macros.
313 */
314
315 int
d37A_prog_chan(struct ddi_dmae_req * dmaereqp,ddi_dma_cookie_t * cp,int chnl)316 d37A_prog_chan(struct ddi_dmae_req *dmaereqp, ddi_dma_cookie_t *cp, int chnl)
317 {
318 if (d37A_chnl_mode[chnl] == DMAE_TRANS_CSCD) {
319 dprintf(("d37A_prog_chan err: chnl=%d in cascade mode\n",
320 chnl));
321 return (DDI_FAILURE);
322 }
323 #ifndef MEM_TO_MEM
324 if (dmaereqp && dmaereqp->der_dest == DMAE_DEST_MEM) {
325 dprintf(("d37A_prog_chan err: memory to memory mode not supported.\n"));
326 return (DDI_FAILURE);
327 }
328 #endif /* !MEM_TO_MEM */
329
330 dprintf(("d37A_prog_chan: chnl=%d dmaereq=%p\n",
331 chnl, (void *)dmaereqp));
332
333 if (dmaereqp) {
334 switch (chnl) {
335 case DMAE_CH0:
336 case DMAE_CH1:
337 case DMAE_CH2:
338 case DMAE_CH3:
339 #ifdef NO_PROG_WIDTH
340 if (dmaereqp->der_path &&
341 dmaereqp->der_path != DMAE_PATH_8) {
342 dprintf(("d37A_prog_chan err: chnl %d not programmed.\n", chnl));
343 return (DDI_FAILURE);
344 }
345 #endif /* NO_PROG_WIDTH */
346 break;
347
348 #ifndef DMA_4CSCD
349 case DMAE_CH4:
350 #endif /* !DMA_4CSCD */
351 case DMAE_CH5:
352 case DMAE_CH6:
353 case DMAE_CH7:
354 #ifdef NO_PROG_WIDTH
355 if (dmaereqp->der_path &&
356 dmaereqp->der_path != DMAE_PATH_16) {
357 dprintf(("d37A_prog_chan err: chnl %d not programmed.\n", chnl));
358 return (DDI_FAILURE);
359 }
360 #endif /* NO_PROG_WIDTH */
361 break;
362
363 default:
364 dprintf(("d37A_prog_chan err: chnl %d not programmed.\n", chnl));
365 return (DDI_FAILURE);
366 }
367 } else
368 chnl &= 3;
369 mutex_enter(&dma_engine_lock);
370
371 d37A_dma_disable(chnl);
372 if (dmaereqp)
373 (void) d37A_set_mode(dmaereqp, chnl);
374
375 if (cp) {
376 (void) d37A_write_addr(cp->dmac_address, chnl);
377 (void) d37A_write_count(cp->dmac_size, chnl);
378
379 #ifdef DMA_BUF_CHAIN
380 if (dmaereqp && dmaereqp->der_bufprocess == DMAE_BUF_CHAIN &&
381 (d37A_next_cookie[chnl] = _dmae_nxcookie(chnl))) {
382 /*
383 * i/o operation has more than 1 cookie
384 * so enable dma buffer chaining
385 */
386 drv_usecwait(10);
387 outb(chan_addr[chnl].scm_reg, chnl | EISA_ENCM);
388 drv_usecwait(15);
389 dEISA_setchain(d37A_next_cookie[chnl], chnl);
390 d37A_next_cookie[chnl] = _dmae_nxcookie(chnl);
391 }
392 #endif /* DMA_BUF_CHAIN */
393 }
394 mutex_exit(&dma_engine_lock);
395 return (DDI_SUCCESS);
396 }
397
398
399 /*
400 * routine: d37A_dma_swsetup()
401 * purpose: program the Mode registers and the Base register for the
402 * specified channel.
403 * caller: dma_swsetup()
404 * calls: d37A_write_addr(), d37A_write_count(), d37A macros.
405 */
406
407 int
d37A_dma_swsetup(struct ddi_dmae_req * dmaereqp,ddi_dma_cookie_t * cp,int chnl)408 d37A_dma_swsetup(struct ddi_dmae_req *dmaereqp, ddi_dma_cookie_t *cp, int chnl)
409 {
410 if (d37A_chnl_mode[chnl] == DMAE_TRANS_CSCD) {
411 dprintf(("d37A_dma_swsetup err: chnl %d not programmed\n",
412 chnl));
413 return (DDI_FAILURE);
414 }
415
416 dprintf(("d37A_dma_swsetup: chnl=%d dmaereq=%p.\n",
417 chnl, (void *)dmaereqp));
418
419 /* MUST BE IN BLOCK MODE FOR SOFTWARE INITIATED REQUESTS */
420 if (dmaereqp->der_trans != DMAE_TRANS_BLCK)
421 dmaereqp->der_trans = DMAE_TRANS_BLCK;
422
423 switch (chnl) {
424 case DMAE_CH0:
425 case DMAE_CH1:
426 case DMAE_CH2:
427 case DMAE_CH3:
428 #ifdef NO_PROG_WIDTH
429 if (dmaereqp->der_path && dmaereqp->der_path != DMAE_PATH_8) {
430 dprintf(("d37A_dma_swsetup err: chnl %d not programmed.\n", chnl));
431 return (DDI_FAILURE);
432 }
433 #endif /* NO_PROG_WIDTH */
434 break;
435
436 #ifndef DMA_4CSCD
437 case DMAE_CH4:
438 #endif /* !DMA_4CSCD */
439 case DMAE_CH5:
440 case DMAE_CH6:
441 case DMAE_CH7:
442 #ifdef NO_PROG_WIDTH
443 if (dmaereqp->der_path && dmaereqp->der_path != DMAE_PATH_16) {
444 dprintf(("d37A_dma_swsetup err: chnl %d not programmed.\n", chnl));
445 return (DDI_FAILURE);
446 }
447 #endif /* NO_PROG_WIDTH */
448 break;
449
450 default:
451 dprintf(("d37A_dma_swsetup err: chnl %d not set up.\n", chnl));
452 return (DDI_FAILURE);
453 };
454
455 mutex_enter(&dma_engine_lock);
456
457 d37A_dma_disable(chnl);
458 (void) d37A_set_mode(dmaereqp, chnl);
459
460 (void) d37A_write_addr(cp->dmac_address, chnl);
461 (void) d37A_write_count(cp->dmac_size, chnl);
462
463 #ifdef DMA_BUF_CHAIN
464 if (dmaereqp->der_bufprocess == DMAE_BUF_CHAIN &&
465 (d37A_next_cookie[chnl] = _dmae_nxcookie(chnl))) {
466 /*
467 * i/o operation has more than 1 cookie
468 * so enable dma buffer chaining
469 */
470 outb(chan_addr[chnl].scm_reg, chnl | EISA_ENCM);
471 dEISA_setchain(d37A_next_cookie[chnl], chnl);
472 d37A_next_cookie[chnl] = _dmae_nxcookie(chnl);
473 }
474 #endif /* DMA_BUF_CHAIN */
475 mutex_exit(&dma_engine_lock);
476 return (DDI_SUCCESS);
477 }
478
479
480 /*
481 * routine: d37A_dma_swstart()
482 * purpose: SW start transfer setup on the indicated channel.
483 * caller: dma_swstart()
484 * calls: d37A_dma_enable(), d37A macros
485 */
486
487 void
d37A_dma_swstart(int chnl)488 d37A_dma_swstart(int chnl)
489 {
490 dprintf(("d37A_dma_swstart: chnl=%d\n", chnl));
491
492 mutex_enter(&dma_engine_lock);
493 d37A_dma_enable(chnl);
494 outb(chan_addr[chnl].reqt_reg, DMA_SETMSK | chnl); /* set request bit */
495 mutex_exit(&dma_engine_lock);
496 }
497
498
499 /*
500 * routine: d37A_dma_stop()
501 * purpose: Stop any activity on the indicated channel.
502 * caller: dma_stop()
503 * calls: d37A macros
504 */
505
506 void
d37A_dma_stop(int chnl)507 d37A_dma_stop(int chnl)
508 {
509 dprintf(("d37A_dma_stop: chnl=%d\n", chnl));
510
511 mutex_enter(&dma_engine_lock);
512 d37A_dma_disable(chnl);
513 outb(chan_addr[chnl].reqt_reg, chnl & 3); /* reset request bit */
514 mutex_exit(&dma_engine_lock);
515 }
516
517
518 /*
519 * routine: d37A_get_chan_stat()
520 * purpose: retrieve the Current Address and Count registers for the
521 * specified channel.
522 * caller: dma_get_chan_stat()
523 * calls: d37A_read_addr(), d37A_read_count().
524 */
525 void
d37A_get_chan_stat(int chnl,ulong_t * addressp,int * countp)526 d37A_get_chan_stat(int chnl, ulong_t *addressp, int *countp)
527 {
528 ulong_t taddr;
529 int tcount;
530
531 mutex_enter(&dma_engine_lock);
532 taddr = d37A_read_addr(chnl);
533 tcount = d37A_read_count(chnl);
534 mutex_exit(&dma_engine_lock);
535 if (addressp)
536 *addressp = taddr;
537 if (countp)
538 *countp = tcount;
539 dprintf(("d37A_get_chan_stat: chnl=%d address=%lx count=%x\n",
540 chnl, taddr, tcount));
541 }
542
543
544 /*
545 * routine: d37A_set_mode()
546 * purpose: program the Mode registers of the
547 * DMAC for a subsequent hardware-initiated transfer.
548 * caller: d37A_prog_chan(), d37A_dma_swsetup
549 * calls:
550 */
551
552 static int
d37A_set_mode(struct ddi_dmae_req * dmaereqp,int chnl)553 d37A_set_mode(struct ddi_dmae_req *dmaereqp, int chnl)
554 {
555 uchar_t mode = 0, emode = 0;
556
557 #ifdef ISA_MODE
558 #if defined(lint)
559 emode = emode;
560 #endif
561 mode = chnl & 3;
562
563 switch (dmaereqp->der_command) {
564 case DMAE_CMD_READ:
565 mode |= DMAMODE_READ;
566 break;
567 case DMAE_CMD_WRITE:
568 mode |= DMAMODE_WRITE;
569 break;
570 case DMAE_CMD_VRFY:
571 mode |= DMAMODE_VERF;
572 break;
573 case DMAE_CMD_TRAN:
574 mode |= 0x0C; /* for Adaptec 1st party DMA on chnl 0 */
575 break;
576 default:
577 return (DDI_FAILURE);
578 }
579
580 if (dmaereqp->der_bufprocess == DMAE_BUF_AUTO)
581 mode |= DMAMODE_AUTO;
582
583 if (dmaereqp->der_step == DMAE_STEP_DEC)
584 mode |= DMAMODE_DECR;
585
586 switch (dmaereqp->der_trans) {
587 case DMAE_TRANS_SNGL:
588 mode |= DMAMODE_SINGLE;
589 break;
590 case DMAE_TRANS_BLCK:
591 mode |= DMAMODE_BLOCK;
592 break;
593 case DMAE_TRANS_DMND:
594 break;
595 case DMAE_TRANS_CSCD:
596 mode |= DMAMODE_CASC;
597 break;
598 default:
599 return (DDI_FAILURE);
600 }
601 d37A_chnl_mode[chnl] = dmaereqp->der_trans;
602
603 dprintf(("d37A_set_mode: chnl=%d mode_reg=0x%x mode=0x%x\n",
604 chnl, chan_addr[chnl].mode_reg, mode));
605 outb(chan_addr[chnl].mode_reg, mode);
606 #endif /* ISA_MODE */
607
608 #ifdef EISA_EXT_MODE
609 emode = chnl & 3;
610 d37A_chnl_path[chnl] = dmaereqp->der_path;
611
612 switch (dmaereqp->der_path) {
613 case DMAE_PATH_8:
614 /* emode |= EISA_DMA_8; */
615 break;
616 case DMAE_PATH_16:
617 emode |= EISA_DMA_16;
618 break;
619 case DMAE_PATH_32:
620 emode |= EISA_DMA_32;
621 break;
622 case DMAE_PATH_16B:
623 emode |= EISA_DMA_16B;
624 break;
625 default:
626 switch (chnl) {
627 case DMAE_CH0:
628 case DMAE_CH1:
629 case DMAE_CH2:
630 case DMAE_CH3:
631 d37A_chnl_path[chnl] = DMAE_PATH_8;
632 /* emode |= EISA_DMA_8; */
633 break;
634 case DMAE_CH5:
635 case DMAE_CH6:
636 case DMAE_CH7:
637 d37A_chnl_path[chnl] = DMAE_PATH_16;
638 emode |= EISA_DMA_16;
639 break;
640 }
641 }
642 emode |= (dmaereqp->der_cycles & 3) << 4;
643 outb(chan_addr[chnl].emode_reg, emode);
644
645 dprintf(("d37A_set_mode: chnl=%d em_reg=0x%x emode=0x%x\n",
646 chnl, chan_addr[chnl].emode_reg, emode));
647 #endif /* EISA_EXT_MODE */
648 return (DDI_SUCCESS);
649 }
650
651
652 /*
653 * routine: d37A_write_addr()
654 * purpose: write the 24- or 32-bit physical address into the Base Address
655 * Register for the indicated channel.
656 * caller: d37A_prog_chan(), d37A_dma_swsetup().
657 * calls: d37A macros
658 */
659
660 static int
d37A_write_addr(ulong_t paddress,int chnl)661 d37A_write_addr(ulong_t paddress, int chnl)
662 {
663 uchar_t *adr_byte;
664
665 dprintf(("d37A_write_addr: chnl=%d address=%lx\n", chnl, paddress));
666
667 switch (d37A_chnl_path[chnl]) {
668 case DMAE_PATH_8:
669 case DMAE_PATH_16B:
670 case DMAE_PATH_32:
671 /*
672 * program DMA controller with byte address
673 */
674 break;
675
676 case DMAE_PATH_16:
677 /*
678 * convert byte address to shifted word address
679 */
680 paddress = (paddress & ~0x1ffff) | ((paddress & 0x1ffff) >> 1);
681 break;
682
683 default:
684 return (DDI_FAILURE);
685 }
686 kpreempt_disable(); /* don't preempt thread while using flip-flop */
687 outb(chan_addr[chnl].ff_reg, 0); /* set flipflop */
688
689 adr_byte = (uchar_t *)&paddress;
690 outb(chan_addr[chnl].addr_reg, adr_byte[0]);
691 outb(chan_addr[chnl].addr_reg, adr_byte[1]);
692 outb(chan_addr[chnl].page_reg, adr_byte[2]);
693 #ifdef ADDR_32
694 outb(chan_addr[chnl].hpage_reg, adr_byte[3]);
695 #endif /* ADDR_32 */
696
697 kpreempt_enable();
698 return (DDI_SUCCESS);
699 }
700
701
702 /*
703 * routine: d37A_read_addr()
704 * purpose: read the 24- or 32-bit physical address from the Current Address
705 * Register for the indicated channel.
706 * caller: d37A_get_chan_stat().
707 * calls: d37A macros
708 */
709
710 static ulong_t
d37A_read_addr(int chnl)711 d37A_read_addr(int chnl)
712 {
713 ulong_t paddress = 0;
714 uchar_t *adr_byte;
715
716 kpreempt_disable(); /* don't preempt thread while using flip-flop */
717 adr_byte = (uchar_t *)&paddress;
718 outb(chan_addr[chnl].ff_reg, 0); /* set flipflop */
719
720 adr_byte[0] = inb(chan_addr[chnl].addr_reg);
721 adr_byte[1] = inb(chan_addr[chnl].addr_reg);
722 adr_byte[2] = inb(chan_addr[chnl].page_reg);
723 #ifdef ADDR_32
724 adr_byte[3] = inb(chan_addr[chnl].hpage_reg);
725 #endif /* ADDR_32 */
726
727 kpreempt_enable();
728
729 switch (d37A_chnl_path[chnl]) {
730 case DMAE_PATH_8:
731 case DMAE_PATH_16B:
732 case DMAE_PATH_32:
733 /*
734 * return with byte address
735 */
736 break;
737
738 case DMAE_PATH_16:
739 /*
740 * convert shifted word address to byte address
741 */
742 paddress = (paddress & ~0x1ffff) | ((paddress & 0x0ffff) << 1);
743 break;
744
745 default:
746 return ((ulong_t)DDI_FAILURE);
747 }
748
749 dprintf(("d37A_read_addr: chnl=%d address=%lx.\n", chnl, paddress));
750 return (paddress);
751 }
752
753
754 /*
755 * routine: d37A_write_count()
756 * purpose: write the 16- or 24-bit count into the Base Count Register for
757 * the indicated channel.
758 * caller: d37A_prog_chan(), d37A_dma_swsetup()
759 * calls: d37A macros
760 */
761
762 static int
d37A_write_count(long count,int chnl)763 d37A_write_count(long count, int chnl)
764 {
765 uchar_t *count_byte;
766
767 dprintf(("d37A_write_count: chnl=%d count=0x%lx\n", chnl, count));
768
769 switch (d37A_chnl_path[chnl]) {
770 case DMAE_PATH_16:
771 /*
772 * Convert byte count to word count
773 */
774 count >>= 1;
775 /* FALLTHROUGH */
776 case DMAE_PATH_8:
777 case DMAE_PATH_16B:
778 case DMAE_PATH_32:
779 --count;
780 break;
781
782 default:
783 return (DDI_FAILURE);
784 }
785
786 kpreempt_disable(); /* don't preempt thread while using flip-flop */
787 outb(chan_addr[chnl].ff_reg, 0); /* set flipflop */
788
789 count_byte = (uchar_t *)&count;
790 outb(chan_addr[chnl].cnt_reg, count_byte[0]);
791 outb(chan_addr[chnl].cnt_reg, count_byte[1]);
792 #ifdef COUNT_24
793 outb(chan_addr[chnl].hcnt_reg, count_byte[2]);
794 #endif /* COUNT_24 */
795
796 kpreempt_enable();
797 return (DDI_SUCCESS);
798 }
799
800
801 /*
802 * routine: d37A_read_count()
803 * purpose: read the 16- or 24-bit count from the Current Count Register for
804 * the indicated channel
805 * caller: d37A_get_chan_stat()
806 * calls: d37A macros
807 */
808
809 static long
d37A_read_count(int chnl)810 d37A_read_count(int chnl)
811 {
812 long count = 0;
813 uchar_t *count_byte;
814
815 kpreempt_disable(); /* don't preempt thread while using flip-flop */
816 count_byte = (uchar_t *)&count;
817 outb(chan_addr[chnl].ff_reg, 0); /* set flipflop */
818
819 count_byte[0] = inb(chan_addr[chnl].cnt_reg);
820 count_byte[1] = inb(chan_addr[chnl].cnt_reg);
821 #ifdef COUNT_24
822 count_byte[2] = inb(chan_addr[chnl].hcnt_reg);
823 #endif /* COUNT_24 */
824
825 #ifdef COUNT_24
826 if ((ulong_t)count == 0xffffff)
827 #else /* !COUNT_24 */
828 if ((ulong_t)count == 0xffff)
829 #endif /* !COUNT_24 */
830 count = -1;
831
832 kpreempt_enable();
833
834 switch (d37A_chnl_path[chnl]) {
835 case DMAE_PATH_8:
836 case DMAE_PATH_16B:
837 case DMAE_PATH_32:
838 ++count;
839 break;
840
841 case DMAE_PATH_16:
842 /*
843 * Convert incremented word count to byte count
844 */
845 count = (count + 1) << 1;
846 break;
847 }
848 dprintf(("d37A_read_count: chnl=%d count=0x%lx\n", chnl, count));
849 return (count);
850 }
851