FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/isa_dma.c
1 /*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD: src/sys/i386/isa/isa_dma.c,v 1.16.2.1 2005/03/07 13:10:47 phk Exp $");
37
38 /*
39 * code to manage AT bus
40 *
41 * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
42 * Fixed uninitialized variable problem and added code to deal
43 * with DMA page boundaries in isa_dmarangecheck(). Fixed word
44 * mode DMA count compution and reorganized DMA setup code in
45 * isa_dmastart()
46 */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/bus.h>
51 #include <sys/kernel.h>
52 #include <sys/malloc.h>
53 #include <sys/lock.h>
54 #include <sys/proc.h>
55 #include <sys/mutex.h>
56 #include <sys/module.h>
57 #include <vm/vm.h>
58 #include <vm/vm_param.h>
59 #include <vm/pmap.h>
60 #include <i386/isa/isa.h>
61 #include <dev/ic/i8237.h>
62 #include <isa/isavar.h>
63
64 /*
65 ** Register definitions for DMA controller 1 (channels 0..3):
66 */
67 #define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
68 #define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
69 #define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
70 #define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
71
72 /*
73 ** Register definitions for DMA controller 2 (channels 4..7):
74 */
75 #define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */
76 #define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
77 #define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
78 #define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
79
80 static int isa_dmarangecheck(caddr_t va, u_int length, int chan);
81
82 static caddr_t dma_bouncebuf[8];
83 static u_int dma_bouncebufsize[8];
84 static u_int8_t dma_bounced = 0;
85 static u_int8_t dma_busy = 0; /* Used in isa_dmastart() */
86 static u_int8_t dma_inuse = 0; /* User for acquire/release */
87 static u_int8_t dma_auto_mode = 0;
88
89 #define VALID_DMA_MASK (7)
90
91 /* high byte of address is stored in this port for i-th dma channel */
92 static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
93
94 /*
95 * Setup a DMA channel's bounce buffer.
96 */
97 void
98 isa_dmainit(chan, bouncebufsize)
99 int chan;
100 u_int bouncebufsize;
101 {
102 void *buf;
103
104 /*
105 * If a DMA channel is shared, both drivers have to call isa_dmainit
106 * since they don't know that the other driver will do it.
107 * Just return if we're already set up good.
108 * XXX: this only works if they agree on the bouncebuf size. This
109 * XXX: is typically the case since they are multiple instances of
110 * XXX: the same driver.
111 */
112 if (dma_bouncebuf[chan] != NULL)
113 return;
114
115 #ifdef DIAGNOSTIC
116 if (chan & ~VALID_DMA_MASK)
117 panic("isa_dmainit: channel out of range");
118 #endif
119
120 dma_bouncebufsize[chan] = bouncebufsize;
121
122 /* Try malloc() first. It works better if it works. */
123 buf = malloc(bouncebufsize, M_DEVBUF, M_NOWAIT);
124 if (buf != NULL) {
125 if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) {
126 dma_bouncebuf[chan] = buf;
127 return;
128 }
129 free(buf, M_DEVBUF);
130 }
131 buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful,
132 1ul, chan & 4 ? 0x20000ul : 0x10000ul);
133 if (buf == NULL)
134 printf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize);
135 else
136 dma_bouncebuf[chan] = buf;
137 }
138
139 /*
140 * Register a DMA channel's usage. Usually called from a device driver
141 * in open() or during its initialization.
142 */
143 int
144 isa_dma_acquire(chan)
145 int chan;
146 {
147 #ifdef DIAGNOSTIC
148 if (chan & ~VALID_DMA_MASK)
149 panic("isa_dma_acquire: channel out of range");
150 #endif
151
152 if (dma_inuse & (1 << chan)) {
153 printf("isa_dma_acquire: channel %d already in use\n", chan);
154 return (EBUSY);
155 }
156 dma_inuse |= (1 << chan);
157 dma_auto_mode &= ~(1 << chan);
158
159 return (0);
160 }
161
162 /*
163 * Unregister a DMA channel's usage. Usually called from a device driver
164 * during close() or during its shutdown.
165 */
166 void
167 isa_dma_release(chan)
168 int chan;
169 {
170 #ifdef DIAGNOSTIC
171 if (chan & ~VALID_DMA_MASK)
172 panic("isa_dma_release: channel out of range");
173
174 if ((dma_inuse & (1 << chan)) == 0)
175 printf("isa_dma_release: channel %d not in use\n", chan);
176 #endif
177
178 if (dma_busy & (1 << chan)) {
179 dma_busy &= ~(1 << chan);
180 /*
181 * XXX We should also do "dma_bounced &= (1 << chan);"
182 * because we are acting on behalf of isa_dmadone() which
183 * was not called to end the last DMA operation. This does
184 * not matter now, but it may in the future.
185 */
186 }
187
188 dma_inuse &= ~(1 << chan);
189 dma_auto_mode &= ~(1 << chan);
190 }
191
192 /*
193 * isa_dmacascade(): program 8237 DMA controller channel to accept
194 * external dma control by a board.
195 */
196 void
197 isa_dmacascade(chan)
198 int chan;
199 {
200 #ifdef DIAGNOSTIC
201 if (chan & ~VALID_DMA_MASK)
202 panic("isa_dmacascade: channel out of range");
203 #endif
204
205 /* set dma channel mode, and set dma channel mode */
206 if ((chan & 4) == 0) {
207 outb(DMA1_MODE, DMA37MD_CASCADE | chan);
208 outb(DMA1_SMSK, chan);
209 } else {
210 outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
211 outb(DMA2_SMSK, chan & 3);
212 }
213 }
214
215 /*
216 * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
217 * problems by using a bounce buffer.
218 */
219 void
220 isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
221 {
222 vm_paddr_t phys;
223 int waport;
224 caddr_t newaddr;
225
226 GIANT_REQUIRED;
227
228 #ifdef DIAGNOSTIC
229 if (chan & ~VALID_DMA_MASK)
230 panic("isa_dmastart: channel out of range");
231
232 if ((chan < 4 && nbytes > (1<<16))
233 || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
234 panic("isa_dmastart: impossible request");
235
236 if ((dma_inuse & (1 << chan)) == 0)
237 printf("isa_dmastart: channel %d not acquired\n", chan);
238 #endif
239
240 #if 0
241 /*
242 * XXX This should be checked, but drivers like ad1848 only call
243 * isa_dmastart() once because they use Auto DMA mode. If we
244 * leave this in, drivers that do this will print this continuously.
245 */
246 if (dma_busy & (1 << chan))
247 printf("isa_dmastart: channel %d busy\n", chan);
248 #endif
249
250 dma_busy |= (1 << chan);
251
252 if (isa_dmarangecheck(addr, nbytes, chan)) {
253 if (dma_bouncebuf[chan] == NULL
254 || dma_bouncebufsize[chan] < nbytes)
255 panic("isa_dmastart: bad bounce buffer");
256 dma_bounced |= (1 << chan);
257 newaddr = dma_bouncebuf[chan];
258
259 /* copy bounce buffer on write */
260 if (!(flags & ISADMA_READ))
261 bcopy(addr, newaddr, nbytes);
262 addr = newaddr;
263 }
264
265 /* translate to physical */
266 phys = pmap_extract(kernel_pmap, (vm_offset_t)addr);
267
268 if (flags & ISADMA_RAW) {
269 dma_auto_mode |= (1 << chan);
270 } else {
271 dma_auto_mode &= ~(1 << chan);
272 }
273
274 if ((chan & 4) == 0) {
275 /*
276 * Program one of DMA channels 0..3. These are
277 * byte mode channels.
278 */
279 /* set dma channel mode, and reset address ff */
280
281 /* If ISADMA_RAW flag is set, then use autoinitialise mode */
282 if (flags & ISADMA_RAW) {
283 if (flags & ISADMA_READ)
284 outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
285 else
286 outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
287 }
288 else
289 if (flags & ISADMA_READ)
290 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
291 else
292 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
293 outb(DMA1_FFC, 0);
294
295 /* send start address */
296 waport = DMA1_CHN(chan);
297 outb(waport, phys);
298 outb(waport, phys>>8);
299 outb(dmapageport[chan], phys>>16);
300
301 /* send count */
302 outb(waport + 1, --nbytes);
303 outb(waport + 1, nbytes>>8);
304
305 /* unmask channel */
306 outb(DMA1_SMSK, chan);
307 } else {
308 /*
309 * Program one of DMA channels 4..7. These are
310 * word mode channels.
311 */
312 /* set dma channel mode, and reset address ff */
313
314 /* If ISADMA_RAW flag is set, then use autoinitialise mode */
315 if (flags & ISADMA_RAW) {
316 if (flags & ISADMA_READ)
317 outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3));
318 else
319 outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3));
320 }
321 else
322 if (flags & ISADMA_READ)
323 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
324 else
325 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
326 outb(DMA2_FFC, 0);
327
328 /* send start address */
329 waport = DMA2_CHN(chan - 4);
330 outb(waport, phys>>1);
331 outb(waport, phys>>9);
332 outb(dmapageport[chan], phys>>16);
333
334 /* send count */
335 nbytes >>= 1;
336 outb(waport + 2, --nbytes);
337 outb(waport + 2, nbytes>>8);
338
339 /* unmask channel */
340 outb(DMA2_SMSK, chan & 3);
341 }
342 }
343
344 void
345 isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
346 {
347 #ifdef DIAGNOSTIC
348 if (chan & ~VALID_DMA_MASK)
349 panic("isa_dmadone: channel out of range");
350
351 if ((dma_inuse & (1 << chan)) == 0)
352 printf("isa_dmadone: channel %d not acquired\n", chan);
353 #endif
354
355 if (((dma_busy & (1 << chan)) == 0) &&
356 (dma_auto_mode & (1 << chan)) == 0 )
357 printf("isa_dmadone: channel %d not busy\n", chan);
358
359 if ((dma_auto_mode & (1 << chan)) == 0)
360 outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4);
361
362 if (dma_bounced & (1 << chan)) {
363 /* copy bounce buffer on read */
364 if (flags & ISADMA_READ)
365 bcopy(dma_bouncebuf[chan], addr, nbytes);
366
367 dma_bounced &= ~(1 << chan);
368 }
369 dma_busy &= ~(1 << chan);
370 }
371
372 /*
373 * Check for problems with the address range of a DMA transfer
374 * (non-contiguous physical pages, outside of bus address space,
375 * crossing DMA page boundaries).
376 * Return true if special handling needed.
377 */
378
379 static int
380 isa_dmarangecheck(caddr_t va, u_int length, int chan)
381 {
382 vm_paddr_t phys, priorpage = 0;
383 vm_offset_t endva;
384 u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
385
386 GIANT_REQUIRED;
387
388 endva = (vm_offset_t)round_page((vm_offset_t)va + length);
389 for (; va < (caddr_t) endva ; va += PAGE_SIZE) {
390 phys = trunc_page(pmap_extract(kernel_pmap, (vm_offset_t)va));
391 #define ISARAM_END RAM_END
392 if (phys == 0)
393 panic("isa_dmacheck: no physical page present");
394 if (phys >= ISARAM_END)
395 return (1);
396 if (priorpage) {
397 if (priorpage + PAGE_SIZE != phys)
398 return (1);
399 /* check if crossing a DMA page boundary */
400 if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
401 return (1);
402 }
403 priorpage = phys;
404 }
405 return (0);
406 }
407
408 /*
409 * Query the progress of a transfer on a DMA channel.
410 *
411 * To avoid having to interrupt a transfer in progress, we sample
412 * each of the high and low databytes twice, and apply the following
413 * logic to determine the correct count.
414 *
415 * Reads are performed with interrupts disabled, thus it is to be
416 * expected that the time between reads is very small. At most
417 * one rollover in the low count byte can be expected within the
418 * four reads that are performed.
419 *
420 * There are three gaps in which a rollover can occur :
421 *
422 * - read low1
423 * gap1
424 * - read high1
425 * gap2
426 * - read low2
427 * gap3
428 * - read high2
429 *
430 * If a rollover occurs in gap1 or gap2, the low2 value will be
431 * greater than the low1 value. In this case, low2 and high2 are a
432 * corresponding pair.
433 *
434 * In any other case, low1 and high1 can be considered to be correct.
435 *
436 * The function returns the number of bytes remaining in the transfer,
437 * or -1 if the channel requested is not active.
438 *
439 */
440 int
441 isa_dmastatus(int chan)
442 {
443 u_long cnt = 0;
444 int ffport, waport;
445 u_long low1, high1, low2, high2;
446
447 /* channel active? */
448 if ((dma_inuse & (1 << chan)) == 0) {
449 printf("isa_dmastatus: channel %d not active\n", chan);
450 return(-1);
451 }
452 /* channel busy? */
453
454 if (((dma_busy & (1 << chan)) == 0) &&
455 (dma_auto_mode & (1 << chan)) == 0 ) {
456 printf("chan %d not busy\n", chan);
457 return -2 ;
458 }
459 if (chan < 4) { /* low DMA controller */
460 ffport = DMA1_FFC;
461 waport = DMA1_CHN(chan) + 1;
462 } else { /* high DMA controller */
463 ffport = DMA2_FFC;
464 waport = DMA2_CHN(chan - 4) + 2;
465 }
466
467 disable_intr(); /* no interrupts Mr Jones! */
468 outb(ffport, 0); /* clear register LSB flipflop */
469 low1 = inb(waport);
470 high1 = inb(waport);
471 outb(ffport, 0); /* clear again */
472 low2 = inb(waport);
473 high2 = inb(waport);
474 enable_intr(); /* enable interrupts again */
475
476 /*
477 * Now decide if a wrap has tried to skew our results.
478 * Note that after TC, the count will read 0xffff, while we want
479 * to return zero, so we add and then mask to compensate.
480 */
481 if (low1 >= low2) {
482 cnt = (low1 + (high1 << 8) + 1) & 0xffff;
483 } else {
484 cnt = (low2 + (high2 << 8) + 1) & 0xffff;
485 }
486
487 if (chan >= 4) /* high channels move words */
488 cnt *= 2;
489 return(cnt);
490 }
491
492 /*
493 * Reached terminal count yet ?
494 */
495 int
496 isa_dmatc(int chan)
497 {
498
499 if (chan < 4)
500 return(inb(DMA1_STATUS) & (1 << chan));
501 else
502 return(inb(DMA2_STATUS) & (1 << (chan & 3)));
503 }
504
505 /*
506 * Stop a DMA transfer currently in progress.
507 */
508 int
509 isa_dmastop(int chan)
510 {
511 if ((dma_inuse & (1 << chan)) == 0)
512 printf("isa_dmastop: channel %d not acquired\n", chan);
513
514 if (((dma_busy & (1 << chan)) == 0) &&
515 ((dma_auto_mode & (1 << chan)) == 0)) {
516 printf("chan %d not busy\n", chan);
517 return -2 ;
518 }
519
520 if ((chan & 4) == 0) {
521 outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */);
522 } else {
523 outb(DMA2_SMSK, (chan & 3) | 4 /* disable mask */);
524 }
525 return(isa_dmastatus(chan));
526 }
527
528 /*
529 * Attach to the ISA PnP descriptor for the AT DMA controller
530 */
531 static struct isa_pnp_id atdma_ids[] = {
532 { 0x0002d041 /* PNP0200 */, "AT DMA controller" },
533 { 0 }
534 };
535
536 static int
537 atdma_probe(device_t dev)
538 {
539 int result;
540
541 if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, atdma_ids)) <= 0)
542 device_quiet(dev);
543 return(result);
544 }
545
546 static int
547 atdma_attach(device_t dev)
548 {
549 return(0);
550 }
551
552 static device_method_t atdma_methods[] = {
553 /* Device interface */
554 DEVMETHOD(device_probe, atdma_probe),
555 DEVMETHOD(device_attach, atdma_attach),
556 DEVMETHOD(device_detach, bus_generic_detach),
557 DEVMETHOD(device_shutdown, bus_generic_shutdown),
558 DEVMETHOD(device_suspend, bus_generic_suspend),
559 DEVMETHOD(device_resume, bus_generic_resume),
560 { 0, 0 }
561 };
562
563 static driver_t atdma_driver = {
564 "atdma",
565 atdma_methods,
566 1, /* no softc */
567 };
568
569 static devclass_t atdma_devclass;
570
571 DRIVER_MODULE(atdma, isa, atdma_driver, atdma_devclass, 0, 0);
572 DRIVER_MODULE(atdma, acpi, atdma_driver, atdma_devclass, 0, 0);
Cache object: 5d99d6129371b63124c1981c50571124
|