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