Loading drivers/gpu/msm/adreno.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -943,6 +943,9 @@ struct adreno_gpudev { bool (*sptprac_is_on)(struct adreno_device *); bool (*sptprac_is_on)(struct adreno_device *); unsigned int (*ccu_invalidate)(struct adreno_device *adreno_dev, unsigned int (*ccu_invalidate)(struct adreno_device *adreno_dev, unsigned int *cmds); unsigned int *cmds); int (*perfcounter_update)(struct adreno_device *adreno_dev, struct adreno_perfcount_register *reg, bool update_reg); }; }; /** /** Loading drivers/gpu/msm/adreno_a6xx.c +76 −3 Original line number Original line Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include <linux/firmware.h> #include <linux/firmware.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_restart.h> #include <linux/pm_opp.h> #include <linux/pm_opp.h> #include <linux/jiffies.h> #include "adreno.h" #include "adreno.h" #include "a6xx_reg.h" #include "a6xx_reg.h" Loading Loading @@ -3010,8 +3011,16 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = { A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, }; }; /* * ADRENO_PERFCOUNTER_GROUP_RESTORE flag is enabled by default * because most of the perfcounter groups need to be restored * as part of preemption and IFPC. Perfcounter groups that are * not restored as part of preemption and IFPC should be defined * using A6XX_PERFCOUNTER_GROUP_FLAGS macro */ #define A6XX_PERFCOUNTER_GROUP(offset, name) \ #define A6XX_PERFCOUNTER_GROUP(offset, name) \ ADRENO_PERFCOUNTER_GROUP(a6xx, offset, name) ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, \ ADRENO_PERFCOUNTER_GROUP_RESTORE) #define A6XX_PERFCOUNTER_GROUP_FLAGS(offset, name, flags) \ #define A6XX_PERFCOUNTER_GROUP_FLAGS(offset, name, flags) \ ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, flags) ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, flags) Loading @@ -3022,7 +3031,7 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = { static struct adreno_perfcount_group a6xx_perfcounter_groups static struct adreno_perfcount_group a6xx_perfcounter_groups [KGSL_PERFCOUNTER_GROUP_MAX] = { [KGSL_PERFCOUNTER_GROUP_MAX] = { A6XX_PERFCOUNTER_GROUP(CP, cp), A6XX_PERFCOUNTER_GROUP(CP, cp), A6XX_PERFCOUNTER_GROUP(RBBM, rbbm), A6XX_PERFCOUNTER_GROUP_FLAGS(RBBM, rbbm, 0), A6XX_PERFCOUNTER_GROUP(PC, pc), A6XX_PERFCOUNTER_GROUP(PC, pc), A6XX_PERFCOUNTER_GROUP(VFD, vfd), A6XX_PERFCOUNTER_GROUP(VFD, vfd), A6XX_PERFCOUNTER_GROUP(HLSQ, hlsq), A6XX_PERFCOUNTER_GROUP(HLSQ, hlsq), Loading @@ -3037,7 +3046,7 @@ static struct adreno_perfcount_group a6xx_perfcounter_groups A6XX_PERFCOUNTER_GROUP(SP, sp), A6XX_PERFCOUNTER_GROUP(SP, sp), A6XX_PERFCOUNTER_GROUP(RB, rb), A6XX_PERFCOUNTER_GROUP(RB, rb), A6XX_PERFCOUNTER_GROUP(VSC, vsc), A6XX_PERFCOUNTER_GROUP(VSC, vsc), A6XX_PERFCOUNTER_GROUP(VBIF, vbif), A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF, vbif, 0), A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF_PWR, vbif_pwr, A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF_PWR, vbif_pwr, ADRENO_PERFCOUNTER_GROUP_FIXED), ADRENO_PERFCOUNTER_GROUP_FIXED), A6XX_PERFCOUNTER_GROUP_FLAGS(PWR, pwr, A6XX_PERFCOUNTER_GROUP_FLAGS(PWR, pwr, Loading Loading @@ -3294,6 +3303,69 @@ static const struct adreno_reg_offsets a6xx_reg_offsets = { .offset_0 = ADRENO_REG_REGISTER_MAX, .offset_0 = ADRENO_REG_REGISTER_MAX, }; }; static int a6xx_perfcounter_update(struct adreno_device *adreno_dev, struct adreno_perfcount_register *reg, bool update_reg) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct cpu_gpu_lock *lock = adreno_dev->pwrup_reglist.hostptr; struct reg_list_pair *reg_pair = (struct reg_list_pair *)(lock + 1); unsigned int i; unsigned long timeout = jiffies + msecs_to_jiffies(1000); int ret = 0; lock->flag_kmd = 1; /* Write flag_kmd before turn */ wmb(); lock->turn = 0; /* Write these fields before looping */ mb(); /* * Spin here while GPU ucode holds the lock, lock->flag_ucode will * be set to 0 after GPU ucode releases the lock. Minimum wait time * is 1 second and this should be enough for GPU to release the lock */ while (lock->flag_ucode == 1 && lock->turn == 0) { cpu_relax(); /* Get the latest updates from GPU */ rmb(); /* * Make sure we wait at least 1sec for the lock, * if we did not get it after 1sec return an error. */ if (time_after(jiffies, timeout) && (lock->flag_ucode == 1 && lock->turn == 0)) { ret = -EBUSY; goto unlock; } } /* Read flag_ucode and turn before list_length */ rmb(); /* * If the perfcounter select register is already present in reglist * update it, otherwise append the <select register, value> pair to * the end of the list. */ for (i = 0; i < lock->list_length >> 1; i++) if (reg_pair[i].offset == reg->select) break; reg_pair[i].offset = reg->select; reg_pair[i].val = reg->countable; if (i == lock->list_length >> 1) lock->list_length += 2; if (update_reg) kgsl_regwrite(device, reg->select, reg->countable); unlock: /* All writes done before releasing the lock */ wmb(); lock->flag_kmd = 0; return ret; } struct adreno_gpudev adreno_a6xx_gpudev = { struct adreno_gpudev adreno_a6xx_gpudev = { .reg_offsets = &a6xx_reg_offsets, .reg_offsets = &a6xx_reg_offsets, .start = a6xx_start, .start = a6xx_start, Loading Loading @@ -3336,4 +3408,5 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .gx_is_on = a6xx_gx_is_on, .gx_is_on = a6xx_gx_is_on, .sptprac_is_on = a6xx_sptprac_is_on, .sptprac_is_on = a6xx_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, .ccu_invalidate = a6xx_ccu_invalidate, .perfcounter_update = a6xx_perfcounter_update, }; }; drivers/gpu/msm/adreno_perfcounter.c +9 −3 Original line number Original line Diff line number Diff line Loading @@ -775,6 +775,7 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_perfcount_register *reg; struct adreno_perfcount_register *reg; struct adreno_perfcount_group *grp; int i; int i; int ret = 0; int ret = 0; Loading @@ -789,7 +790,8 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev, if (countable == invalid_countable.countables[i]) if (countable == invalid_countable.countables[i]) return -EACCES; return -EACCES; } } reg = &(counters->groups[group].regs[counter]); grp = &(counters->groups[group]); reg = &(grp->regs[counter]); if (!adreno_is_a6xx(adreno_dev) && if (!adreno_is_a6xx(adreno_dev) && test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) { test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) { Loading Loading @@ -834,12 +836,16 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev, } } } else { } else { /* Select the desired perfcounter */ /* Select the desired perfcounter */ if (gpudev->perfcounter_update && (grp->flags & ADRENO_PERFCOUNTER_GROUP_RESTORE)) ret = gpudev->perfcounter_update(adreno_dev, reg, true); else kgsl_regwrite(device, reg->select, countable); kgsl_regwrite(device, reg->select, countable); } } if (!ret) if (!ret) reg->value = 0; reg->value = 0; return 0; return ret; } } /** /** Loading drivers/gpu/msm/adreno_perfcounter.h +8 −1 Original line number Original line Diff line number Diff line /* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2008-2015, 2017 The Linux Foundation. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -70,6 +70,13 @@ struct adreno_perfcount_group { #define ADRENO_PERFCOUNTER_GROUP_FIXED BIT(0) #define ADRENO_PERFCOUNTER_GROUP_FIXED BIT(0) /* * ADRENO_PERFCOUNTER_GROUP_RESTORE indicates CP needs to restore the select * registers of this perfcounter group as part of preemption and IFPC */ #define ADRENO_PERFCOUNTER_GROUP_RESTORE BIT(1) /** /** * adreno_perfcounts: all available perfcounter groups * adreno_perfcounts: all available perfcounter groups * @groups: available groups for this device * @groups: available groups for this device Loading Loading
drivers/gpu/msm/adreno.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -943,6 +943,9 @@ struct adreno_gpudev { bool (*sptprac_is_on)(struct adreno_device *); bool (*sptprac_is_on)(struct adreno_device *); unsigned int (*ccu_invalidate)(struct adreno_device *adreno_dev, unsigned int (*ccu_invalidate)(struct adreno_device *adreno_dev, unsigned int *cmds); unsigned int *cmds); int (*perfcounter_update)(struct adreno_device *adreno_dev, struct adreno_perfcount_register *reg, bool update_reg); }; }; /** /** Loading
drivers/gpu/msm/adreno_a6xx.c +76 −3 Original line number Original line Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include <linux/firmware.h> #include <linux/firmware.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_restart.h> #include <linux/pm_opp.h> #include <linux/pm_opp.h> #include <linux/jiffies.h> #include "adreno.h" #include "adreno.h" #include "a6xx_reg.h" #include "a6xx_reg.h" Loading Loading @@ -3010,8 +3011,16 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = { A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, }; }; /* * ADRENO_PERFCOUNTER_GROUP_RESTORE flag is enabled by default * because most of the perfcounter groups need to be restored * as part of preemption and IFPC. Perfcounter groups that are * not restored as part of preemption and IFPC should be defined * using A6XX_PERFCOUNTER_GROUP_FLAGS macro */ #define A6XX_PERFCOUNTER_GROUP(offset, name) \ #define A6XX_PERFCOUNTER_GROUP(offset, name) \ ADRENO_PERFCOUNTER_GROUP(a6xx, offset, name) ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, \ ADRENO_PERFCOUNTER_GROUP_RESTORE) #define A6XX_PERFCOUNTER_GROUP_FLAGS(offset, name, flags) \ #define A6XX_PERFCOUNTER_GROUP_FLAGS(offset, name, flags) \ ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, flags) ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, flags) Loading @@ -3022,7 +3031,7 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = { static struct adreno_perfcount_group a6xx_perfcounter_groups static struct adreno_perfcount_group a6xx_perfcounter_groups [KGSL_PERFCOUNTER_GROUP_MAX] = { [KGSL_PERFCOUNTER_GROUP_MAX] = { A6XX_PERFCOUNTER_GROUP(CP, cp), A6XX_PERFCOUNTER_GROUP(CP, cp), A6XX_PERFCOUNTER_GROUP(RBBM, rbbm), A6XX_PERFCOUNTER_GROUP_FLAGS(RBBM, rbbm, 0), A6XX_PERFCOUNTER_GROUP(PC, pc), A6XX_PERFCOUNTER_GROUP(PC, pc), A6XX_PERFCOUNTER_GROUP(VFD, vfd), A6XX_PERFCOUNTER_GROUP(VFD, vfd), A6XX_PERFCOUNTER_GROUP(HLSQ, hlsq), A6XX_PERFCOUNTER_GROUP(HLSQ, hlsq), Loading @@ -3037,7 +3046,7 @@ static struct adreno_perfcount_group a6xx_perfcounter_groups A6XX_PERFCOUNTER_GROUP(SP, sp), A6XX_PERFCOUNTER_GROUP(SP, sp), A6XX_PERFCOUNTER_GROUP(RB, rb), A6XX_PERFCOUNTER_GROUP(RB, rb), A6XX_PERFCOUNTER_GROUP(VSC, vsc), A6XX_PERFCOUNTER_GROUP(VSC, vsc), A6XX_PERFCOUNTER_GROUP(VBIF, vbif), A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF, vbif, 0), A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF_PWR, vbif_pwr, A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF_PWR, vbif_pwr, ADRENO_PERFCOUNTER_GROUP_FIXED), ADRENO_PERFCOUNTER_GROUP_FIXED), A6XX_PERFCOUNTER_GROUP_FLAGS(PWR, pwr, A6XX_PERFCOUNTER_GROUP_FLAGS(PWR, pwr, Loading Loading @@ -3294,6 +3303,69 @@ static const struct adreno_reg_offsets a6xx_reg_offsets = { .offset_0 = ADRENO_REG_REGISTER_MAX, .offset_0 = ADRENO_REG_REGISTER_MAX, }; }; static int a6xx_perfcounter_update(struct adreno_device *adreno_dev, struct adreno_perfcount_register *reg, bool update_reg) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct cpu_gpu_lock *lock = adreno_dev->pwrup_reglist.hostptr; struct reg_list_pair *reg_pair = (struct reg_list_pair *)(lock + 1); unsigned int i; unsigned long timeout = jiffies + msecs_to_jiffies(1000); int ret = 0; lock->flag_kmd = 1; /* Write flag_kmd before turn */ wmb(); lock->turn = 0; /* Write these fields before looping */ mb(); /* * Spin here while GPU ucode holds the lock, lock->flag_ucode will * be set to 0 after GPU ucode releases the lock. Minimum wait time * is 1 second and this should be enough for GPU to release the lock */ while (lock->flag_ucode == 1 && lock->turn == 0) { cpu_relax(); /* Get the latest updates from GPU */ rmb(); /* * Make sure we wait at least 1sec for the lock, * if we did not get it after 1sec return an error. */ if (time_after(jiffies, timeout) && (lock->flag_ucode == 1 && lock->turn == 0)) { ret = -EBUSY; goto unlock; } } /* Read flag_ucode and turn before list_length */ rmb(); /* * If the perfcounter select register is already present in reglist * update it, otherwise append the <select register, value> pair to * the end of the list. */ for (i = 0; i < lock->list_length >> 1; i++) if (reg_pair[i].offset == reg->select) break; reg_pair[i].offset = reg->select; reg_pair[i].val = reg->countable; if (i == lock->list_length >> 1) lock->list_length += 2; if (update_reg) kgsl_regwrite(device, reg->select, reg->countable); unlock: /* All writes done before releasing the lock */ wmb(); lock->flag_kmd = 0; return ret; } struct adreno_gpudev adreno_a6xx_gpudev = { struct adreno_gpudev adreno_a6xx_gpudev = { .reg_offsets = &a6xx_reg_offsets, .reg_offsets = &a6xx_reg_offsets, .start = a6xx_start, .start = a6xx_start, Loading Loading @@ -3336,4 +3408,5 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .gx_is_on = a6xx_gx_is_on, .gx_is_on = a6xx_gx_is_on, .sptprac_is_on = a6xx_sptprac_is_on, .sptprac_is_on = a6xx_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, .ccu_invalidate = a6xx_ccu_invalidate, .perfcounter_update = a6xx_perfcounter_update, }; };
drivers/gpu/msm/adreno_perfcounter.c +9 −3 Original line number Original line Diff line number Diff line Loading @@ -775,6 +775,7 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_perfcount_register *reg; struct adreno_perfcount_register *reg; struct adreno_perfcount_group *grp; int i; int i; int ret = 0; int ret = 0; Loading @@ -789,7 +790,8 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev, if (countable == invalid_countable.countables[i]) if (countable == invalid_countable.countables[i]) return -EACCES; return -EACCES; } } reg = &(counters->groups[group].regs[counter]); grp = &(counters->groups[group]); reg = &(grp->regs[counter]); if (!adreno_is_a6xx(adreno_dev) && if (!adreno_is_a6xx(adreno_dev) && test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) { test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) { Loading Loading @@ -834,12 +836,16 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev, } } } else { } else { /* Select the desired perfcounter */ /* Select the desired perfcounter */ if (gpudev->perfcounter_update && (grp->flags & ADRENO_PERFCOUNTER_GROUP_RESTORE)) ret = gpudev->perfcounter_update(adreno_dev, reg, true); else kgsl_regwrite(device, reg->select, countable); kgsl_regwrite(device, reg->select, countable); } } if (!ret) if (!ret) reg->value = 0; reg->value = 0; return 0; return ret; } } /** /** Loading
drivers/gpu/msm/adreno_perfcounter.h +8 −1 Original line number Original line Diff line number Diff line /* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2008-2015, 2017 The Linux Foundation. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -70,6 +70,13 @@ struct adreno_perfcount_group { #define ADRENO_PERFCOUNTER_GROUP_FIXED BIT(0) #define ADRENO_PERFCOUNTER_GROUP_FIXED BIT(0) /* * ADRENO_PERFCOUNTER_GROUP_RESTORE indicates CP needs to restore the select * registers of this perfcounter group as part of preemption and IFPC */ #define ADRENO_PERFCOUNTER_GROUP_RESTORE BIT(1) /** /** * adreno_perfcounts: all available perfcounter groups * adreno_perfcounts: all available perfcounter groups * @groups: available groups for this device * @groups: available groups for this device Loading