From 2e560ec3d03229a6654843757207d0a070dfde68 Mon Sep 17 00:00:00 2001 From: Jonathan Wicks Date: Fri, 24 Feb 2017 16:21:26 -0700 Subject: [PATCH] msm: kgsl: Map GPU QTimer through GPU IOMMU Map the GPU QTimer area as a global into the GPU IOMMU so that the GPU can access the QTimer. Change-Id: If50bd36681123adde7e3a37644c41316f101154c Signed-off-by: Jonathan Wicks --- .../devicetree/bindings/gpu/adreno.txt | 5 ++ drivers/gpu/msm/adreno.c | 24 ++++++++++ drivers/gpu/msm/adreno_compat.c | 26 +++++++++- drivers/gpu/msm/kgsl_iommu.c | 48 +++++++++++++++++++ drivers/gpu/msm/kgsl_mmu.c | 14 +++++- drivers/gpu/msm/kgsl_mmu.h | 6 ++- include/uapi/linux/msm_kgsl.h | 6 +++ 7 files changed, 126 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 453223dc195a..20ac956f9d22 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -139,6 +139,11 @@ Optional Properties: baseAddr - base address of the gpu channels in the qdss stm memory region size - size of the gpu stm region +- qcom,gpu-qtimer: + + baseAddr - base address of the qtimer memory region + size - size of the qtimer region + - qcom,tsens-name: Specify the name of GPU temperature sensor. This name will be used to get the temperature from the thermal driver API. diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 0f582cf35e6b..f46402aae4f6 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1720,6 +1720,30 @@ static int adreno_getproperty(struct kgsl_device *device, status = 0; } break; + case KGSL_PROP_DEVICE_QTIMER: + { + struct kgsl_qtimer_prop qtimerprop = {0}; + struct kgsl_memdesc *qtimer_desc = + kgsl_mmu_get_qtimer_global_entry(device); + + if (sizebytes != sizeof(qtimerprop)) { + status = -EINVAL; + break; + } + + if (qtimer_desc) { + qtimerprop.gpuaddr = qtimer_desc->gpuaddr; + qtimerprop.size = qtimer_desc->size; + } + + if (copy_to_user(value, &qtimerprop, + sizeof(qtimerprop))) { + 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 d86a0c60f0b4..5a8d587d4536 100644 --- a/drivers/gpu/msm/adreno_compat.c +++ b/drivers/gpu/msm/adreno_compat.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -113,6 +113,30 @@ int adreno_getproperty_compat(struct kgsl_device *device, status = 0; } break; + case KGSL_PROP_DEVICE_QTIMER: + { + struct kgsl_qtimer_prop qtimerprop = {0}; + struct kgsl_memdesc *qtimer_desc = + kgsl_mmu_get_qtimer_global_entry(device); + + if (sizebytes != sizeof(qtimerprop)) { + status = -EINVAL; + break; + } + + if (qtimer_desc) { + qtimerprop.gpuaddr = qtimer_desc->gpuaddr; + qtimerprop.size = qtimer_desc->size; + } + + if (copy_to_user(value, &qtimerprop, + sizeof(qtimerprop))) { + 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 6c667cb62896..af9fc1c15236 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -106,6 +106,7 @@ 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 struct kgsl_memdesc gpu_qtimer_desc; void kgsl_print_global_pt_entries(struct seq_file *s) { @@ -261,6 +262,50 @@ static inline void kgsl_cleanup_qdss_desc(struct kgsl_mmu *mmu) kgsl_sharedmem_free(&gpu_qdss_desc); } +struct kgsl_memdesc *kgsl_iommu_get_qtimer_global_entry(void) +{ + return &gpu_qtimer_desc; +} + +static void kgsl_setup_qtimer_desc(struct kgsl_device *device) +{ + int result = 0; + uint32_t gpu_qtimer_entry[2]; + + if (!of_find_property(device->pdev->dev.of_node, + "qcom,gpu-qtimer", NULL)) + return; + + if (of_property_read_u32_array(device->pdev->dev.of_node, + "qcom,gpu-qtimer", gpu_qtimer_entry, 2)) { + KGSL_CORE_ERR("Failed to read gpu qtimer dts entry\n"); + return; + } + + gpu_qtimer_desc.flags = 0; + gpu_qtimer_desc.priv = 0; + gpu_qtimer_desc.physaddr = gpu_qtimer_entry[0]; + gpu_qtimer_desc.size = gpu_qtimer_entry[1]; + gpu_qtimer_desc.pagetable = NULL; + gpu_qtimer_desc.ops = NULL; + gpu_qtimer_desc.dev = device->dev->parent; + gpu_qtimer_desc.hostptr = NULL; + + result = memdesc_sg_dma(&gpu_qtimer_desc, gpu_qtimer_desc.physaddr, + gpu_qtimer_desc.size); + if (result) { + KGSL_CORE_ERR("memdesc_sg_dma failed: %d\n", result); + return; + } + + kgsl_mmu_add_global(device, &gpu_qtimer_desc, "gpu-qtimer"); +} + +static inline void kgsl_cleanup_qtimer_desc(struct kgsl_mmu *mmu) +{ + kgsl_iommu_remove_global(mmu, &gpu_qtimer_desc); + kgsl_sharedmem_free(&gpu_qtimer_desc); +} static inline void _iommu_sync_mmu_pc(bool lock) { @@ -1403,6 +1448,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); + kgsl_cleanup_qtimer_desc(mmu); } static int _setstate_alloc(struct kgsl_device *device, @@ -1474,6 +1520,7 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu) kgsl_iommu_add_global(mmu, &iommu->setstate, "setstate"); kgsl_setup_qdss_desc(device); + kgsl_setup_qtimer_desc(device); done: if (status) @@ -2616,6 +2663,7 @@ struct kgsl_mmu_ops kgsl_iommu_ops = { .mmu_remove_global = kgsl_iommu_remove_global, .mmu_getpagetable = kgsl_iommu_getpagetable, .mmu_get_qdss_global_entry = kgsl_iommu_get_qdss_global_entry, + .mmu_get_qtimer_global_entry = kgsl_iommu_get_qtimer_global_entry, .probe = kgsl_iommu_probe, }; diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 46bb6f4656fb..aa7157e882ac 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -619,6 +619,18 @@ struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device) } EXPORT_SYMBOL(kgsl_mmu_get_qdss_global_entry); +struct kgsl_memdesc *kgsl_mmu_get_qtimer_global_entry( + struct kgsl_device *device) +{ + struct kgsl_mmu *mmu = &device->mmu; + + if (MMU_OP_VALID(mmu, mmu_get_qtimer_global_entry)) + return mmu->mmu_ops->mmu_get_qtimer_global_entry(); + + return NULL; +} +EXPORT_SYMBOL(kgsl_mmu_get_qtimer_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 bc448d424ccb..505fe591a53e 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -81,6 +81,7 @@ struct kgsl_mmu_ops { struct kgsl_pagetable * (*mmu_getpagetable)(struct kgsl_mmu *mmu, unsigned long name); struct kgsl_memdesc* (*mmu_get_qdss_global_entry)(void); + struct kgsl_memdesc* (*mmu_get_qtimer_global_entry)(void); }; struct kgsl_mmu_pt_ops { @@ -231,6 +232,9 @@ int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device); +struct kgsl_memdesc *kgsl_mmu_get_qtimer_global_entry( + struct kgsl_device *device); + int kgsl_mmu_sparse_dummy_map(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size); diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h index 71fdf6d6e9e5..843e02711aa7 100644 --- a/include/uapi/linux/msm_kgsl.h +++ b/include/uapi/linux/msm_kgsl.h @@ -318,6 +318,7 @@ enum kgsl_timestamp_type { #define KGSL_PROP_HIGHEST_BANK_BIT 0x17 #define KGSL_PROP_DEVICE_BITNESS 0x18 #define KGSL_PROP_DEVICE_QDSS_STM 0x19 +#define KGSL_PROP_DEVICE_QTIMER 0x20 struct kgsl_shadowprop { unsigned long gpuaddr; @@ -330,6 +331,11 @@ struct kgsl_qdss_stm_prop { uint64_t size; }; +struct kgsl_qtimer_prop { + uint64_t gpuaddr; + uint64_t size; +}; + struct kgsl_version { unsigned int drv_major; unsigned int drv_minor;