static DEFINE_PER_CPU(struct chip *, chip_info);
/*
- * Note: The set of pstates consists of contiguous integers, the
- * smallest of which is indicated by powernv_pstate_info.min, the
- * largest of which is indicated by powernv_pstate_info.max.
+ * Note:
+ * The set of pstates consists of contiguous integers.
+ * powernv_pstate_info stores the index of the frequency table for
+ * max, min and nominal frequencies. It also stores number of
+ * available frequencies.
*
- * The nominal pstate is the highest non-turbo pstate in this
- * platform. This is indicated by powernv_pstate_info.nominal.
+ * powernv_pstate_info.nominal indicates the index to the highest
+ * non-turbo frequency.
*/
static struct powernv_pstate_info {
- int min;
- int max;
- int nominal;
- int nr_pstates;
+ unsigned int min;
+ unsigned int max;
+ unsigned int nominal;
+ unsigned int nr_pstates;
} powernv_pstate_info;
+ /* Use following macros for conversions between pstate_id and index */
+ static inline int idx_to_pstate(unsigned int i)
+ {
++ if (unlikely(i >= powernv_pstate_info.nr_pstates)) {
++ pr_warn_once("index %u is out of bound\n", i);
++ return powernv_freqs[powernv_pstate_info.nominal].driver_data;
++ }
++
+ return powernv_freqs[i].driver_data;
+ }
+
+ static inline unsigned int pstate_to_idx(int pstate)
+ {
++ int min = powernv_freqs[powernv_pstate_info.min].driver_data;
++ int max = powernv_freqs[powernv_pstate_info.max].driver_data;
++
++ if (min > 0) {
++ if (unlikely((pstate < max) || (pstate > min))) {
++ pr_warn_once("pstate %d is out of bound\n", pstate);
++ return powernv_pstate_info.nominal;
++ }
++ } else {
++ if (unlikely((pstate > max) || (pstate < min))) {
++ pr_warn_once("pstate %d is out of bound\n", pstate);
++ return powernv_pstate_info.nominal;
++ }
++ }
+ /*
+ * abs() is deliberately used so that is works with
+ * both monotonically increasing and decreasing
+ * pstate values
+ */
+ return abs(pstate - idx_to_pstate(powernv_pstate_info.max));
+ }
+
static inline void reset_gpstates(struct cpufreq_policy *policy)
{
struct global_pstate_info *gpstates = policy->driver_data;
gpstates->last_sampled_time += time_diff;
gpstates->elapsed_time += time_diff;
- freq_data.pstate_id = gpstates->last_lpstate;
+ freq_data.pstate_id = idx_to_pstate(gpstates->last_lpstate_idx);
- if ((gpstates->last_gpstate == freq_data.pstate_id) ||
+ if ((gpstates->last_gpstate_idx == gpstates->last_lpstate_idx) ||
(gpstates->elapsed_time > MAX_RAMP_DOWN_TIME)) {
- gpstate_id = freq_data.pstate_id;
+ gpstate_idx = pstate_to_idx(freq_data.pstate_id);
reset_gpstates(policy);
- gpstates->highest_lpstate = freq_data.pstate_id;
+ gpstates->highest_lpstate_idx = gpstate_idx;
} else {
- gpstate_id = calc_global_pstate(gpstates->elapsed_time,
- gpstates->highest_lpstate,
- freq_data.pstate_id);
+ gpstate_idx = calc_global_pstate(gpstates->elapsed_time,
+ gpstates->highest_lpstate_idx,
- freq_data.pstate_id);
++ gpstates->last_lpstate_idx);
}
/*