Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/jazz/jazzdma.c
10817 views
1
/*
2
* Mips Jazz DMA controller support
3
* Copyright (C) 1995, 1996 by Andreas Busse
4
*
5
* NOTE: Some of the argument checking could be removed when
6
* things have settled down. Also, instead of returning 0xffffffff
7
* on failure of vdma_alloc() one could leave page #0 unused
8
* and return the more usual NULL pointer as logical address.
9
*/
10
#include <linux/kernel.h>
11
#include <linux/init.h>
12
#include <linux/module.h>
13
#include <linux/errno.h>
14
#include <linux/mm.h>
15
#include <linux/bootmem.h>
16
#include <linux/spinlock.h>
17
#include <linux/gfp.h>
18
#include <asm/mipsregs.h>
19
#include <asm/jazz.h>
20
#include <asm/io.h>
21
#include <asm/uaccess.h>
22
#include <asm/dma.h>
23
#include <asm/jazzdma.h>
24
#include <asm/pgtable.h>
25
26
/*
27
* Set this to one to enable additional vdma debug code.
28
*/
29
#define CONF_DEBUG_VDMA 0
30
31
static VDMA_PGTBL_ENTRY *pgtbl;
32
33
static DEFINE_SPINLOCK(vdma_lock);
34
35
/*
36
* Debug stuff
37
*/
38
#define vdma_debug ((CONF_DEBUG_VDMA) ? debuglvl : 0)
39
40
static int debuglvl = 3;
41
42
/*
43
* Initialize the pagetable with a one-to-one mapping of
44
* the first 16 Mbytes of main memory and declare all
45
* entries to be unused. Using this method will at least
46
* allow some early device driver operations to work.
47
*/
48
static inline void vdma_pgtbl_init(void)
49
{
50
unsigned long paddr = 0;
51
int i;
52
53
for (i = 0; i < VDMA_PGTBL_ENTRIES; i++) {
54
pgtbl[i].frame = paddr;
55
pgtbl[i].owner = VDMA_PAGE_EMPTY;
56
paddr += VDMA_PAGESIZE;
57
}
58
}
59
60
/*
61
* Initialize the Jazz R4030 dma controller
62
*/
63
static int __init vdma_init(void)
64
{
65
/*
66
* Allocate 32k of memory for DMA page tables. This needs to be page
67
* aligned and should be uncached to avoid cache flushing after every
68
* update.
69
*/
70
pgtbl = (VDMA_PGTBL_ENTRY *)__get_free_pages(GFP_KERNEL | GFP_DMA,
71
get_order(VDMA_PGTBL_SIZE));
72
BUG_ON(!pgtbl);
73
dma_cache_wback_inv((unsigned long)pgtbl, VDMA_PGTBL_SIZE);
74
pgtbl = (VDMA_PGTBL_ENTRY *)KSEG1ADDR(pgtbl);
75
76
/*
77
* Clear the R4030 translation table
78
*/
79
vdma_pgtbl_init();
80
81
r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE, CPHYSADDR(pgtbl));
82
r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM, VDMA_PGTBL_SIZE);
83
r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0);
84
85
printk(KERN_INFO "VDMA: R4030 DMA pagetables initialized.\n");
86
return 0;
87
}
88
89
/*
90
* Allocate DMA pagetables using a simple first-fit algorithm
91
*/
92
unsigned long vdma_alloc(unsigned long paddr, unsigned long size)
93
{
94
int first, last, pages, frame, i;
95
unsigned long laddr, flags;
96
97
/* check arguments */
98
99
if (paddr > 0x1fffffff) {
100
if (vdma_debug)
101
printk("vdma_alloc: Invalid physical address: %08lx\n",
102
paddr);
103
return VDMA_ERROR; /* invalid physical address */
104
}
105
if (size > 0x400000 || size == 0) {
106
if (vdma_debug)
107
printk("vdma_alloc: Invalid size: %08lx\n", size);
108
return VDMA_ERROR; /* invalid physical address */
109
}
110
111
spin_lock_irqsave(&vdma_lock, flags);
112
/*
113
* Find free chunk
114
*/
115
pages = VDMA_PAGE(paddr + size) - VDMA_PAGE(paddr) + 1;
116
first = 0;
117
while (1) {
118
while (pgtbl[first].owner != VDMA_PAGE_EMPTY &&
119
first < VDMA_PGTBL_ENTRIES) first++;
120
if (first + pages > VDMA_PGTBL_ENTRIES) { /* nothing free */
121
spin_unlock_irqrestore(&vdma_lock, flags);
122
return VDMA_ERROR;
123
}
124
125
last = first + 1;
126
while (pgtbl[last].owner == VDMA_PAGE_EMPTY
127
&& last - first < pages)
128
last++;
129
130
if (last - first == pages)
131
break; /* found */
132
first = last + 1;
133
}
134
135
/*
136
* Mark pages as allocated
137
*/
138
laddr = (first << 12) + (paddr & (VDMA_PAGESIZE - 1));
139
frame = paddr & ~(VDMA_PAGESIZE - 1);
140
141
for (i = first; i < last; i++) {
142
pgtbl[i].frame = frame;
143
pgtbl[i].owner = laddr;
144
frame += VDMA_PAGESIZE;
145
}
146
147
/*
148
* Update translation table and return logical start address
149
*/
150
r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0);
151
152
if (vdma_debug > 1)
153
printk("vdma_alloc: Allocated %d pages starting from %08lx\n",
154
pages, laddr);
155
156
if (vdma_debug > 2) {
157
printk("LADDR: ");
158
for (i = first; i < last; i++)
159
printk("%08x ", i << 12);
160
printk("\nPADDR: ");
161
for (i = first; i < last; i++)
162
printk("%08x ", pgtbl[i].frame);
163
printk("\nOWNER: ");
164
for (i = first; i < last; i++)
165
printk("%08x ", pgtbl[i].owner);
166
printk("\n");
167
}
168
169
spin_unlock_irqrestore(&vdma_lock, flags);
170
171
return laddr;
172
}
173
174
EXPORT_SYMBOL(vdma_alloc);
175
176
/*
177
* Free previously allocated dma translation pages
178
* Note that this does NOT change the translation table,
179
* it just marks the free'd pages as unused!
180
*/
181
int vdma_free(unsigned long laddr)
182
{
183
int i;
184
185
i = laddr >> 12;
186
187
if (pgtbl[i].owner != laddr) {
188
printk
189
("vdma_free: trying to free other's dma pages, laddr=%8lx\n",
190
laddr);
191
return -1;
192
}
193
194
while (i < VDMA_PGTBL_ENTRIES && pgtbl[i].owner == laddr) {
195
pgtbl[i].owner = VDMA_PAGE_EMPTY;
196
i++;
197
}
198
199
if (vdma_debug > 1)
200
printk("vdma_free: freed %ld pages starting from %08lx\n",
201
i - (laddr >> 12), laddr);
202
203
return 0;
204
}
205
206
EXPORT_SYMBOL(vdma_free);
207
208
/*
209
* Map certain page(s) to another physical address.
210
* Caller must have allocated the page(s) before.
211
*/
212
int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size)
213
{
214
int first, pages;
215
216
if (laddr > 0xffffff) {
217
if (vdma_debug)
218
printk
219
("vdma_map: Invalid logical address: %08lx\n",
220
laddr);
221
return -EINVAL; /* invalid logical address */
222
}
223
if (paddr > 0x1fffffff) {
224
if (vdma_debug)
225
printk
226
("vdma_map: Invalid physical address: %08lx\n",
227
paddr);
228
return -EINVAL; /* invalid physical address */
229
}
230
231
pages = (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1;
232
first = laddr >> 12;
233
if (vdma_debug)
234
printk("vdma_remap: first=%x, pages=%x\n", first, pages);
235
if (first + pages > VDMA_PGTBL_ENTRIES) {
236
if (vdma_debug)
237
printk("vdma_alloc: Invalid size: %08lx\n", size);
238
return -EINVAL;
239
}
240
241
paddr &= ~(VDMA_PAGESIZE - 1);
242
while (pages > 0 && first < VDMA_PGTBL_ENTRIES) {
243
if (pgtbl[first].owner != laddr) {
244
if (vdma_debug)
245
printk("Trying to remap other's pages.\n");
246
return -EPERM; /* not owner */
247
}
248
pgtbl[first].frame = paddr;
249
paddr += VDMA_PAGESIZE;
250
first++;
251
pages--;
252
}
253
254
/*
255
* Update translation table
256
*/
257
r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0);
258
259
if (vdma_debug > 2) {
260
int i;
261
pages = (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1;
262
first = laddr >> 12;
263
printk("LADDR: ");
264
for (i = first; i < first + pages; i++)
265
printk("%08x ", i << 12);
266
printk("\nPADDR: ");
267
for (i = first; i < first + pages; i++)
268
printk("%08x ", pgtbl[i].frame);
269
printk("\nOWNER: ");
270
for (i = first; i < first + pages; i++)
271
printk("%08x ", pgtbl[i].owner);
272
printk("\n");
273
}
274
275
return 0;
276
}
277
278
/*
279
* Translate a physical address to a logical address.
280
* This will return the logical address of the first
281
* match.
282
*/
283
unsigned long vdma_phys2log(unsigned long paddr)
284
{
285
int i;
286
int frame;
287
288
frame = paddr & ~(VDMA_PAGESIZE - 1);
289
290
for (i = 0; i < VDMA_PGTBL_ENTRIES; i++) {
291
if (pgtbl[i].frame == frame)
292
break;
293
}
294
295
if (i == VDMA_PGTBL_ENTRIES)
296
return ~0UL;
297
298
return (i << 12) + (paddr & (VDMA_PAGESIZE - 1));
299
}
300
301
EXPORT_SYMBOL(vdma_phys2log);
302
303
/*
304
* Translate a logical DMA address to a physical address
305
*/
306
unsigned long vdma_log2phys(unsigned long laddr)
307
{
308
return pgtbl[laddr >> 12].frame + (laddr & (VDMA_PAGESIZE - 1));
309
}
310
311
EXPORT_SYMBOL(vdma_log2phys);
312
313
/*
314
* Print DMA statistics
315
*/
316
void vdma_stats(void)
317
{
318
int i;
319
320
printk("vdma_stats: CONFIG: %08x\n",
321
r4030_read_reg32(JAZZ_R4030_CONFIG));
322
printk("R4030 translation table base: %08x\n",
323
r4030_read_reg32(JAZZ_R4030_TRSTBL_BASE));
324
printk("R4030 translation table limit: %08x\n",
325
r4030_read_reg32(JAZZ_R4030_TRSTBL_LIM));
326
printk("vdma_stats: INV_ADDR: %08x\n",
327
r4030_read_reg32(JAZZ_R4030_INV_ADDR));
328
printk("vdma_stats: R_FAIL_ADDR: %08x\n",
329
r4030_read_reg32(JAZZ_R4030_R_FAIL_ADDR));
330
printk("vdma_stats: M_FAIL_ADDR: %08x\n",
331
r4030_read_reg32(JAZZ_R4030_M_FAIL_ADDR));
332
printk("vdma_stats: IRQ_SOURCE: %08x\n",
333
r4030_read_reg32(JAZZ_R4030_IRQ_SOURCE));
334
printk("vdma_stats: I386_ERROR: %08x\n",
335
r4030_read_reg32(JAZZ_R4030_I386_ERROR));
336
printk("vdma_chnl_modes: ");
337
for (i = 0; i < 8; i++)
338
printk("%04x ",
339
(unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_MODE +
340
(i << 5)));
341
printk("\n");
342
printk("vdma_chnl_enables: ");
343
for (i = 0; i < 8; i++)
344
printk("%04x ",
345
(unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
346
(i << 5)));
347
printk("\n");
348
}
349
350
/*
351
* DMA transfer functions
352
*/
353
354
/*
355
* Enable a DMA channel. Also clear any error conditions.
356
*/
357
void vdma_enable(int channel)
358
{
359
int status;
360
361
if (vdma_debug)
362
printk("vdma_enable: channel %d\n", channel);
363
364
/*
365
* Check error conditions first
366
*/
367
status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5));
368
if (status & 0x400)
369
printk("VDMA: Channel %d: Address error!\n", channel);
370
if (status & 0x200)
371
printk("VDMA: Channel %d: Memory error!\n", channel);
372
373
/*
374
* Clear all interrupt flags
375
*/
376
r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
377
r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
378
(channel << 5)) | R4030_TC_INTR
379
| R4030_MEM_INTR | R4030_ADDR_INTR);
380
381
/*
382
* Enable the desired channel
383
*/
384
r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
385
r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
386
(channel << 5)) |
387
R4030_CHNL_ENABLE);
388
}
389
390
EXPORT_SYMBOL(vdma_enable);
391
392
/*
393
* Disable a DMA channel
394
*/
395
void vdma_disable(int channel)
396
{
397
if (vdma_debug) {
398
int status =
399
r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
400
(channel << 5));
401
402
printk("vdma_disable: channel %d\n", channel);
403
printk("VDMA: channel %d status: %04x (%s) mode: "
404
"%02x addr: %06x count: %06x\n",
405
channel, status,
406
((status & 0x600) ? "ERROR" : "OK"),
407
(unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_MODE +
408
(channel << 5)),
409
(unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_ADDR +
410
(channel << 5)),
411
(unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_COUNT +
412
(channel << 5)));
413
}
414
415
r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
416
r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
417
(channel << 5)) &
418
~R4030_CHNL_ENABLE);
419
420
/*
421
* After disabling a DMA channel a remote bus register should be
422
* read to ensure that the current DMA acknowledge cycle is completed.
423
*/
424
*((volatile unsigned int *) JAZZ_DUMMY_DEVICE);
425
}
426
427
EXPORT_SYMBOL(vdma_disable);
428
429
/*
430
* Set DMA mode. This function accepts the mode values used
431
* to set a PC-style DMA controller. For the SCSI and FDC
432
* channels, we also set the default modes each time we're
433
* called.
434
* NOTE: The FAST and BURST dma modes are supported by the
435
* R4030 Rev. 2 and PICA chipsets only. I leave them disabled
436
* for now.
437
*/
438
void vdma_set_mode(int channel, int mode)
439
{
440
if (vdma_debug)
441
printk("vdma_set_mode: channel %d, mode 0x%x\n", channel,
442
mode);
443
444
switch (channel) {
445
case JAZZ_SCSI_DMA: /* scsi */
446
r4030_write_reg32(JAZZ_R4030_CHNL_MODE + (channel << 5),
447
/* R4030_MODE_FAST | */
448
/* R4030_MODE_BURST | */
449
R4030_MODE_INTR_EN |
450
R4030_MODE_WIDTH_16 |
451
R4030_MODE_ATIME_80);
452
break;
453
454
case JAZZ_FLOPPY_DMA: /* floppy */
455
r4030_write_reg32(JAZZ_R4030_CHNL_MODE + (channel << 5),
456
/* R4030_MODE_FAST | */
457
/* R4030_MODE_BURST | */
458
R4030_MODE_INTR_EN |
459
R4030_MODE_WIDTH_8 |
460
R4030_MODE_ATIME_120);
461
break;
462
463
case JAZZ_AUDIOL_DMA:
464
case JAZZ_AUDIOR_DMA:
465
printk("VDMA: Audio DMA not supported yet.\n");
466
break;
467
468
default:
469
printk
470
("VDMA: vdma_set_mode() called with unsupported channel %d!\n",
471
channel);
472
}
473
474
switch (mode) {
475
case DMA_MODE_READ:
476
r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
477
r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
478
(channel << 5)) &
479
~R4030_CHNL_WRITE);
480
break;
481
482
case DMA_MODE_WRITE:
483
r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
484
r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
485
(channel << 5)) |
486
R4030_CHNL_WRITE);
487
break;
488
489
default:
490
printk
491
("VDMA: vdma_set_mode() called with unknown dma mode 0x%x\n",
492
mode);
493
}
494
}
495
496
EXPORT_SYMBOL(vdma_set_mode);
497
498
/*
499
* Set Transfer Address
500
*/
501
void vdma_set_addr(int channel, long addr)
502
{
503
if (vdma_debug)
504
printk("vdma_set_addr: channel %d, addr %lx\n", channel,
505
addr);
506
507
r4030_write_reg32(JAZZ_R4030_CHNL_ADDR + (channel << 5), addr);
508
}
509
510
EXPORT_SYMBOL(vdma_set_addr);
511
512
/*
513
* Set Transfer Count
514
*/
515
void vdma_set_count(int channel, int count)
516
{
517
if (vdma_debug)
518
printk("vdma_set_count: channel %d, count %08x\n", channel,
519
(unsigned) count);
520
521
r4030_write_reg32(JAZZ_R4030_CHNL_COUNT + (channel << 5), count);
522
}
523
524
EXPORT_SYMBOL(vdma_set_count);
525
526
/*
527
* Get Residual
528
*/
529
int vdma_get_residue(int channel)
530
{
531
int residual;
532
533
residual = r4030_read_reg32(JAZZ_R4030_CHNL_COUNT + (channel << 5));
534
535
if (vdma_debug)
536
printk("vdma_get_residual: channel %d: residual=%d\n",
537
channel, residual);
538
539
return residual;
540
}
541
542
/*
543
* Get DMA channel enable register
544
*/
545
int vdma_get_enable(int channel)
546
{
547
int enable;
548
549
enable = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5));
550
551
if (vdma_debug)
552
printk("vdma_get_enable: channel %d: enable=%d\n", channel,
553
enable);
554
555
return enable;
556
}
557
558
arch_initcall(vdma_init);
559
560