arch/sh: make the DMA mapping operations observe dev->dma_pfn_offset
authorThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Mon, 4 Dec 2017 15:09:01 +0000 (16:09 +0100)
committerRich Felker <dalias@libc.org>
Thu, 12 Apr 2018 23:47:53 +0000 (19:47 -0400)
Some devices may have a non-zero DMA offset, i.e an offset between the
DMA address and the physical address. Such an offset can be encoded
into the dma_pfn_offset field of "struct device", but the SuperH
implementation of the DMA mapping API does not observe this
information.

This commit fixes that by ensuring the DMA address is properly
calculated depending on this DMA offset.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: Rich Felker <dalias@libc.org>
arch/sh/kernel/dma-nommu.c
arch/sh/mm/consistent.c

index 62b485107eae0fbd5c6dc5fc76f816c42443c88d..178457d7620c3b9f55fe47b2b90736f4d83a2d2d 100644 (file)
@@ -16,7 +16,8 @@ static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
                                 enum dma_data_direction dir,
                                 unsigned long attrs)
 {
-       dma_addr_t addr = page_to_phys(page) + offset;
+       dma_addr_t addr = page_to_phys(page) + offset
+               - PFN_PHYS(dev->dma_pfn_offset);
 
        WARN_ON(size == 0);
 
@@ -36,12 +37,14 @@ static int nommu_map_sg(struct device *dev, struct scatterlist *sg,
        WARN_ON(nents == 0 || sg[0].length == 0);
 
        for_each_sg(sg, s, nents, i) {
+               dma_addr_t offset = PFN_PHYS(dev->dma_pfn_offset);
+
                BUG_ON(!sg_page(s));
 
                if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
                        sh_sync_dma_for_device(sg_virt(s), s->length, dir);
 
-               s->dma_address = sg_phys(s);
+               s->dma_address = sg_phys(s) - offset;
                s->dma_length = s->length;
        }
 
index 6ea3aab508f2211c76999d5c5d970620aa47b6a5..8ce98691d82257fb61a99c3881506bb790e60217 100644 (file)
@@ -59,7 +59,7 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
 
        split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order);
 
-       *dma_handle = virt_to_phys(ret);
+       *dma_handle = virt_to_phys(ret) - PFN_PHYS(dev->dma_pfn_offset);
 
        return ret_nocache;
 }
@@ -69,7 +69,7 @@ void dma_generic_free_coherent(struct device *dev, size_t size,
                               unsigned long attrs)
 {
        int order = get_order(size);
-       unsigned long pfn = dma_handle >> PAGE_SHIFT;
+       unsigned long pfn = (dma_handle >> PAGE_SHIFT) + dev->dma_pfn_offset;
        int k;
 
        for (k = 0; k < (1 << order); k++)