Loading drivers/gpu/msm/adreno.c +4 −1 Original line number Diff line number Diff line Loading @@ -2759,8 +2759,11 @@ int adreno_set_constraint(struct kgsl_device *device, /* If a new constraint has been set for a context, cancel the old one */ if ((status == 0) && (context->id == device->pwrctrl.constraint.owner_id)) (context->id == device->pwrctrl.constraint.owner_id)) { trace_kgsl_constraint(device, device->pwrctrl.constraint.type, device->pwrctrl.active_pwrlevel, 0); device->pwrctrl.constraint.type = KGSL_CONSTRAINT_NONE; } return status; } Loading drivers/gpu/msm/adreno_ringbuffer.c +4 −61 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include "kgsl_sharedmem.h" #include "kgsl_cffdump.h" #include "kgsl_trace.h" #include "kgsl_pwrctrl.h" #include "adreno.h" #include "adreno_pm4types.h" Loading Loading @@ -1183,35 +1184,9 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, return ret; } unsigned int adreno_ringbuffer_get_constraint(struct kgsl_device *device, struct kgsl_context *context) { unsigned int pwrlevel = device->pwrctrl.active_pwrlevel; switch (context->pwr_constraint.type) { case KGSL_CONSTRAINT_PWRLEVEL: { switch (context->pwr_constraint.sub_type) { case KGSL_CONSTRAINT_PWR_MAX: pwrlevel = device->pwrctrl.max_pwrlevel; break; case KGSL_CONSTRAINT_PWR_MIN: pwrlevel = device->pwrctrl.min_pwrlevel; break; default: break; } } break; } return pwrlevel; } void adreno_ringbuffer_set_constraint(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch) { unsigned int constraint; struct kgsl_context *context = cmdbatch->context; /* * Check if the context has a constraint and constraint flags are Loading @@ -1219,41 +1194,9 @@ void adreno_ringbuffer_set_constraint(struct kgsl_device *device, */ if (context->pwr_constraint.type && ((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) || (cmdbatch->flags & KGSL_CMDBATCH_PWR_CONSTRAINT))) { constraint = adreno_ringbuffer_get_constraint(device, context); /* * If a constraint is already set, set a new constraint only * if it is faster. If the requested constraint is the same * as the current one, update ownership and timestamp. */ if ((device->pwrctrl.constraint.type == KGSL_CONSTRAINT_NONE) || (constraint < device->pwrctrl.constraint.hint.pwrlevel.level)) { kgsl_pwrctrl_pwrlevel_change(device, constraint); device->pwrctrl.constraint.type = context->pwr_constraint.type; device->pwrctrl.constraint.hint. pwrlevel.level = constraint; device->pwrctrl.constraint.owner_id = context->id; device->pwrctrl.constraint.expires = jiffies + device->pwrctrl.interval_timeout; /* Trace the constraint being set by the driver */ trace_kgsl_constraint(device, device->pwrctrl.constraint.type, constraint, 1); } else if ((device->pwrctrl.constraint.type == context->pwr_constraint.type) && (device->pwrctrl.constraint.hint.pwrlevel.level == constraint)) { device->pwrctrl.constraint.owner_id = context->id; device->pwrctrl.constraint.expires = jiffies + device->pwrctrl.interval_timeout; } } (cmdbatch->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) kgsl_pwrctrl_set_constraint(device, &context->pwr_constraint, context->id); } /* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */ Loading drivers/gpu/msm/kgsl_pwrctrl.c +130 −56 Original line number Diff line number Diff line Loading @@ -87,18 +87,40 @@ static void kgsl_pwrctrl_set_state(struct kgsl_device *device, static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); /* * Given a requested power level do bounds checking on the constraints and * return the nearest possible level /** * _adjust_pwrlevel() - Given a requested power level do bounds checking on the * constraints and return the nearest possible level * @device: Pointer to the kgsl_device struct * @level: Requested level * @pwrc: Pointer to the power constraint to be applied * * Apply thermal and max/min limits first. Then force the level with a * constraint if one exists. */ static inline unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level) static unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level, struct kgsl_pwr_constraint *pwrc) { unsigned int max_pwrlevel = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->max_pwrlevel); unsigned int min_pwrlevel = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->min_pwrlevel); switch (pwrc->type) { case KGSL_CONSTRAINT_PWRLEVEL: { switch (pwrc->sub_type) { case KGSL_CONSTRAINT_PWR_MAX: return max_pwrlevel; break; case KGSL_CONSTRAINT_PWR_MIN: return min_pwrlevel; break; default: break; } } break; } if (level < max_pwrlevel) return max_pwrlevel; if (level > min_pwrlevel) Loading @@ -107,6 +129,11 @@ static inline unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level) return level; } /** * kgsl_pwrctrl_buslevel_update() - Recalculate the bus vote and send it * @device: Pointer to the kgsl_device struct * @on: true for setting and active bus vote, false to turn off the vote */ void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device, bool on) { Loading @@ -126,22 +153,51 @@ void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device, buslevel = min_t(int, pwr->pwrlevels[0].bus_freq, cur + pwr->bus_mod); buslevel = max_t(int, buslevel, 1); } else { /* If the bus is being turned off, reset to default level */ pwr->bus_mod = 0; } msm_bus_scale_client_update_request(pwr->pcl, buslevel); trace_kgsl_buslevel(device, pwr->active_pwrlevel, buslevel); } EXPORT_SYMBOL(kgsl_pwrctrl_buslevel_update); /** * kgsl_pwrctrl_pwrlevel_change() - Validate and change power levels * @device: Pointer to the kgsl_device struct * @new_level: Requested powerlevel, an index into the pwrlevel array * * Check that any power level constraints are still valid. Update the * requested level according to any thermal, max/min, or power constraints. * If a new GPU level is going to be set, update the bus to that level's * default value. Do not change the bus if a constraint keeps the new * level at the current level. Set the new GPU frequency. */ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, unsigned int new_level) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrlevel *pwrlevel; unsigned int old_level = pwr->active_pwrlevel; /* Adjust the power level to the current constraints */ new_level = _adjust_pwrlevel(pwr, new_level); /* If a pwr constraint is expired, remove it */ if ((pwr->constraint.type != KGSL_CONSTRAINT_NONE) && (time_after(jiffies, pwr->constraint.expires))) { /* Trace the constraint being un-set by the driver */ trace_kgsl_constraint(device, pwr->constraint.type, old_level, 0); /*Invalidate the constraint set */ pwr->constraint.expires = 0; pwr->constraint.type = KGSL_CONSTRAINT_NONE; } if (new_level == pwr->active_pwrlevel) /* * Adjust the power level if required by thermal, max/min, * constraints, etc */ new_level = _adjust_pwrlevel(pwr, new_level, &pwr->constraint); if (new_level == old_level) return; /* Loading @@ -149,20 +205,68 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, * don't do this then the pwrlevel change won't take effect when the * clocks come back */ pwr->active_pwrlevel = new_level; pwr->bus_mod = 0; pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel]; /* * Update the bus before the GPU clock to prevent underrun during * frequency increases. */ pwr->bus_mod = 0; kgsl_pwrctrl_buslevel_update(device, true); clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[new_level].gpu_freq); pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel]; clk_set_rate(pwr->grp_clks[0], pwrlevel->gpu_freq); trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq); } EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); /** * kgsl_pwrctrl_set_constraint() - Validate and change enforced constraint * @device: Pointer to the kgsl_device struct * @pwrc: Pointer to requested constraint * @id: Context id which owns the constraint * * Accept the new constraint if no previous constraint existed or if the * new constraint is faster than the previous one. If the new and previous * constraints are equal, update the timestamp and ownership to make sure * the constraint expires at the correct time. */ void kgsl_pwrctrl_set_constraint(struct kgsl_device *device, struct kgsl_pwr_constraint *pwrc, uint32_t id) { unsigned int constraint; struct kgsl_pwr_constraint *pwrc_old; trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq); } if (device == NULL || pwrc == NULL) return; constraint = _adjust_pwrlevel(&device->pwrctrl, device->pwrctrl.active_pwrlevel, pwrc); pwrc_old = &device->pwrctrl.constraint; EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); /* * If a constraint is already set, set a new constraint only * if it is faster. If the requested constraint is the same * as the current one, update ownership and timestamp. */ if ((pwrc_old->type == KGSL_CONSTRAINT_NONE) || (constraint < pwrc_old->hint.pwrlevel.level)) { pwrc_old->type = pwrc->type; pwrc_old->sub_type = pwrc->sub_type; pwrc_old->hint.pwrlevel.level = constraint; pwrc_old->owner_id = id; pwrc_old->expires = jiffies + device->pwrctrl.interval_timeout; kgsl_pwrctrl_pwrlevel_change(device, constraint); /* Trace the constraint being set by the driver */ trace_kgsl_constraint(device, pwrc_old->type, constraint, 1); } else if ((pwrc_old->type == pwrc->type) && (pwrc_old->hint.pwrlevel.level == constraint)) { pwrc_old->owner_id = id; pwrc_old->expires = jiffies + device->pwrctrl.interval_timeout; } } EXPORT_SYMBOL(kgsl_pwrctrl_set_constraint); static ssize_t kgsl_pwrctrl_thermal_pwrlevel_store(struct device *dev, struct device_attribute *attr, Loading Loading @@ -190,15 +294,8 @@ static ssize_t kgsl_pwrctrl_thermal_pwrlevel_store(struct device *dev, pwr->thermal_pwrlevel = level; /* * If there is no power policy set the clock to the requested thermal * level - if thermal now happens to be higher than max, then that will * be limited by the pwrlevel change function. Otherwise if there is * a policy only change the active clock if it is higher then the new * thermal level */ if (pwr->thermal_pwrlevel > pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel); /* Update the current level using the new limit */ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); mutex_unlock(&device->mutex); return count; Loading @@ -224,7 +321,7 @@ static ssize_t kgsl_pwrctrl_max_pwrlevel_store(struct device *dev, struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; int ret; unsigned int max_level, level = 0; unsigned int level = 0; if (device == NULL) return 0; Loading @@ -243,16 +340,8 @@ static ssize_t kgsl_pwrctrl_max_pwrlevel_store(struct device *dev, pwr->max_pwrlevel = level; max_level = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->max_pwrlevel); /* * If there is no policy then move to max by default. Otherwise only * move max if the current level happens to be higher then the new max */ if (max_level > pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, max_level); /* Update the current level using the new limit */ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); mutex_unlock(&device->mutex); return count; Loading @@ -277,7 +366,7 @@ static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev, { struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; int ret; unsigned int min_level, level = 0; unsigned int level = 0; if (device == NULL) return 0; Loading @@ -298,15 +387,8 @@ static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev, pwr->min_pwrlevel = level; min_level = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->min_pwrlevel); /* Only move the power level higher if minimum is higher then the * current level */ if (min_level < pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, min_level); /* Update the current level using the new limit */ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); mutex_unlock(&device->mutex); Loading Loading @@ -377,13 +459,8 @@ static ssize_t kgsl_pwrctrl_max_gpuclk_store(struct device *dev, pwr->thermal_pwrlevel = (unsigned int) level; /* * if the thermal limit is lower than the current setting, * move the speed down immediately */ if (pwr->thermal_pwrlevel > pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel); /* Update the current level using the new limit */ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); done: mutex_unlock(&device->mutex); Loading Loading @@ -1490,9 +1567,6 @@ int kgsl_pwrctrl_enable(struct kgsl_device *device) } else level = pwr->default_pwrlevel; pwr->bus_mod = 0; if (pwr->constraint.type == KGSL_CONSTRAINT_NONE) kgsl_pwrctrl_pwrlevel_change(device, level); /* Order pwrrail/clk sequence based upon platform */ Loading drivers/gpu/msm/kgsl_pwrctrl.h +2 −0 Original line number Diff line number Diff line Loading @@ -162,4 +162,6 @@ int __must_check kgsl_active_count_get(struct kgsl_device *device); void kgsl_active_count_put(struct kgsl_device *device); int kgsl_active_count_wait(struct kgsl_device *device, int count); void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy); void kgsl_pwrctrl_set_constraint(struct kgsl_device *device, struct kgsl_pwr_constraint *pwrc, uint32_t id); #endif /* __KGSL_PWRCTRL_H */ drivers/gpu/msm/kgsl_pwrscale.c +4 −24 Original line number Diff line number Diff line Loading @@ -227,6 +227,7 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) level = pwr->active_pwrlevel; pwr_level = &pwr->pwrlevels[level]; /* If the governor recommends a new frequency, update it here */ if (*freq != cur_freq) { level = pwr->max_pwrlevel; for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--) Loading @@ -234,6 +235,8 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) level = i; break; } if (level != pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, level); } else if (flags && pwr->bus_control) { /* * Signal for faster or slower bus. If KGSL isn't already Loading @@ -253,30 +256,7 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) kgsl_pwrctrl_buslevel_update(device, true); } /* * The power constraints need an entire interval to do their magic, so * skip changing the powerlevel if the time hasn't expired yet and the * new level is less than the constraint */ if ((pwr->constraint.type != KGSL_CONSTRAINT_NONE) && (!time_after(jiffies, pwr->constraint.expires))) *freq = cur_freq; else { /* Change the power level */ kgsl_pwrctrl_pwrlevel_change(device, level); if (pwr->constraint.type != KGSL_CONSTRAINT_NONE) { /* Trace the constraint being un-set by the driver */ trace_kgsl_constraint(device, pwr->constraint.type, level, 0); /*Invalidate the constraint set */ pwr->constraint.type = KGSL_CONSTRAINT_NONE; } pwr->constraint.expires = 0; *freq = kgsl_pwrctrl_active_freq(pwr); } mutex_unlock(&device->mutex); return 0; Loading Loading
drivers/gpu/msm/adreno.c +4 −1 Original line number Diff line number Diff line Loading @@ -2759,8 +2759,11 @@ int adreno_set_constraint(struct kgsl_device *device, /* If a new constraint has been set for a context, cancel the old one */ if ((status == 0) && (context->id == device->pwrctrl.constraint.owner_id)) (context->id == device->pwrctrl.constraint.owner_id)) { trace_kgsl_constraint(device, device->pwrctrl.constraint.type, device->pwrctrl.active_pwrlevel, 0); device->pwrctrl.constraint.type = KGSL_CONSTRAINT_NONE; } return status; } Loading
drivers/gpu/msm/adreno_ringbuffer.c +4 −61 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include "kgsl_sharedmem.h" #include "kgsl_cffdump.h" #include "kgsl_trace.h" #include "kgsl_pwrctrl.h" #include "adreno.h" #include "adreno_pm4types.h" Loading Loading @@ -1183,35 +1184,9 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, return ret; } unsigned int adreno_ringbuffer_get_constraint(struct kgsl_device *device, struct kgsl_context *context) { unsigned int pwrlevel = device->pwrctrl.active_pwrlevel; switch (context->pwr_constraint.type) { case KGSL_CONSTRAINT_PWRLEVEL: { switch (context->pwr_constraint.sub_type) { case KGSL_CONSTRAINT_PWR_MAX: pwrlevel = device->pwrctrl.max_pwrlevel; break; case KGSL_CONSTRAINT_PWR_MIN: pwrlevel = device->pwrctrl.min_pwrlevel; break; default: break; } } break; } return pwrlevel; } void adreno_ringbuffer_set_constraint(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch) { unsigned int constraint; struct kgsl_context *context = cmdbatch->context; /* * Check if the context has a constraint and constraint flags are Loading @@ -1219,41 +1194,9 @@ void adreno_ringbuffer_set_constraint(struct kgsl_device *device, */ if (context->pwr_constraint.type && ((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) || (cmdbatch->flags & KGSL_CMDBATCH_PWR_CONSTRAINT))) { constraint = adreno_ringbuffer_get_constraint(device, context); /* * If a constraint is already set, set a new constraint only * if it is faster. If the requested constraint is the same * as the current one, update ownership and timestamp. */ if ((device->pwrctrl.constraint.type == KGSL_CONSTRAINT_NONE) || (constraint < device->pwrctrl.constraint.hint.pwrlevel.level)) { kgsl_pwrctrl_pwrlevel_change(device, constraint); device->pwrctrl.constraint.type = context->pwr_constraint.type; device->pwrctrl.constraint.hint. pwrlevel.level = constraint; device->pwrctrl.constraint.owner_id = context->id; device->pwrctrl.constraint.expires = jiffies + device->pwrctrl.interval_timeout; /* Trace the constraint being set by the driver */ trace_kgsl_constraint(device, device->pwrctrl.constraint.type, constraint, 1); } else if ((device->pwrctrl.constraint.type == context->pwr_constraint.type) && (device->pwrctrl.constraint.hint.pwrlevel.level == constraint)) { device->pwrctrl.constraint.owner_id = context->id; device->pwrctrl.constraint.expires = jiffies + device->pwrctrl.interval_timeout; } } (cmdbatch->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) kgsl_pwrctrl_set_constraint(device, &context->pwr_constraint, context->id); } /* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */ Loading
drivers/gpu/msm/kgsl_pwrctrl.c +130 −56 Original line number Diff line number Diff line Loading @@ -87,18 +87,40 @@ static void kgsl_pwrctrl_set_state(struct kgsl_device *device, static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); /* * Given a requested power level do bounds checking on the constraints and * return the nearest possible level /** * _adjust_pwrlevel() - Given a requested power level do bounds checking on the * constraints and return the nearest possible level * @device: Pointer to the kgsl_device struct * @level: Requested level * @pwrc: Pointer to the power constraint to be applied * * Apply thermal and max/min limits first. Then force the level with a * constraint if one exists. */ static inline unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level) static unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level, struct kgsl_pwr_constraint *pwrc) { unsigned int max_pwrlevel = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->max_pwrlevel); unsigned int min_pwrlevel = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->min_pwrlevel); switch (pwrc->type) { case KGSL_CONSTRAINT_PWRLEVEL: { switch (pwrc->sub_type) { case KGSL_CONSTRAINT_PWR_MAX: return max_pwrlevel; break; case KGSL_CONSTRAINT_PWR_MIN: return min_pwrlevel; break; default: break; } } break; } if (level < max_pwrlevel) return max_pwrlevel; if (level > min_pwrlevel) Loading @@ -107,6 +129,11 @@ static inline unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level) return level; } /** * kgsl_pwrctrl_buslevel_update() - Recalculate the bus vote and send it * @device: Pointer to the kgsl_device struct * @on: true for setting and active bus vote, false to turn off the vote */ void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device, bool on) { Loading @@ -126,22 +153,51 @@ void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device, buslevel = min_t(int, pwr->pwrlevels[0].bus_freq, cur + pwr->bus_mod); buslevel = max_t(int, buslevel, 1); } else { /* If the bus is being turned off, reset to default level */ pwr->bus_mod = 0; } msm_bus_scale_client_update_request(pwr->pcl, buslevel); trace_kgsl_buslevel(device, pwr->active_pwrlevel, buslevel); } EXPORT_SYMBOL(kgsl_pwrctrl_buslevel_update); /** * kgsl_pwrctrl_pwrlevel_change() - Validate and change power levels * @device: Pointer to the kgsl_device struct * @new_level: Requested powerlevel, an index into the pwrlevel array * * Check that any power level constraints are still valid. Update the * requested level according to any thermal, max/min, or power constraints. * If a new GPU level is going to be set, update the bus to that level's * default value. Do not change the bus if a constraint keeps the new * level at the current level. Set the new GPU frequency. */ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, unsigned int new_level) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrlevel *pwrlevel; unsigned int old_level = pwr->active_pwrlevel; /* Adjust the power level to the current constraints */ new_level = _adjust_pwrlevel(pwr, new_level); /* If a pwr constraint is expired, remove it */ if ((pwr->constraint.type != KGSL_CONSTRAINT_NONE) && (time_after(jiffies, pwr->constraint.expires))) { /* Trace the constraint being un-set by the driver */ trace_kgsl_constraint(device, pwr->constraint.type, old_level, 0); /*Invalidate the constraint set */ pwr->constraint.expires = 0; pwr->constraint.type = KGSL_CONSTRAINT_NONE; } if (new_level == pwr->active_pwrlevel) /* * Adjust the power level if required by thermal, max/min, * constraints, etc */ new_level = _adjust_pwrlevel(pwr, new_level, &pwr->constraint); if (new_level == old_level) return; /* Loading @@ -149,20 +205,68 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, * don't do this then the pwrlevel change won't take effect when the * clocks come back */ pwr->active_pwrlevel = new_level; pwr->bus_mod = 0; pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel]; /* * Update the bus before the GPU clock to prevent underrun during * frequency increases. */ pwr->bus_mod = 0; kgsl_pwrctrl_buslevel_update(device, true); clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[new_level].gpu_freq); pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel]; clk_set_rate(pwr->grp_clks[0], pwrlevel->gpu_freq); trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq); } EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); /** * kgsl_pwrctrl_set_constraint() - Validate and change enforced constraint * @device: Pointer to the kgsl_device struct * @pwrc: Pointer to requested constraint * @id: Context id which owns the constraint * * Accept the new constraint if no previous constraint existed or if the * new constraint is faster than the previous one. If the new and previous * constraints are equal, update the timestamp and ownership to make sure * the constraint expires at the correct time. */ void kgsl_pwrctrl_set_constraint(struct kgsl_device *device, struct kgsl_pwr_constraint *pwrc, uint32_t id) { unsigned int constraint; struct kgsl_pwr_constraint *pwrc_old; trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq); } if (device == NULL || pwrc == NULL) return; constraint = _adjust_pwrlevel(&device->pwrctrl, device->pwrctrl.active_pwrlevel, pwrc); pwrc_old = &device->pwrctrl.constraint; EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); /* * If a constraint is already set, set a new constraint only * if it is faster. If the requested constraint is the same * as the current one, update ownership and timestamp. */ if ((pwrc_old->type == KGSL_CONSTRAINT_NONE) || (constraint < pwrc_old->hint.pwrlevel.level)) { pwrc_old->type = pwrc->type; pwrc_old->sub_type = pwrc->sub_type; pwrc_old->hint.pwrlevel.level = constraint; pwrc_old->owner_id = id; pwrc_old->expires = jiffies + device->pwrctrl.interval_timeout; kgsl_pwrctrl_pwrlevel_change(device, constraint); /* Trace the constraint being set by the driver */ trace_kgsl_constraint(device, pwrc_old->type, constraint, 1); } else if ((pwrc_old->type == pwrc->type) && (pwrc_old->hint.pwrlevel.level == constraint)) { pwrc_old->owner_id = id; pwrc_old->expires = jiffies + device->pwrctrl.interval_timeout; } } EXPORT_SYMBOL(kgsl_pwrctrl_set_constraint); static ssize_t kgsl_pwrctrl_thermal_pwrlevel_store(struct device *dev, struct device_attribute *attr, Loading Loading @@ -190,15 +294,8 @@ static ssize_t kgsl_pwrctrl_thermal_pwrlevel_store(struct device *dev, pwr->thermal_pwrlevel = level; /* * If there is no power policy set the clock to the requested thermal * level - if thermal now happens to be higher than max, then that will * be limited by the pwrlevel change function. Otherwise if there is * a policy only change the active clock if it is higher then the new * thermal level */ if (pwr->thermal_pwrlevel > pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel); /* Update the current level using the new limit */ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); mutex_unlock(&device->mutex); return count; Loading @@ -224,7 +321,7 @@ static ssize_t kgsl_pwrctrl_max_pwrlevel_store(struct device *dev, struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; int ret; unsigned int max_level, level = 0; unsigned int level = 0; if (device == NULL) return 0; Loading @@ -243,16 +340,8 @@ static ssize_t kgsl_pwrctrl_max_pwrlevel_store(struct device *dev, pwr->max_pwrlevel = level; max_level = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->max_pwrlevel); /* * If there is no policy then move to max by default. Otherwise only * move max if the current level happens to be higher then the new max */ if (max_level > pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, max_level); /* Update the current level using the new limit */ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); mutex_unlock(&device->mutex); return count; Loading @@ -277,7 +366,7 @@ static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev, { struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; int ret; unsigned int min_level, level = 0; unsigned int level = 0; if (device == NULL) return 0; Loading @@ -298,15 +387,8 @@ static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev, pwr->min_pwrlevel = level; min_level = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->min_pwrlevel); /* Only move the power level higher if minimum is higher then the * current level */ if (min_level < pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, min_level); /* Update the current level using the new limit */ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); mutex_unlock(&device->mutex); Loading Loading @@ -377,13 +459,8 @@ static ssize_t kgsl_pwrctrl_max_gpuclk_store(struct device *dev, pwr->thermal_pwrlevel = (unsigned int) level; /* * if the thermal limit is lower than the current setting, * move the speed down immediately */ if (pwr->thermal_pwrlevel > pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel); /* Update the current level using the new limit */ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); done: mutex_unlock(&device->mutex); Loading Loading @@ -1490,9 +1567,6 @@ int kgsl_pwrctrl_enable(struct kgsl_device *device) } else level = pwr->default_pwrlevel; pwr->bus_mod = 0; if (pwr->constraint.type == KGSL_CONSTRAINT_NONE) kgsl_pwrctrl_pwrlevel_change(device, level); /* Order pwrrail/clk sequence based upon platform */ Loading
drivers/gpu/msm/kgsl_pwrctrl.h +2 −0 Original line number Diff line number Diff line Loading @@ -162,4 +162,6 @@ int __must_check kgsl_active_count_get(struct kgsl_device *device); void kgsl_active_count_put(struct kgsl_device *device); int kgsl_active_count_wait(struct kgsl_device *device, int count); void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy); void kgsl_pwrctrl_set_constraint(struct kgsl_device *device, struct kgsl_pwr_constraint *pwrc, uint32_t id); #endif /* __KGSL_PWRCTRL_H */
drivers/gpu/msm/kgsl_pwrscale.c +4 −24 Original line number Diff line number Diff line Loading @@ -227,6 +227,7 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) level = pwr->active_pwrlevel; pwr_level = &pwr->pwrlevels[level]; /* If the governor recommends a new frequency, update it here */ if (*freq != cur_freq) { level = pwr->max_pwrlevel; for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--) Loading @@ -234,6 +235,8 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) level = i; break; } if (level != pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, level); } else if (flags && pwr->bus_control) { /* * Signal for faster or slower bus. If KGSL isn't already Loading @@ -253,30 +256,7 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) kgsl_pwrctrl_buslevel_update(device, true); } /* * The power constraints need an entire interval to do their magic, so * skip changing the powerlevel if the time hasn't expired yet and the * new level is less than the constraint */ if ((pwr->constraint.type != KGSL_CONSTRAINT_NONE) && (!time_after(jiffies, pwr->constraint.expires))) *freq = cur_freq; else { /* Change the power level */ kgsl_pwrctrl_pwrlevel_change(device, level); if (pwr->constraint.type != KGSL_CONSTRAINT_NONE) { /* Trace the constraint being un-set by the driver */ trace_kgsl_constraint(device, pwr->constraint.type, level, 0); /*Invalidate the constraint set */ pwr->constraint.type = KGSL_CONSTRAINT_NONE; } pwr->constraint.expires = 0; *freq = kgsl_pwrctrl_active_freq(pwr); } mutex_unlock(&device->mutex); return 0; Loading