The GMU RPMh vote construction repeats two patterns across a6xx_gmu_rpmh_arc_votes_init() and a6xx_gmu_rpmh_dep_votes_init(): reading a cmd-db aux-data resource (with the same "halve the byte count and reject empty" handling), and scanning an arc level array for the first corner that satisfies a target level.
Refactor out a6xx_gmu_rpmh_read_arc() and a6xx_gmu_rpmh_arc_index() to reduce code duplication and improve code readability. Assisted-by: LLM Signed-off-by: Akhil P Oommen <[email protected]> --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 138 ++++++++++++++++------------------ 1 file changed, 63 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 161b360bf3eb..0ed01ce1c5c5 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1711,74 +1711,85 @@ static unsigned int a6xx_gmu_get_arc_level(struct device *dev, return val; } +static const u16 *a6xx_gmu_rpmh_read_arc(const char *id, size_t *count) +{ + const u16 *vals; + + vals = cmd_db_read_aux_data(id, count); + if (IS_ERR(vals)) + return vals; + + *count >>= 1; + /* Exclude the trailing zero paddings if there are any */ + while (*count && !vals[*count - 1]) + (*count)--; + + if (!*count) + return ERR_PTR(-EINVAL); + + return vals; +} + +/* + * Find the first index in an arc level array whose level is greater than or + * equal to the target. If no level is high enough, either clamp to the + * highest available level (@clamp) or fail, dumping the list. + */ +static int a6xx_gmu_rpmh_arc_index(struct device *dev, const u16 *arc, + size_t arc_count, unsigned int level, bool clamp) +{ + int j; + + for (j = 0; j < arc_count; j++) { + if (arc[j] >= level) + return j; + } + + if (clamp) + return arc_count - 1; + + DRM_DEV_ERROR(dev, "Level %u not found in the RPMh list\n", level); + DRM_DEV_ERROR(dev, "Available levels:\n"); + for (j = 0; j < arc_count; j++) + DRM_DEV_ERROR(dev, " %u\n", arc[j]); + + return -EINVAL; +} + static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, unsigned long *freqs, int freqs_count, const char *pri_id, const char *sec_id) { - int i, j; + int i; const u16 *pri, *sec; size_t pri_count, sec_count; - pri = cmd_db_read_aux_data(pri_id, &pri_count); + pri = a6xx_gmu_rpmh_read_arc(pri_id, &pri_count); if (IS_ERR(pri)) return PTR_ERR(pri); - /* - * The data comes back as an array of unsigned shorts so adjust the - * count accordingly - */ - pri_count >>= 1; - if (!pri_count) - return -EINVAL; - sec = cmd_db_read_aux_data(sec_id, &sec_count); + sec = a6xx_gmu_rpmh_read_arc(sec_id, &sec_count); if (IS_ERR(sec)) return PTR_ERR(sec); - sec_count >>= 1; - if (!sec_count) - return -EINVAL; - /* Construct a vote for each frequency */ for (i = 0; i < freqs_count; i++) { - u8 pindex = 0, sindex = 0; unsigned int level = a6xx_gmu_get_arc_level(dev, freqs[i]); + int pindex, sindex; - /* Get the primary index that matches the arc level */ - for (j = 0; j < pri_count; j++) { - if (pri[j] >= level) { - pindex = j; - break; - } - } - - if (j == pri_count) { - DRM_DEV_ERROR(dev, - "Level %u not found in the RPMh list\n", - level); - DRM_DEV_ERROR(dev, "Available levels:\n"); - for (j = 0; j < pri_count; j++) - DRM_DEV_ERROR(dev, " %u\n", pri[j]); - - return -EINVAL; - } + pindex = a6xx_gmu_rpmh_arc_index(dev, pri, pri_count, level, false); + if (pindex < 0) + return pindex; /* - * Look for a level in in the secondary list that matches. If - * nothing fits, use the maximum non zero vote - * - * The secondary rail depends on the primary rail, so match it - * against the quantized primary voltage (which is >= the - * requested level), not the requested level itself. + * Look for a matching level in the secondary list; if nothing + * fits, clamp to the highest available vote. The secondary rail + * depends on the primary rail, so match it against the selected + * primary voltage (which is >= the requested level), not the + * requested level itself. */ - - for (j = 0; j < sec_count; j++) { - if (sec[j] >= pri[pindex]) { - sindex = j; - break; - } else if (sec[j]) { - sindex = j; - } - } + sindex = a6xx_gmu_rpmh_arc_index(dev, sec, sec_count, + pri[pindex], true); /* Construct the vote */ votes[i] = ((pri[pindex] & 0xffff) << 16) | @@ -1794,16 +1805,9 @@ static int a6xx_gmu_rpmh_dep_votes_init(struct device *dev, u32 *votes, const u16 *mx; size_t count; - mx = cmd_db_read_aux_data("mx.lvl", &count); + mx = a6xx_gmu_rpmh_read_arc("mx.lvl", &count); if (IS_ERR(mx)) return PTR_ERR(mx); - /* - * The data comes back as an array of unsigned shorts so adjust the - * count accordingly - */ - count >>= 1; - if (!count) - return -EINVAL; /* Fix the vote for zero frequency */ votes[0] = 0xffffffff; @@ -1811,26 +1815,10 @@ static int a6xx_gmu_rpmh_dep_votes_init(struct device *dev, u32 *votes, /* Construct a vote for rest of the corners */ for (int i = 1; i < freqs_count; i++) { unsigned int level = a6xx_gmu_get_arc_level(dev, freqs[i]); - u8 j, index = 0; + int index = a6xx_gmu_rpmh_arc_index(dev, mx, count, level, false); - /* Get the primary index that matches the arc level */ - for (j = 0; j < count; j++) { - if (mx[j] >= level) { - index = j; - break; - } - } - - if (j == count) { - DRM_DEV_ERROR(dev, - "Mx Level %u not found in the RPMh list\n", - level); - DRM_DEV_ERROR(dev, "Available levels:\n"); - for (j = 0; j < count; j++) - DRM_DEV_ERROR(dev, " %u\n", mx[j]); - - return -EINVAL; - } + if (index < 0) + return index; /* Construct the vote */ votes[i] = (0x3fff << 14) | (index << 8) | (0xff); -- 2.55.0
