Merge branches 'pm-sleep' and 'pm-cpufreq'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 12 Aug 2016 20:53:58 +0000 (22:53 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 12 Aug 2016 20:53:58 +0000 (22:53 +0200)
* pm-sleep:
  PM / hibernate: Restore processor state before using per-CPU variables
  x86/power/64: Always create temporary identity mapping correctly

* pm-cpufreq:
  cpufreq: powernv: Fix crash in gpstate_timer_handler()

1  2  3 
drivers/cpufreq/powernv-cpufreq.c
kernel/power/hibernate.c

index 87796e0864e945e41725be06106234ca8a32a133,54c45368e3f17d3333a124cbb378ccf0fefee9fe,2fcc879d2b97483876e9736c734f48e493eb534f..d3ffde8066298ff48d64c990eefe1dec0bf34cb6
@@@@ -126,38 -124,20 -126,57 +126,57 @@@@ static int nr_chips
   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;
@@@@ -583,17 -557,17 -603,17 +602,17 @@@@ void gpstate_timer_handler(unsigned lon
   
        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);
        }
   
        /*
Simple merge