Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm/adreno: Disable IFPC when sysprof is active

Moving to IFPC state clears the 'Perfcounter Select' register setup
by the userspace. So, lets block the IFPC when sysprof is active by
using the perfcounter oob signal to the GMU.

Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/673380/
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>

authored by

Akhil P Oommen and committed by
Rob Clark
62cd0fa6 a242ef4a

+47
+37
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
··· 1157 1157 /* Set the GPU to the current freq */ 1158 1158 a6xx_gmu_set_initial_freq(gpu, gmu); 1159 1159 1160 + if (refcount_read(&gpu->sysprof_active) > 1) { 1161 + ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET); 1162 + if (!ret) 1163 + set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status); 1164 + } 1160 1165 out: 1161 1166 /* On failure, shut down the GMU to leave it in a good state */ 1162 1167 if (ret) { ··· 1208 1203 1209 1204 a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); 1210 1205 } 1206 + 1207 + if (test_and_clear_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status)) 1208 + a6xx_gmu_clear_oob(gmu, GMU_OOB_PERFCOUNTER_SET); 1211 1209 1212 1210 ret = a6xx_gmu_wait_for_idle(gmu); 1213 1211 ··· 1823 1815 } 1824 1816 1825 1817 return irq; 1818 + } 1819 + 1820 + void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu) 1821 + { 1822 + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 1823 + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); 1824 + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; 1825 + unsigned int sysprof_active; 1826 + 1827 + /* Nothing to do if GPU is suspended. We will handle this during GMU resume */ 1828 + if (!pm_runtime_get_if_active(&gpu->pdev->dev)) 1829 + return; 1830 + 1831 + mutex_lock(&gmu->lock); 1832 + 1833 + sysprof_active = refcount_read(&gpu->sysprof_active); 1834 + 1835 + /* 1836 + * 'Perfcounter select' register values are lost during IFPC collapse. To avoid that, 1837 + * use the currently unused perfcounter oob vote to block IFPC when sysprof is active 1838 + */ 1839 + if ((sysprof_active > 1) && !test_and_set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status)) 1840 + a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET); 1841 + else if ((sysprof_active == 1) && test_and_clear_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status)) 1842 + a6xx_gmu_clear_oob(gmu, GMU_OOB_PERFCOUNTER_SET); 1843 + 1844 + mutex_unlock(&gmu->lock); 1845 + 1846 + pm_runtime_put(&gpu->pdev->dev); 1826 1847 } 1827 1848 1828 1849 void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
+2
drivers/gpu/drm/msm/adreno/a6xx_gmu.h
··· 125 125 #define GMU_STATUS_FW_START 0 126 126 /* To track if PDC sleep seq was done */ 127 127 #define GMU_STATUS_PDC_SLEEP 1 128 + /* To track Perfcounter OOB set status */ 129 + #define GMU_STATUS_OOB_PERF_SET 2 128 130 unsigned long status; 129 131 }; 130 132
+2
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
··· 2536 2536 .create_private_vm = a6xx_create_private_vm, 2537 2537 .get_rptr = a6xx_get_rptr, 2538 2538 .progress = a6xx_progress, 2539 + .sysprof_setup = a6xx_gmu_sysprof_setup, 2539 2540 }, 2540 2541 .get_timestamp = a6xx_gmu_get_timestamp, 2541 2542 }; ··· 2597 2596 .create_private_vm = a6xx_create_private_vm, 2598 2597 .get_rptr = a6xx_get_rptr, 2599 2598 .progress = a6xx_progress, 2599 + .sysprof_setup = a6xx_gmu_sysprof_setup, 2600 2600 }, 2601 2601 .get_timestamp = a6xx_gmu_get_timestamp, 2602 2602 };
+1
drivers/gpu/drm/msm/adreno/a6xx_gpu.h
··· 254 254 int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node); 255 255 int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node); 256 256 void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu); 257 + void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu); 257 258 258 259 void a6xx_preempt_init(struct msm_gpu *gpu); 259 260 void a6xx_preempt_hw_init(struct msm_gpu *gpu);
+1
drivers/gpu/drm/msm/msm_gpu.h
··· 92 92 * for cmdstream that is buffered in this FIFO upstream of the CP fw. 93 93 */ 94 94 bool (*progress)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); 95 + void (*sysprof_setup)(struct msm_gpu *gpu); 95 96 }; 96 97 97 98 /* Additional state for iommu faults: */
+4
drivers/gpu/drm/msm/msm_submitqueue.c
··· 40 40 break; 41 41 } 42 42 43 + /* Some gpu families require additional setup for sysprof */ 44 + if (gpu->funcs->sysprof_setup) 45 + gpu->funcs->sysprof_setup(gpu); 46 + 43 47 ctx->sysprof = sysprof; 44 48 45 49 return 0;