Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
0003 
0004 #include <linux/cache.h>
0005 #include <linux/dma-map-ops.h>
0006 #include <linux/genalloc.h>
0007 #include <linux/highmem.h>
0008 #include <linux/io.h>
0009 #include <linux/mm.h>
0010 #include <linux/scatterlist.h>
0011 #include <linux/types.h>
0012 #include <asm/cache.h>
0013 
0014 static inline void cache_op(phys_addr_t paddr, size_t size,
0015                 void (*fn)(unsigned long start, unsigned long end))
0016 {
0017     struct page *page    = phys_to_page(paddr);
0018     void *start          = __va(page_to_phys(page));
0019     unsigned long offset = offset_in_page(paddr);
0020     size_t left          = size;
0021 
0022     do {
0023         size_t len = left;
0024 
0025         if (offset + len > PAGE_SIZE)
0026             len = PAGE_SIZE - offset;
0027 
0028         if (PageHighMem(page)) {
0029             start = kmap_atomic(page);
0030 
0031             fn((unsigned long)start + offset,
0032                     (unsigned long)start + offset + len);
0033 
0034             kunmap_atomic(start);
0035         } else {
0036             fn((unsigned long)start + offset,
0037                     (unsigned long)start + offset + len);
0038         }
0039         offset = 0;
0040 
0041         page++;
0042         start += PAGE_SIZE;
0043         left -= len;
0044     } while (left);
0045 }
0046 
0047 static void dma_wbinv_set_zero_range(unsigned long start, unsigned long end)
0048 {
0049     memset((void *)start, 0, end - start);
0050     dma_wbinv_range(start, end);
0051 }
0052 
0053 void arch_dma_prep_coherent(struct page *page, size_t size)
0054 {
0055     cache_op(page_to_phys(page), size, dma_wbinv_set_zero_range);
0056 }
0057 
0058 void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
0059         enum dma_data_direction dir)
0060 {
0061     switch (dir) {
0062     case DMA_TO_DEVICE:
0063         cache_op(paddr, size, dma_wb_range);
0064         break;
0065     case DMA_FROM_DEVICE:
0066     case DMA_BIDIRECTIONAL:
0067         cache_op(paddr, size, dma_wbinv_range);
0068         break;
0069     default:
0070         BUG();
0071     }
0072 }
0073 
0074 void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
0075         enum dma_data_direction dir)
0076 {
0077     switch (dir) {
0078     case DMA_TO_DEVICE:
0079         return;
0080     case DMA_FROM_DEVICE:
0081     case DMA_BIDIRECTIONAL:
0082         cache_op(paddr, size, dma_inv_range);
0083         break;
0084     default:
0085         BUG();
0086     }
0087 }