/* /include/linux/exynos_iovmm.h * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef __ASM_PLAT_IOVMM_H #define __ASM_PLAT_IOVMM_H #include #include #include #include #define IOMMU_PFNMAP (1 << 5) /* VM_PFNMAP is set */ struct scatterlist; struct device; typedef u32 exynos_iova_t; #define SYSMMU_FAULT_BITS 4 #define SYSMMU_FAULT_SHIFT 16 #define SYSMMU_FAULT_MASK ((1 << SYSMMU_FAULT_BITS) - 1) #define SYSMMU_FAULT_FLAG(id) (((id) & SYSMMU_FAULT_MASK) << SYSMMU_FAULT_SHIFT) #define SYSMMU_FAULT_ID(fg) (((fg) >> SYSMMU_FAULT_SHIFT) & SYSMMU_FAULT_MASK) #define SYSMMU_FAULT_PTW_ACCESS 0 #define SYSMMU_FAULT_PAGE_FAULT 1 #define SYSMMU_FAULT_TLB_MULTIHIT 2 #define SYSMMU_FAULT_ACCESS 3 #define SYSMMU_FAULT_SECURITY 4 #define SYSMMU_FAULT_UNKNOWN 5 #define IOMMU_FAULT_EXYNOS_PTW_ACCESS SYSMMU_FAULT_FLAG(SYSMMU_FAULT_PTW_ACCESS) #define IOMMU_FAULT_EXYNOS_PAGE_FAULT SYSMMU_FAULT_FLAG(SYSMMU_FAULT_PAGE_FAULT) #define IOMMU_FAULT_EXYNOS_TLB_MULTIHIT \ SYSMMU_FAULT_FLAG(SYSMMU_FAULT_TLB_MULTIHIT) #define IOMMU_FAULT_EXYNOS_ACCESS SYSMMU_FAULT_FLAG(SYSMMU_FAULT_ACCESS) #define IOMMU_FAULT_EXYNOS_SECURITY SYSMMU_FAULT_FLAG(SYSMMU_FAULT_SECURITY) #define IOMMU_FAULT_EXYNOS_UNKNOWN SYSMMU_FAULT_FLAG(SYSMMU_FAULT_UNKOWN) /* TODO: PB related for sysmmu v6, remove it later */ #define SYSMMU_PBUFCFG_TLB_UPDATE (1 << 16) #define SYSMMU_PBUFCFG_ASCENDING (1 << 12) #define SYSMMU_PBUFCFG_DESCENDING (0 << 12) #define SYSMMU_PBUFCFG_PREFETCH (1 << 8) #define SYSMMU_PBUFCFG_WRITE (1 << 4) #define SYSMMU_PBUFCFG_READ (0 << 4) #define SYSMMU_PBUFCFG_DEFAULT_INPUT (SYSMMU_PBUFCFG_TLB_UPDATE | \ SYSMMU_PBUFCFG_ASCENDING | \ SYSMMU_PBUFCFG_PREFETCH | \ SYSMMU_PBUFCFG_READ) #define SYSMMU_PBUFCFG_DEFAULT_OUTPUT (SYSMMU_PBUFCFG_TLB_UPDATE | \ SYSMMU_PBUFCFG_ASCENDING | \ SYSMMU_PBUFCFG_PREFETCH | \ SYSMMU_PBUFCFG_WRITE) #define SYSMMU_PBUFCFG_ASCENDING_INPUT (SYSMMU_PBUFCFG_TLB_UPDATE | \ SYSMMU_PBUFCFG_ASCENDING | \ SYSMMU_PBUFCFG_PREFETCH | \ SYSMMU_PBUFCFG_READ) #define SYSMMU_PBUFCFG_DESCENDING_INPUT (SYSMMU_PBUFCFG_TLB_UPDATE | \ SYSMMU_PBUFCFG_DESCENDING | \ SYSMMU_PBUFCFG_PREFETCH | \ SYSMMU_PBUFCFG_READ) /* SYSMMU PPC Event ID */ enum sysmmu_ppc_event { READ_TOTAL, READ_L1TLB_MISS, READ_L2TLB_MISS, READ_FLPD_MISS, READ_PB_LOOKUP, READ_PB_MISS, READ_BLOCK_NUM_BY_PREFETCH, READ_BLOCK_CYCLE_BRY_PREFETCH, READ_TLB_MISS, READ_FLPD_MISS_PREFETCH, WRITE_TOTAL = 0x10, WRITE_L1TLB_MISS, WRITE_L2TLB_MISS, WRITE_FLPD_MISS, WRITE_PB_LOOKUP, WRITE_PB_MISS, WRITE_BLOCK_NUM_BY_PREFETCH, WRITE_BLOCK_CYCLE_BY_PREFETCH, WRITE_TLB_MISS, WRITE_FLPD_MISS_PREFETCH, TOTAL_ID_NUM, }; struct sysmmu_prefbuf { unsigned long base; unsigned long size; unsigned long config; }; #if defined(CONFIG_EXYNOS_IOVMM) int iovmm_activate(struct device *dev); void iovmm_deactivate(struct device *dev); struct iommu_domain *get_domain_from_dev(struct device *dev); /* iovmm_map() - Maps a list of physical memory chunks * @dev: the owner of the IO address space where the mapping is created * @sg: list of physical memory chunks to map * @offset: length in bytes where the mapping starts * @size: how much memory to map in bytes. @offset + @size must not exceed * total size of @sg * @direction: dma data direction for iova * @prot: iommu mapping property * * This function returns mapped IO address in the address space of @dev. * Returns minus error number if mapping fails. * Caller must check its return code with IS_ERROR_VALUE() if the function * succeeded. * * The caller of this function must ensure that iovmm_cleanup() is not called * while this function is called. * */ dma_addr_t iovmm_map(struct device *dev, struct scatterlist *sg, off_t offset, size_t size, enum dma_data_direction direction, int prot); /* iovmm_unmap() - unmaps the given IO address * @dev: the owner of the IO address space where @iova belongs * @iova: IO address that needs to be unmapped and freed. * * The caller of this function must ensure that iovmm_cleanup() is not called * while this function is called. */ void iovmm_unmap(struct device *dev, dma_addr_t iova); /* * flags to option_iplanes and option_oplanes. * inplanes and onplanes is 'input planes' and 'output planes', respectively. * * default value to option_iplanes: * (TLB_UPDATE | ASCENDING | PREFETCH) * default value to option_oplanes: * (TLB_UPDATE | ASCENDING | PREFETCH | WRITE) * * SYSMMU_PBUFCFG_READ and SYSMMU_PBUFCFG_WRITE are ignored because they are * implicitly set from 'inplanes' and 'onplanes' arguments to * iovmm_set_prefetch_buffer(). * * Guide to setting flags: * - Clear SYSMMU_BUFCFG_TLB_UPDATE if a buffer is accessed by the device * for rotation. * - Set SYSMMU_PBUFCFG_DESCENDING if the device access a buffer in reversed * order * - Clear SYSMMU_PBUFCFG_PREFETCH if access to a buffer has poor locality. * - Otherwise, always set flags as default value. */ #else #define iovmm_activate(dev) (-ENOSYS) #define iovmm_deactivate(dev) do { } while (0) #define iovmm_map(dev, sg, offset, size, direction, prot) (-ENOSYS) #define iovmm_unmap(dev, iova) do { } while (0) #define get_domain_from_dev(dev) NULL static inline dma_addr_t exynos_iovmm_map_userptr(struct device *dev, unsigned long vaddr, size_t size, int prot) { } #define exynos_iovmm_unmap_userptr(dev, iova) do { } while (0) #endif /* CONFIG_EXYNOS_IOVMM */ #if defined(CONFIG_EXYNOS_IOMMU) /** * exynos_sysmmu_map_user_pages() - maps all pages by fetching from * user page table entries. * @dev: The device whose System MMU is about to be disabled. * @mm: mm struct of user requested to map * @vaddr: start vaddr in valid vma * @iova: start io vaddr to be mapped * @size: size to map * @write: set if buffer may be written * @shareable: set shareable bit if true * * This function maps all user pages into sysmmu page table. */ int exynos_sysmmu_map_user_pages(struct device *dev, struct mm_struct *mm, unsigned long vaddr, exynos_iova_t iova, size_t size, bool write, bool shareable); /** * exynos_sysmmu_unmap_user_pages() - unmaps all mapped pages * @dev: The device whose System MMU is about to be disabled. * @mm: mm struct of user requested to map * @vaddr: start vaddr in valid vma * @iova: start io vaddr to be unmapped * @size: size to map * * This function unmaps all user pages mapped in sysmmu page table. */ int exynos_sysmmu_unmap_user_pages(struct device *dev, struct mm_struct *mm, unsigned long vaddr, exynos_iova_t iova, size_t size); /** * exynos_iommu_sync_for_device() * - maintain cache lines on the given area before DMA * @dev: The device that is about to see the area * @iova: The start DMA address of @dev to maintain * @len: The length of the area * @dir: Indicate whether @dev read from or write to the area */ void exynos_iommu_sync_for_device(struct device *dev, dma_addr_t iova, size_t len, enum dma_data_direction dir); /** * exynos_iommu_sync_for_cpu() * - maintain cache lines on the given area after DMA * @dev: The device that is about to see the area * @iova: The start DMA address of @dev to maintain * @len: The length of the area * @dir: Indicate whether @dev read from or write to the area */ void exynos_iommu_sync_for_cpu(struct device *dev, dma_addr_t iova, size_t len, enum dma_data_direction dir); /** * TODO: description */ dma_addr_t exynos_iovmm_map_userptr(struct device *dev, unsigned long vaddr, size_t size, int prot); /** * TODO: description */ void exynos_iovmm_unmap_userptr(struct device *dev, dma_addr_t iova); int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size); void iovmm_unmap_oto(struct device *dev, phys_addr_t phys); /* * The handle_pte_fault() is called by exynos_sysmmu_map_user_pages(). * Driver cannot include include/linux/huge_mm.h because * CONFIG_TRANSPARENT_HUGEPAGE is disabled. */ extern int handle_pte_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *pte, pmd_t *pmd, unsigned int flags); /* * sysmmu_set_prefetch_buffer_by_region() - set prefetch buffer configuration * * @dev: device descriptor of master device * @pb_reg: array of regions where prefetch buffer contains. * * If @dev is NULL or @pb_reg is 0, prefetch buffers is disabled. * */ void sysmmu_set_prefetch_buffer_by_region(struct device *dev, struct sysmmu_prefbuf pb_reg[], unsigned int num_reg); int sysmmu_set_prefetch_buffer_property(struct device *dev, unsigned int inplanes, unsigned int onplanes, unsigned int ipoption[], unsigned int opoption[]); void exynos_sysmmu_show_status(struct device *dev); void exynos_sysmmu_dump_pgtable(struct device *dev); void exynos_sysmmu_control(struct device *master, bool enable); /* * exynos_sysmmu_set/clear/show_ppc_event() - * set/clear/show system mmu ppc event * * @dev: device descriptor of master device. * @event: system mmu ppc event id. * Returns 0 if setting is successful. -EINVAL if the argument is invalid. * */ int exynos_sysmmu_set_ppc_event(struct device *dev, int event); void exynos_sysmmu_clear_ppc_event(struct device *dev); void exynos_sysmmu_show_ppc_event(struct device *dev); /* * iovmm_set_fault_handler - register fault handler of dev to iommu controller * @dev: the device that wants to register fault handler * @handler: fault handler * @token: any data the device driver needs to get when fault occurred */ void iovmm_set_fault_handler(struct device *dev, iommu_fault_handler_t handler, void *token); #else #define sysmmu_set_prefetch_buffer_property(dev, inplanes, onplnes, ipoption, opoption) \ (0) #define sysmmu_set_prefetch_buffer_by_region(dev, pb_reg, num_reg) \ do { } while (0) #define exynos_sysmmu_map_user_pages(dev, mm, vaddr, iova, size, write, sharable) \ (-ENOSYS) #define exynos_sysmmu_unmap_user_pages(dev, mm, vaddr, iova, size) \ do { } while (0) #define exynos_sysmmu_show_status(dev) do { } while (0) #define exynos_sysmmu_dump_pgtable(dev) do { } while (0) #define exynos_sysmmu_clear_ppc_event(dev) do { } while (0) #define exynos_sysmmu_show_ppc_event(dev) do { } while (0) #define exynos_sysmmu_set_ppc_event(dev, event) do { } while (0) #define iovmm_set_fault_handler(dev, handler, token) do { } while(0) #define exynos_iommu_sync_for_device(dev, iova, len, dir) do { } while (0) #define exynos_iommu_sync_for_cpu(dev, iova, len, dir) do { } while (0) #endif #endif /*__ASM_PLAT_IOVMM_H*/