Define the map_resource/unmap_resource callbacks for the dma_iommu_ops used by several powerpc platforms. The map_resource callback is called when trying to map a mmio resource through the dma_map_resource() driver API. For now, the callback returns an invalid address for devices using translations, but will "direct" map the resource when in bypass mode. Previous behavior for dma_map_resource() was to always return an invalid address. We also call an optional platform-specific controller op in case some setup is needed for the platform. Signed-off-by: Frederic Barrat <fbarrat@xxxxxxxxxxxxx> Signed-off-by: Max Gurtovoy <maxg@xxxxxxxxxxxx> --- changes from v1: - rename pci_controller_ops callback to dma_direct_map_resource/dma_direct_unmap_resource - cosmetic changes to make the code more readable --- arch/powerpc/include/asm/pci-bridge.h | 7 +++++++ arch/powerpc/kernel/dma-iommu.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 69f4cb3..aca3724 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -44,6 +44,13 @@ struct pci_controller_ops { #endif void (*shutdown)(struct pci_controller *hose); + int (*dma_direct_map_resource)(struct pci_dev *pdev, + phys_addr_t phys_addr, + size_t size, + enum dma_data_direction dir); + void (*dma_direct_unmap_resource)(struct pci_dev *pdev, + dma_addr_t addr, size_t size, + enum dma_data_direction dir); }; /* diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index e486d1d..049d000 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -108,6 +108,35 @@ static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist, dma_direct_unmap_sg(dev, sglist, nelems, direction, attrs); } +static dma_addr_t dma_iommu_map_resource(struct device *dev, + phys_addr_t phys_addr, size_t size, + enum dma_data_direction dir, + unsigned long attrs) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_controller *phb = pci_bus_to_host(pdev->bus); + struct pci_controller_ops *ops = &phb->controller_ops; + + if (!dma_iommu_map_bypass(dev, attrs) || + !ops->dma_direct_map_resource || + ops->dma_direct_map_resource(pdev, phys_addr, size, dir)) + return DMA_MAPPING_ERROR; + + return dma_direct_map_resource(dev, phys_addr, size, dir, attrs); +} + +static void dma_iommu_unmap_resource(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, + unsigned long attrs) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_controller *phb = pci_bus_to_host(pdev->bus); + struct pci_controller_ops *ops = &phb->controller_ops; + + if (dma_iommu_map_bypass(dev, attrs) && ops->dma_direct_unmap_resource) + ops->dma_direct_unmap_resource(pdev, dma_handle, size, dir); +} + static bool dma_iommu_bypass_supported(struct device *dev, u64 mask) { struct pci_dev *pdev = to_pci_dev(dev); @@ -199,6 +228,8 @@ extern void dma_iommu_sync_sg_for_device(struct device *dev, .free = dma_iommu_free_coherent, .map_sg = dma_iommu_map_sg, .unmap_sg = dma_iommu_unmap_sg, + .map_resource = dma_iommu_map_resource, + .unmap_resource = dma_iommu_unmap_resource, .dma_supported = dma_iommu_dma_supported, .map_page = dma_iommu_map_page, .unmap_page = dma_iommu_unmap_page, -- 1.8.3.1