// SPDX-License-Identifier: GPL-2.0-only
 #include <linux/cpu.h>
+#include <linux/dma-direct.h>
 #include <linux/dma-noncoherent.h>
 #include <linux/gfp.h>
 #include <linux/highmem.h>
  * dma-direct functions, otherwise we call the Xen specific version.
  */
 void xen_dma_sync_for_cpu(struct device *dev, dma_addr_t handle,
-                         phys_addr_t paddr, size_t size,
-                         enum dma_data_direction dir)
+                         size_t size, enum dma_data_direction dir)
 {
-       if (pfn_valid(PFN_DOWN(handle)))
-               arch_sync_dma_for_cpu(paddr, size, dir);
-       else if (dir != DMA_TO_DEVICE)
+       if (dir != DMA_TO_DEVICE)
                dma_cache_maint(handle, size, GNTTAB_CACHE_INVAL);
 }
 
 void xen_dma_sync_for_device(struct device *dev, dma_addr_t handle,
-                            phys_addr_t paddr, size_t size,
-                            enum dma_data_direction dir)
+                            size_t size, enum dma_data_direction dir)
 {
-       if (pfn_valid(PFN_DOWN(handle)))
-               arch_sync_dma_for_device(paddr, size, dir);
-       else if (dir == DMA_FROM_DEVICE)
+       if (dir == DMA_FROM_DEVICE)
                dma_cache_maint(handle, size, GNTTAB_CACHE_INVAL);
        else
                dma_cache_maint(handle, size, GNTTAB_CACHE_CLEAN);
                           dma_addr_t dev_addr)
 {
        unsigned int xen_pfn = XEN_PFN_DOWN(phys);
-       unsigned int bfn = XEN_PFN_DOWN(dev_addr);
+       unsigned int bfn = XEN_PFN_DOWN(dma_to_phys(dev, dev_addr));
 
        /*
         * The swiotlb buffer should be used if
 
        }
 
 done:
-       if (!dev_is_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-               xen_dma_sync_for_device(dev, dev_addr, phys, size, dir);
+       if (!dev_is_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
+               if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dev_addr))))
+                       arch_sync_dma_for_device(phys, size, dir);
+               else
+                       xen_dma_sync_for_device(dev, dev_addr, size, dir);
+       }
        return dev_addr;
 }
 
 
        BUG_ON(dir == DMA_NONE);
 
-       if (!dev_is_dma_coherent(hwdev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-               xen_dma_sync_for_cpu(hwdev, dev_addr, paddr, size, dir);
+       if (!dev_is_dma_coherent(hwdev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
+               if (pfn_valid(PFN_DOWN(dma_to_phys(hwdev, dev_addr))))
+                       arch_sync_dma_for_cpu(paddr, size, dir);
+               else
+                       xen_dma_sync_for_cpu(hwdev, dev_addr, size, dir);
+       }
 
        /* NOTE: We use dev_addr here, not paddr! */
        if (is_xen_swiotlb_buffer(hwdev, dev_addr))
 {
        phys_addr_t paddr = xen_dma_to_phys(dev, dma_addr);
 
-       if (!dev_is_dma_coherent(dev))
-               xen_dma_sync_for_cpu(dev, dma_addr, paddr, size, dir);
+       if (!dev_is_dma_coherent(dev)) {
+               if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dma_addr))))
+                       arch_sync_dma_for_cpu(paddr, size, dir);
+               else
+                       xen_dma_sync_for_cpu(dev, dma_addr, size, dir);
+       }
 
        if (is_xen_swiotlb_buffer(dev, dma_addr))
                swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_CPU);
        if (is_xen_swiotlb_buffer(dev, dma_addr))
                swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_DEVICE);
 
-       if (!dev_is_dma_coherent(dev))
-               xen_dma_sync_for_device(dev, dma_addr, paddr, size, dir);
+       if (!dev_is_dma_coherent(dev)) {
+               if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dma_addr))))
+                       arch_sync_dma_for_device(paddr, size, dir);
+               else
+                       xen_dma_sync_for_device(dev, dma_addr, size, dir);
+       }
 }
 
 /*
 
 #include <linux/swiotlb.h>
 
 void xen_dma_sync_for_cpu(struct device *dev, dma_addr_t handle,
-                         phys_addr_t paddr, size_t size,
-                         enum dma_data_direction dir);
+                         size_t size, enum dma_data_direction dir);
 void xen_dma_sync_for_device(struct device *dev, dma_addr_t handle,
-                            phys_addr_t paddr, size_t size,
-                            enum dma_data_direction dir);
+                            size_t size, enum dma_data_direction dir);
 
 extern int xen_swiotlb_init(int verbose, bool early);
 extern const struct dma_map_ops xen_swiotlb_dma_ops;