linux/arch/csky/mm/dma-mapping.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
   3
   4#include <linux/cache.h>
   5#include <linux/dma-mapping.h>
   6#include <linux/dma-contiguous.h>
   7#include <linux/dma-noncoherent.h>
   8#include <linux/genalloc.h>
   9#include <linux/highmem.h>
  10#include <linux/io.h>
  11#include <linux/mm.h>
  12#include <linux/scatterlist.h>
  13#include <linux/types.h>
  14#include <linux/version.h>
  15#include <asm/cache.h>
  16
  17static inline void cache_op(phys_addr_t paddr, size_t size,
  18                            void (*fn)(unsigned long start, unsigned long end))
  19{
  20        struct page *page    = phys_to_page(paddr);
  21        void *start          = __va(page_to_phys(page));
  22        unsigned long offset = offset_in_page(paddr);
  23        size_t left          = size;
  24
  25        do {
  26                size_t len = left;
  27
  28                if (offset + len > PAGE_SIZE)
  29                        len = PAGE_SIZE - offset;
  30
  31                if (PageHighMem(page)) {
  32                        start = kmap_atomic(page);
  33
  34                        fn((unsigned long)start + offset,
  35                                        (unsigned long)start + offset + len);
  36
  37                        kunmap_atomic(start);
  38                } else {
  39                        fn((unsigned long)start + offset,
  40                                        (unsigned long)start + offset + len);
  41                }
  42                offset = 0;
  43
  44                page++;
  45                start += PAGE_SIZE;
  46                left -= len;
  47        } while (left);
  48}
  49
  50static void dma_wbinv_set_zero_range(unsigned long start, unsigned long end)
  51{
  52        memset((void *)start, 0, end - start);
  53        dma_wbinv_range(start, end);
  54}
  55
  56void arch_dma_prep_coherent(struct page *page, size_t size)
  57{
  58        cache_op(page_to_phys(page), size, dma_wbinv_set_zero_range);
  59}
  60
  61void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
  62                enum dma_data_direction dir)
  63{
  64        switch (dir) {
  65        case DMA_TO_DEVICE:
  66                cache_op(paddr, size, dma_wb_range);
  67                break;
  68        case DMA_FROM_DEVICE:
  69        case DMA_BIDIRECTIONAL:
  70                cache_op(paddr, size, dma_wbinv_range);
  71                break;
  72        default:
  73                BUG();
  74        }
  75}
  76
  77void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
  78                enum dma_data_direction dir)
  79{
  80        switch (dir) {
  81        case DMA_TO_DEVICE:
  82                return;
  83        case DMA_FROM_DEVICE:
  84        case DMA_BIDIRECTIONAL:
  85                cache_op(paddr, size, dma_inv_range);
  86                break;
  87        default:
  88                BUG();
  89        }
  90}
  91