static void __dma_clear_buffer(struct page *page, size_t size)
 {
-       void *ptr;
        /*
         * Ensure that the allocated pages are zeroed, and that any data
         * lurking in the kernel direct-mapped region is invalidated.
         */
-       ptr = page_address(page);
-       if (ptr) {
+       if (PageHighMem(page)) {
+               phys_addr_t base = __pfn_to_phys(page_to_pfn(page));
+               phys_addr_t end = base + size;
+               while (size > 0) {
+                       void *ptr = kmap_atomic(page);
+                       memset(ptr, 0, PAGE_SIZE);
+                       dmac_flush_range(ptr, ptr + PAGE_SIZE);
+                       kunmap_atomic(ptr);
+                       page++;
+                       size -= PAGE_SIZE;
+               }
+               outer_flush_range(base, end);
+       } else {
+               void *ptr = page_address(page);
                memset(ptr, 0, size);
                dmac_flush_range(ptr, ptr + size);
                outer_flush_range(__pa(ptr), __pa(ptr) + size);
 #endif
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
-                                    pgprot_t prot, struct page **ret_page);
+                                    pgprot_t prot, struct page **ret_page,
+                                    const void *caller);
 
 static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
                                 pgprot_t prot, struct page **ret_page,
                goto no_pages;
 
        if (IS_ENABLED(CONFIG_CMA))
-               ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page);
+               ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page,
+                                             atomic_pool_init);
        else
                ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot,
-                                          &page, NULL);
+                                          &page, atomic_pool_init);
        if (ptr) {
                int i;
 
 }
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
-                                    pgprot_t prot, struct page **ret_page)
+                                    pgprot_t prot, struct page **ret_page,
+                                    const void *caller)
 {
        unsigned long order = get_order(size);
        size_t count = size >> PAGE_SHIFT;
        struct page *page;
+       void *ptr;
 
        page = dma_alloc_from_contiguous(dev, count, order);
        if (!page)
                return NULL;
 
        __dma_clear_buffer(page, size);
-       __dma_remap(page, size, prot);
 
+       if (PageHighMem(page)) {
+               ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller);
+               if (!ptr) {
+                       dma_release_from_contiguous(dev, page, count);
+                       return NULL;
+               }
+       } else {
+               __dma_remap(page, size, prot);
+               ptr = page_address(page);
+       }
        *ret_page = page;
-       return page_address(page);
+       return ptr;
 }
 
 static void __free_from_contiguous(struct device *dev, struct page *page,
-                                  size_t size)
+                                  void *cpu_addr, size_t size)
 {
-       __dma_remap(page, size, pgprot_kernel);
+       if (PageHighMem(page))
+               __dma_free_remap(cpu_addr, size);
+       else
+               __dma_remap(page, size, pgprot_kernel);
        dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
 }
 
 #define __get_dma_pgprot(attrs, prot)  __pgprot(0)
 #define __alloc_remap_buffer(dev, size, gfp, prot, ret, c)     NULL
 #define __alloc_from_pool(size, ret_page)                      NULL
-#define __alloc_from_contiguous(dev, size, prot, ret)          NULL
+#define __alloc_from_contiguous(dev, size, prot, ret, c)       NULL
 #define __free_from_pool(cpu_addr, size)                       0
-#define __free_from_contiguous(dev, page, size)                        do { } while (0)
+#define __free_from_contiguous(dev, page, cpu_addr, size)      do { } while (0)
 #define __dma_free_remap(cpu_addr, size)                       do { } while (0)
 
 #endif /* CONFIG_MMU */
        else if (!IS_ENABLED(CONFIG_CMA))
                addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
        else
-               addr = __alloc_from_contiguous(dev, size, prot, &page);
+               addr = __alloc_from_contiguous(dev, size, prot, &page, caller);
 
        if (addr)
                *handle = pfn_to_dma(dev, page_to_pfn(page));
                 * Non-atomic allocations cannot be freed with IRQs disabled
                 */
                WARN_ON(irqs_disabled());
-               __free_from_contiguous(dev, page, size);
+               __free_from_contiguous(dev, page, cpu_addr, size);
        }
 }