From 6e192957e898624bd3f065a0948040b393b70077 Mon Sep 17 00:00:00 2001 From: Jonathan Wicks <jwicks@codeaurora.org> Date: Mon, 18 Jul 2016 16:13:21 -0600 Subject: [PATCH] msm: kgsl: Map GPU QDSS STM through GPU IOMMU Map the GPU QDSS STM area as a global into the GPU IOMMU so that GPU traces can be routed to QDSS. Enable the gpuaddr and size of the area to be queried from userspace. CRs-Fixed: 1031648 Change-Id: I2e32522a42508a6bee088c95dc56a13935dd691c Signed-off-by: Jonathan Wicks <jwicks@codeaurora.org> --- .../devicetree/bindings/gpu/adreno.txt | 5 ++ drivers/gpu/msm/adreno.c | 24 +++++++++ drivers/gpu/msm/adreno_compat.c | 24 +++++++++ drivers/gpu/msm/kgsl_iommu.c | 49 +++++++++++++++++++ drivers/gpu/msm/kgsl_mmu.c | 11 +++++ drivers/gpu/msm/kgsl_mmu.h | 3 ++ include/uapi/linux/msm_kgsl.h | 6 +++ 7 files changed, 122 insertions(+) diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index ce2e38b905a1..06b8c71effcc 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -138,6 +138,11 @@ Optional Properties: Specify the size of snapshot in bytes. This will override snapshot size defined in the driver code. +- qcom,gpu-qdss-stm: + <baseAddr size> + baseAddr - base address of the gpu channels in the qdss stm memory region + size - size of the gpu stm region + GPU Quirks: - qcom,gpu-quirk-two-pass-use-wfi: Signal the GPU to set Set TWOPASSUSEWFI bit in diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 26e341a876e8..40ee6e9ae01d 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1718,6 +1718,30 @@ static int adreno_getproperty(struct kgsl_device *device, status = 0; } break; + case KGSL_PROP_DEVICE_QDSS_STM: + { + struct kgsl_qdss_stm_prop qdssprop = {0}; + struct kgsl_memdesc *qdss_desc = + kgsl_mmu_get_qdss_global_entry(device); + + if (sizebytes != sizeof(qdssprop)) { + status = -EINVAL; + break; + } + + if (qdss_desc) { + qdssprop.gpuaddr = qdss_desc->gpuaddr; + qdssprop.size = qdss_desc->size; + } + + if (copy_to_user(value, &qdssprop, + sizeof(qdssprop))) { + status = -EFAULT; + break; + } + status = 0; + } + break; case KGSL_PROP_MMU_ENABLE: { /* Report MMU only if we can handle paged memory */ diff --git a/drivers/gpu/msm/adreno_compat.c b/drivers/gpu/msm/adreno_compat.c index 582cbfb61e78..d86a0c60f0b4 100644 --- a/drivers/gpu/msm/adreno_compat.c +++ b/drivers/gpu/msm/adreno_compat.c @@ -89,6 +89,30 @@ int adreno_getproperty_compat(struct kgsl_device *device, status = 0; } break; + case KGSL_PROP_DEVICE_QDSS_STM: + { + struct kgsl_qdss_stm_prop qdssprop = {0}; + struct kgsl_memdesc *qdss_desc = + kgsl_mmu_get_qdss_global_entry(device); + + if (sizebytes != sizeof(qdssprop)) { + status = -EINVAL; + break; + } + + if (qdss_desc) { + qdssprop.gpuaddr = qdss_desc->gpuaddr; + qdssprop.size = qdss_desc->size; + } + + if (copy_to_user(value, &qdssprop, + sizeof(qdssprop))) { + status = -EFAULT; + break; + } + status = 0; + } + break; default: /* * Call the adreno_getproperty to check if the property type diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index a338559ac0bb..d2963edb04b8 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -96,6 +96,7 @@ static struct kgsl_memdesc *global_pt_entries[GLOBAL_PT_ENTRIES]; static struct kgsl_memdesc *kgsl_global_secure_pt_entry; static int global_pt_count; uint64_t global_pt_alloc; +static struct kgsl_memdesc gpu_qdss_desc; static void kgsl_iommu_unmap_globals(struct kgsl_pagetable *pagetable) { @@ -183,6 +184,51 @@ void kgsl_add_global_secure_entry(struct kgsl_device *device, kgsl_global_secure_pt_entry = memdesc; } +struct kgsl_memdesc *kgsl_iommu_get_qdss_global_entry(void) +{ + return &gpu_qdss_desc; +} + +static void kgsl_setup_qdss_desc(struct kgsl_device *device) +{ + int result = 0; + uint32_t gpu_qdss_entry[2]; + + if (!of_find_property(device->pdev->dev.of_node, + "qcom,gpu-qdss-stm", NULL)) + return; + + if (of_property_read_u32_array(device->pdev->dev.of_node, + "qcom,gpu-qdss-stm", gpu_qdss_entry, 2)) { + KGSL_CORE_ERR("Failed to read gpu qdss dts entry\n"); + return; + } + + gpu_qdss_desc.flags = 0; + gpu_qdss_desc.priv = 0; + gpu_qdss_desc.physaddr = gpu_qdss_entry[0]; + gpu_qdss_desc.size = gpu_qdss_entry[1]; + gpu_qdss_desc.pagetable = NULL; + gpu_qdss_desc.ops = NULL; + gpu_qdss_desc.dev = device->dev->parent; + gpu_qdss_desc.hostptr = NULL; + + result = memdesc_sg_dma(&gpu_qdss_desc, gpu_qdss_desc.physaddr, + gpu_qdss_desc.size); + if (result) { + KGSL_CORE_ERR("memdesc_sg_dma failed: %d\n", result); + return; + } + + kgsl_mmu_add_global(device, &gpu_qdss_desc); +} + +static inline void kgsl_cleanup_qdss_desc(struct kgsl_mmu *mmu) +{ + kgsl_iommu_remove_global(mmu, &gpu_qdss_desc); + kgsl_sharedmem_free(&gpu_qdss_desc); +} + static inline void _iommu_sync_mmu_pc(bool lock) { @@ -1268,6 +1314,7 @@ static void kgsl_iommu_close(struct kgsl_mmu *mmu) kgsl_iommu_remove_global(mmu, &iommu->setstate); kgsl_sharedmem_free(&iommu->setstate); + kgsl_cleanup_qdss_desc(mmu); } static int _setstate_alloc(struct kgsl_device *device, @@ -1339,6 +1386,7 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu) } kgsl_iommu_add_global(mmu, &iommu->setstate); + kgsl_setup_qdss_desc(device); done: if (status) @@ -2367,6 +2415,7 @@ struct kgsl_mmu_ops kgsl_iommu_ops = { .mmu_add_global = kgsl_iommu_add_global, .mmu_remove_global = kgsl_iommu_remove_global, .mmu_getpagetable = kgsl_iommu_getpagetable, + .mmu_get_qdss_global_entry = kgsl_iommu_get_qdss_global_entry, .probe = kgsl_iommu_probe, }; diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index f8315090ff06..8b0d93fda32c 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -546,6 +546,17 @@ bool kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pagetable, } EXPORT_SYMBOL(kgsl_mmu_gpuaddr_in_range); +struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device) +{ + struct kgsl_mmu *mmu = &device->mmu; + + if (MMU_OP_VALID(mmu, mmu_get_qdss_global_entry)) + return mmu->mmu_ops->mmu_get_qdss_global_entry(); + + return NULL; +} +EXPORT_SYMBOL(kgsl_mmu_get_qdss_global_entry); + /* * NOMMU defintions - NOMMU really just means that the MMU is kept in pass * through and the GPU directly accesses physical memory. Used in debug mode and diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 3652aa2e6ec4..abb7cc698376 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -74,6 +74,7 @@ struct kgsl_mmu_ops { struct kgsl_memdesc *memdesc); struct kgsl_pagetable * (*mmu_getpagetable)(struct kgsl_mmu *mmu, unsigned long name); + struct kgsl_memdesc* (*mmu_get_qdss_global_entry)(void); }; struct kgsl_mmu_pt_ops { @@ -221,6 +222,8 @@ int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc, uint64_t addr, uint64_t offset, uint64_t size); +struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device); + /* * Static inline functions of MMU that simply call the SMMU specific * function using a function pointer. These functions can be thought diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h index 34503420c882..8b805a4f86a5 100644 --- a/include/uapi/linux/msm_kgsl.h +++ b/include/uapi/linux/msm_kgsl.h @@ -308,6 +308,7 @@ enum kgsl_timestamp_type { #define KGSL_PROP_GPMU_VERSION 0x16 #define KGSL_PROP_HIGHEST_BANK_BIT 0x17 #define KGSL_PROP_DEVICE_BITNESS 0x18 +#define KGSL_PROP_DEVICE_QDSS_STM 0x19 struct kgsl_shadowprop { unsigned long gpuaddr; @@ -315,6 +316,11 @@ struct kgsl_shadowprop { unsigned int flags; /* contains KGSL_FLAGS_ values */ }; +struct kgsl_qdss_stm_prop { + uint64_t gpuaddr; + uint64_t size; +}; + struct kgsl_version { unsigned int drv_major; unsigned int drv_minor;