123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- /* SPDX-License-Identifier: GPL-2.0-only */
- /*
- * Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #ifndef __KGSL_MMU_H
- #define __KGSL_MMU_H
- #include <linux/platform_device.h>
- /* Identifier for the global page table */
- /*
- * Per process page tables will probably pass in the thread group
- * as an identifier
- */
- #define KGSL_MMU_GLOBAL_PT 0
- #define KGSL_MMU_SECURE_PT 1
- #define MMU_DEFAULT_TTBR0(_d) \
- (kgsl_mmu_pagetable_get_ttbr0((_d)->mmu.defaultpagetable))
- /* Mask ASID fields to match 48bit ptbase address*/
- #define MMU_SW_PT_BASE(_ttbr0) \
- (_ttbr0 & (BIT_ULL(KGSL_IOMMU_ASID_START_BIT) - 1))
- #define KGSL_MMU_DEVICE(_mmu) \
- container_of((_mmu), struct kgsl_device, mmu)
- /**
- * enum kgsl_ft_pagefault_policy_bits - KGSL pagefault policy bits
- * @KGSL_FT_PAGEFAULT_INT_ENABLE: No longer used, but retained for compatibility
- * @KGSL_FT_PAGEFAULT_GPUHALT_ENABLE: enable GPU halt on pagefaults
- * @KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE: log one pagefault per page
- * @KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT: log one pagefault per interrupt
- */
- enum {
- KGSL_FT_PAGEFAULT_INT_ENABLE = 0,
- KGSL_FT_PAGEFAULT_GPUHALT_ENABLE = 1,
- KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE = 2,
- KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT = 3,
- /* KGSL_FT_PAGEFAULT_MAX_BITS is used to calculate the mask */
- KGSL_FT_PAGEFAULT_MAX_BITS,
- };
- #define KGSL_FT_PAGEFAULT_MASK GENMASK(KGSL_FT_PAGEFAULT_MAX_BITS - 1, 0)
- #define KGSL_FT_PAGEFAULT_DEFAULT_POLICY 0
- struct kgsl_device;
- enum kgsl_mmutype {
- KGSL_MMU_TYPE_IOMMU = 0,
- KGSL_MMU_TYPE_NONE
- };
- #define KGSL_IOMMU_SMMU_V500 1
- struct kgsl_pagetable {
- spinlock_t lock;
- struct kref refcount;
- struct list_head list;
- unsigned int name;
- struct kobject *kobj;
- struct work_struct destroy_ws;
- struct {
- atomic_t entries;
- atomic_long_t mapped;
- atomic_long_t max_mapped;
- } stats;
- const struct kgsl_mmu_pt_ops *pt_ops;
- uint64_t fault_addr;
- struct kgsl_mmu *mmu;
- /** @rbtree: all buffers mapped into the pagetable, indexed by gpuaddr */
- struct rb_root rbtree;
- /** @va_start: Start of virtual range used in this pagetable */
- u64 va_start;
- /** @va_end: End of virtual range */
- u64 va_end;
- /**
- * @svm_start: Start of shared virtual memory range. Addresses in this
- * range are also valid in the process's CPU address space.
- */
- u64 svm_start;
- /** @svm_end: end of 32 bit compatible range */
- u64 svm_end;
- /**
- * @compat_va_start - Start of the "compat" virtual address range for
- * forced 32 bit allocations
- */
- u64 compat_va_start;
- /**
- * @compat_va_end - End of the "compat" virtual address range for
- * forced 32 bit allocations
- */
- u64 compat_va_end;
- /** @va_hint: Virtual address hint for 64-bit non-SVM allocations */
- u64 va_hint;
- u64 global_base;
- };
- struct kgsl_mmu;
- struct kgsl_mmu_ops {
- void (*mmu_close)(struct kgsl_mmu *mmu);
- int (*mmu_start)(struct kgsl_mmu *mmu);
- uint64_t (*mmu_get_current_ttbr0)(struct kgsl_mmu *mmu, struct kgsl_context *context);
- void (*mmu_pagefault_resume)(struct kgsl_mmu *mmu, bool terminate);
- void (*mmu_clear_fsr)(struct kgsl_mmu *mmu);
- void (*mmu_enable_clk)(struct kgsl_mmu *mmu);
- void (*mmu_disable_clk)(struct kgsl_mmu *mmu);
- int (*mmu_set_pf_policy)(struct kgsl_mmu *mmu, unsigned long pf_policy);
- int (*mmu_init_pt)(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt);
- struct kgsl_pagetable * (*mmu_getpagetable)(struct kgsl_mmu *mmu,
- unsigned long name);
- void (*mmu_map_global)(struct kgsl_mmu *mmu,
- struct kgsl_memdesc *memdesc, u32 padding);
- void (*mmu_send_tlb_hint)(struct kgsl_mmu *mmu, bool hint);
- };
- struct kgsl_mmu_pt_ops {
- int (*mmu_map)(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc);
- int (*mmu_map_child)(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc, u64 offset,
- struct kgsl_memdesc *child, u64 child_offset,
- u64 length);
- int (*mmu_map_zero_page_to_range)(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc, u64 start, u64 length);
- int (*mmu_unmap)(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc);
- int (*mmu_unmap_range)(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc, u64 offset, u64 length);
- void (*mmu_destroy_pagetable)(struct kgsl_pagetable *pt);
- u64 (*get_ttbr0)(struct kgsl_pagetable *pt);
- int (*get_context_bank)(struct kgsl_pagetable *pt, struct kgsl_context *context);
- int (*get_asid)(struct kgsl_pagetable *pt, struct kgsl_context *context);
- int (*get_gpuaddr)(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc);
- void (*put_gpuaddr)(struct kgsl_memdesc *memdesc);
- uint64_t (*find_svm_region)(struct kgsl_pagetable *pt, uint64_t start,
- uint64_t end, uint64_t size, uint64_t align);
- int (*set_svm_region)(struct kgsl_pagetable *pt,
- uint64_t gpuaddr, uint64_t size);
- int (*svm_range)(struct kgsl_pagetable *pt, uint64_t *lo, uint64_t *hi,
- uint64_t memflags);
- bool (*addr_in_range)(struct kgsl_pagetable *pagetable,
- uint64_t gpuaddr, uint64_t size);
- };
- enum kgsl_mmu_feature {
- /* @KGSL_MMU_64BIT: Use 64 bit virtual address space */
- KGSL_MMU_64BIT,
- /* @KGSL_MMU_PAGED: Support paged memory */
- KGSL_MMU_PAGED,
- /*
- * @KGSL_MMU_NEED_GUARD_PAGE: Set if a guard page is needed for each
- * mapped region
- */
- KGSL_MMU_NEED_GUARD_PAGE,
- /** @KGSL_MMU_IO_COHERENT: Set if a device supports I/O coherency */
- KGSL_MMU_IO_COHERENT,
- /** @KGSL_MMU_LLC_ENABLE: Set if LLC is activated for the target */
- KGSL_MMU_LLCC_ENABLE,
- /** @KGSL_MMU_SMMU_APERTURE: Set the SMMU aperture */
- KGSL_MMU_SMMU_APERTURE,
- /**
- * @KGSL_MMU_IOPGTABLE: Set if the qcom,adreno-smmu implementation is
- * available. Implies split address space and per-process pagetables
- */
- KGSL_MMU_IOPGTABLE,
- /** @KGSL_MMU_SUPPORT_VBO: Non-secure VBOs are supported */
- KGSL_MMU_SUPPORT_VBO,
- /** @KGSL_MMU_PAGEFAULT_TERMINATE: Set to make pagefaults fatal */
- KGSL_MMU_PAGEFAULT_TERMINATE,
- };
- #include "kgsl_iommu.h"
- /**
- * struct kgsl_mmu - Master definition for KGSL MMU devices
- * @flags: MMU device flags
- * @type: Type of MMU that is attached
- * @subtype: Sub Type of MMU that is attached
- * @defaultpagetable: Default pagetable object for the MMU
- * @securepagetable: Default secure pagetable object for the MMU
- * @mmu_ops: Function pointers for the MMU sub-type
- * @secured: True if the MMU needs to be secured
- * @feature: Static list of MMU features
- */
- struct kgsl_mmu {
- unsigned long flags;
- enum kgsl_mmutype type;
- u32 subtype;
- struct kgsl_pagetable *defaultpagetable;
- struct kgsl_pagetable *securepagetable;
- const struct kgsl_mmu_ops *mmu_ops;
- bool secured;
- unsigned long features;
- /** @pfpolicy: The current pagefault policy for the device */
- unsigned long pfpolicy;
- /** mmu: Pointer to the IOMMU sub-device */
- struct kgsl_iommu iommu;
- };
- #define KGSL_IOMMU(d) (&((d)->mmu.iommu))
- int __init kgsl_mmu_init(void);
- void kgsl_mmu_exit(void);
- int kgsl_mmu_start(struct kgsl_device *device);
- void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable);
- int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
- struct kgsl_memdesc *memdesc);
- int kgsl_mmu_map_child(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc, u64 offset,
- struct kgsl_memdesc *child, u64 child_offset,
- u64 length);
- int kgsl_mmu_map_zero_page_to_range(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc, u64 start, u64 length);
- int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
- struct kgsl_memdesc *memdesc);
- int kgsl_mmu_unmap_range(struct kgsl_pagetable *pt,
- struct kgsl_memdesc *memdesc, u64 offset, u64 length);
- unsigned int kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu,
- u64 ttbr0, uint64_t addr);
- bool kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pt, uint64_t gpuaddr,
- uint64_t size);
- uint64_t kgsl_mmu_find_svm_region(struct kgsl_pagetable *pagetable,
- uint64_t start, uint64_t end, uint64_t size,
- uint64_t alignment);
- int kgsl_mmu_set_svm_region(struct kgsl_pagetable *pagetable, uint64_t gpuaddr,
- uint64_t size);
- void kgsl_mmu_detach_pagetable(struct kgsl_pagetable *pagetable);
- int kgsl_mmu_svm_range(struct kgsl_pagetable *pagetable,
- uint64_t *lo, uint64_t *hi, uint64_t memflags);
- struct kgsl_pagetable *kgsl_get_pagetable(unsigned long name);
- /*
- * Static inline functions of MMU that simply call the SMMU specific
- * function using a function pointer. These functions can be thought
- * of as wrappers around the actual function
- */
- #define MMU_OP_VALID(_mmu, _field) \
- (((_mmu) != NULL) && \
- ((_mmu)->mmu_ops != NULL) && \
- ((_mmu)->mmu_ops->_field != NULL))
- #define PT_OP_VALID(_pt, _field) \
- (((_pt) != NULL) && \
- ((_pt)->pt_ops != NULL) && \
- ((_pt)->pt_ops->_field != NULL))
- /**
- * kgsl_mmu_get_gpuaddr - Assign a GPU address to the memdesc
- * @pagetable: GPU pagetable to assign the address in
- * @memdesc: mem descriptor to assign the memory to
- *
- * Return: 0 on success or negative on failure
- */
- static inline int kgsl_mmu_get_gpuaddr(struct kgsl_pagetable *pagetable,
- struct kgsl_memdesc *memdesc)
- {
- if (PT_OP_VALID(pagetable, get_gpuaddr))
- return pagetable->pt_ops->get_gpuaddr(pagetable, memdesc);
- return -ENOMEM;
- }
- /**
- * kgsl_mmu_put_gpuaddr - Remove a GPU address from a pagetable
- * @pagetable: Pagetable to release the memory from
- * @memdesc: Memory descriptor containing the GPU address to free
- *
- * Release a GPU address in the MMU virtual address space.
- */
- static inline void kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable,
- struct kgsl_memdesc *memdesc)
- {
- if (PT_OP_VALID(pagetable, put_gpuaddr))
- pagetable->pt_ops->put_gpuaddr(memdesc);
- }
- static inline u64 kgsl_mmu_get_current_ttbr0(struct kgsl_mmu *mmu, struct kgsl_context *context)
- {
- if (MMU_OP_VALID(mmu, mmu_get_current_ttbr0))
- return mmu->mmu_ops->mmu_get_current_ttbr0(mmu, context);
- return 0;
- }
- static inline struct kgsl_pagetable *kgsl_mmu_getpagetable(struct kgsl_mmu *mmu,
- unsigned long name)
- {
- if (MMU_OP_VALID(mmu, mmu_getpagetable))
- return mmu->mmu_ops->mmu_getpagetable(mmu, name);
- return NULL;
- }
- static inline void kgsl_mmu_enable_clk(struct kgsl_mmu *mmu)
- {
- if (MMU_OP_VALID(mmu, mmu_enable_clk))
- mmu->mmu_ops->mmu_enable_clk(mmu);
- }
- static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu)
- {
- if (MMU_OP_VALID(mmu, mmu_disable_clk))
- mmu->mmu_ops->mmu_disable_clk(mmu);
- }
- static inline int kgsl_mmu_set_pagefault_policy(struct kgsl_mmu *mmu,
- unsigned long pf_policy)
- {
- if (MMU_OP_VALID(mmu, mmu_set_pf_policy))
- return mmu->mmu_ops->mmu_set_pf_policy(mmu, pf_policy);
- return 0;
- }
- static inline void kgsl_mmu_pagefault_resume(struct kgsl_mmu *mmu,
- bool terminate)
- {
- if (MMU_OP_VALID(mmu, mmu_pagefault_resume))
- return mmu->mmu_ops->mmu_pagefault_resume(mmu, terminate);
- }
- static inline void kgsl_mmu_clear_fsr(struct kgsl_mmu *mmu)
- {
- if (MMU_OP_VALID(mmu, mmu_clear_fsr))
- return mmu->mmu_ops->mmu_clear_fsr(mmu);
- }
- static inline bool kgsl_mmu_is_perprocess(struct kgsl_mmu *mmu)
- {
- return test_bit(KGSL_MMU_IOPGTABLE, &mmu->features);
- }
- static inline bool kgsl_mmu_is_secured(struct kgsl_mmu *mmu)
- {
- return mmu && (mmu->secured) && (!IS_ERR_OR_NULL(mmu->securepagetable));
- }
- static inline u64
- kgsl_mmu_pagetable_get_ttbr0(struct kgsl_pagetable *pagetable)
- {
- if (PT_OP_VALID(pagetable, get_ttbr0))
- return pagetable->pt_ops->get_ttbr0(pagetable);
- return 0;
- }
- static inline void kgsl_mmu_send_tlb_hint(struct kgsl_mmu *mmu, bool hint)
- {
- if (MMU_OP_VALID(mmu, mmu_send_tlb_hint))
- return mmu->mmu_ops->mmu_send_tlb_hint(mmu, hint);
- }
- /**
- * kgsl_mmu_map_global - Map a memdesc as a global buffer
- * @device: A KGSL GPU device handle
- * @memdesc: Pointer to a GPU memory descriptor
- * @padding: Any padding to add to the end of the VA allotment (in bytes)
- *
- * Map a buffer as globally accessible in all pagetable contexts
- */
- void kgsl_mmu_map_global(struct kgsl_device *device,
- struct kgsl_memdesc *memdesc, u32 padding);
- /**
- * kgsl_mmu_pagetable_get_context_bank - Return the context bank number
- * @pagetable: A handle to a given pagetable
- * @context : LPAC or User context
- *
- * This function will find the context number of the given pagetable
- * Return: The context bank number the pagetable is attached to or
- * negative error on failure.
- */
- int kgsl_mmu_pagetable_get_context_bank(struct kgsl_pagetable *pagetable,
- struct kgsl_context *context);
- /**
- * kgsl_mmu_pagetable_get_asid - Return the ASID number
- * @pagetable: A handle to a given pagetable
- * @context: LPAC or GC context
- *
- * This function will find the ASID number of the given pagetable
- * Return: The ASID number the pagetable is attached to or
- * negative error on failure.
- */
- int kgsl_mmu_pagetable_get_asid(struct kgsl_pagetable *pagetable,
- struct kgsl_context *context);
- void kgsl_mmu_pagetable_init(struct kgsl_mmu *mmu,
- struct kgsl_pagetable *pagetable, u32 name);
- void kgsl_mmu_pagetable_add(struct kgsl_mmu *mmu, struct kgsl_pagetable *pagetable);
- #if IS_ENABLED(CONFIG_ARM_SMMU)
- int kgsl_iommu_bind(struct kgsl_device *device, struct platform_device *pdev);
- #else
- static inline int kgsl_iommu_bind(struct kgsl_device *device, struct platform_device *pdev)
- {
- return -ENODEV;
- }
- #endif
- /**
- * kgsl_mmu_map_sg - Map the given buffer to the IOMMU domain
- * @domain: The IOMMU domain to perform the mapping
- * @iova: The start address to map the buffer
- * @sgt: The sg_table object describing the buffer
- * @prot: IOMMU protection bits
- *
- * Creates a mapping at @iova for the buffer described by a scatterlist
- * stored in the given sg_table object in the provided IOMMU domain.
- */
- ssize_t kgsl_mmu_map_sg(struct iommu_domain *domain,
- unsigned long iova, struct scatterlist *sg,
- unsigned int nents, int prot);
- #endif /* __KGSL_MMU_H */
|