ANDROID: GKI: arm64: add support for NO_KERNEL_MAPPING and STRONGLY_ORDERED

arm64 needs support for both DMA_ATTR_NO_KERNEL_MAPPING and
DMA_ATTR_STRONGLY_ORDERD. Add support for both of them.

Change-Id: I35d670b8639fed465d2adbe8972ded40bd9f1d1c
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
Signed-off-by: Patrick Daly <pdaly@codeaurora.org>
Bug: 155522481
Signed-off-by: Mark Salyzyn <salyzyn@google.com>
[saravanak snapshot from commit 79efc458af96 that approximately matches
commit 28a88c9d84abb3180bc651a29074f79ef0474b48]
Signed-off-by: Saravana Kannan <saravanak@google.com>
This commit is contained in:
Laura Abbott
2014-08-05 20:11:44 -07:00
committed by Saravana Kannan
parent 9257548d3c
commit 4ac42c4404

View File

@@ -44,13 +44,16 @@ static int swiotlb __ro_after_init;
static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot,
bool coherent)
{
if (!coherent || (attrs & DMA_ATTR_WRITE_COMBINE))
if (attrs & DMA_ATTR_STRONGLY_ORDERED)
return pgprot_noncached(prot);
else if (!coherent || (attrs & DMA_ATTR_WRITE_COMBINE))
return pgprot_writecombine(prot);
return prot;
}
static struct gen_pool *atomic_pool __ro_after_init;
#define NO_KERNEL_MAPPING_DUMMY 0x2222
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
@@ -98,6 +101,43 @@ static int __free_from_pool(void *start, size_t size)
return 1;
}
static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr,
void *data)
{
struct page *page = virt_to_page(addr);
pgprot_t prot = *(pgprot_t *)data;
set_pte(pte, mk_pte(page, prot));
return 0;
}
static int __dma_clear_pte(pte_t *pte, pgtable_t token, unsigned long addr,
void *data)
{
pte_clear(&init_mm, addr, pte);
return 0;
}
static void __dma_remap(struct page *page, size_t size, pgprot_t prot,
bool no_kernel_map)
{
unsigned long start = (unsigned long) page_address(page);
unsigned long end = start + size;
int (*func)(pte_t *pte, pgtable_t token, unsigned long addr,
void *data);
if (no_kernel_map)
func = __dma_clear_pte;
else
func = __dma_update_pte;
apply_to_page_range(&init_mm, start, size, func, &prot);
/* ensure prot is applied before returning */
mb();
flush_tlb_kernel_range(start, end);
}
static void *__dma_alloc(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flags,
unsigned long attrs)
@@ -127,19 +167,31 @@ static void *__dma_alloc(struct device *dev, size_t size,
if (coherent)
return ptr;
/* remove any dirty cache lines on the kernel alias */
__dma_flush_area(ptr, size);
/* create a coherent mapping */
page = virt_to_page(ptr);
coherent_ptr = dma_common_contiguous_remap(page, size, VM_USERMAP,
prot, __builtin_return_address(0));
if (!coherent_ptr)
goto no_map;
if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
coherent_ptr = (void *)NO_KERNEL_MAPPING_DUMMY;
__dma_remap(virt_to_page(ptr), size, __pgprot(0), true);
} else {
if ((attrs & DMA_ATTR_STRONGLY_ORDERED))
__dma_remap(virt_to_page(ptr), size, __pgprot(0), true);
/* create a coherent mapping */
page = virt_to_page(ptr);
coherent_ptr = dma_common_contiguous_remap(
page, size, VM_USERMAP, prot,
__builtin_return_address(0));
if (!coherent_ptr)
goto no_map;
}
return coherent_ptr;
no_map:
if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) ||
(attrs & DMA_ATTR_STRONGLY_ORDERED))
__dma_remap(phys_to_page(dma_to_phys(dev, *dma_handle)),
size, PAGE_KERNEL, false);
swiotlb_free(dev, size, ptr, *dma_handle, attrs);
no_mem:
return NULL;
@@ -153,11 +205,17 @@ static void __dma_free(struct device *dev, size_t size,
size = PAGE_ALIGN(size);
if (!is_device_dma_coherent(dev)) {
if (!is_dma_coherent(dev, attrs)) {
if (__free_from_pool(vaddr, size))
return;
vunmap(vaddr);
if (!(attrs & DMA_ATTR_NO_KERNEL_MAPPING))
vunmap(vaddr);
}
if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) ||
(attrs & DMA_ATTR_STRONGLY_ORDERED))
__dma_remap(phys_to_page(dma_to_phys(dev, dma_handle)),
size, PAGE_KERNEL, false);
swiotlb_free(dev, size, swiotlb_addr, dma_handle, attrs);
}