Commit 923c256e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branches 'pm-cpuidle' and 'pm-em'

Merge cpuidle and Energy Model changes for 6.13-rc1:

 - Add a built-in idle states table for Granite Rapids Xeon D to the
   intel_idle driver (Artem Bityutskiy).

 - Fix some typos in comments in the cpuidle core and drivers (Shen
   Lichuan).

 - Remove iowait influence from the menu cpuidle governor (Christian
   Loehle).

 - Add min/max available performance state limits to the Energy Model
   management code (Lukasz Luba).

* pm-cpuidle:
  intel_idle: add Granite Rapids Xeon D support
  cpuidle: Correct some typos in comments
  cpuidle: menu: Remove iowait influence

* pm-em:
  PM: EM: Add min/max available performance state limits
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -139,7 +139,7 @@ static int __init arm_idle_init_cpu(int cpu)
 *
 * Initializes arm cpuidle driver for all CPUs, if any CPU fails
 * to register cpuidle driver then rollback to cancel all CPUs
 * registeration.
 * registration.
 */
static int __init arm_idle_init(void)
{
+1 −1
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ static int qcom_cpu_spc(struct spm_driver_data *drv)
	ret = cpu_suspend(0, qcom_pm_collapse);
	/*
	 * ARM common code executes WFI without calling into our driver and
	 * if the SPM mode is not reset, then we may accidently power down the
	 * if the SPM mode is not reset, then we may accidentally power down the
	 * cpu when we intended only to gate the cpu clock.
	 * Ensure the state is set to standby before returning.
	 */
+1 −1
Original line number Diff line number Diff line
@@ -406,7 +406,7 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index)
 * Min polling interval of 10usec is a guess. It is assuming that
 * for most users, the time for a single ping-pong workload like
 * perf bench pipe would generally complete within 10usec but
 * this is hardware dependant. Actual time can be estimated with
 * this is hardware dependent. Actual time can be estimated with
 *
 * perf bench sched pipe -l 10000
 *
+2 −2
Original line number Diff line number Diff line
@@ -261,7 +261,7 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
 * @drv: a pointer to a valid struct cpuidle_driver
 *
 * Register the driver under a lock to prevent concurrent attempts to
 * [un]register the driver from occuring at the same time.
 * [un]register the driver from occurring at the same time.
 *
 * Returns 0 on success, a negative error code (returned by
 * __cpuidle_register_driver()) otherwise.
@@ -296,7 +296,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver);
 * @drv: a pointer to a valid struct cpuidle_driver
 *
 * Unregisters the cpuidle driver under a lock to prevent concurrent attempts
 * to [un]register the driver from occuring at the same time.  @drv has to
 * to [un]register the driver from occurring at the same time.  @drv has to
 * match the currently registered driver.
 */
void cpuidle_unregister_driver(struct cpuidle_driver *drv)
+9 −67
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

#include "gov.h"

#define BUCKETS 12
#define BUCKETS 6
#define INTERVAL_SHIFT 3
#define INTERVALS (1UL << INTERVAL_SHIFT)
#define RESOLUTION 1024
@@ -29,12 +29,11 @@
/*
 * Concepts and ideas behind the menu governor
 *
 * For the menu governor, there are 3 decision factors for picking a C
 * For the menu governor, there are 2 decision factors for picking a C
 * state:
 * 1) Energy break even point
 * 2) Performance impact
 * 3) Latency tolerance (from pmqos infrastructure)
 * These three factors are treated independently.
 * 2) Latency tolerance (from pmqos infrastructure)
 * These two factors are treated independently.
 *
 * Energy break even point
 * -----------------------
@@ -75,30 +74,6 @@
 * intervals and if the stand deviation of these 8 intervals is below a
 * threshold value, we use the average of these intervals as prediction.
 *
 * Limiting Performance Impact
 * ---------------------------
 * C states, especially those with large exit latencies, can have a real
 * noticeable impact on workloads, which is not acceptable for most sysadmins,
 * and in addition, less performance has a power price of its own.
 *
 * As a general rule of thumb, menu assumes that the following heuristic
 * holds:
 *     The busier the system, the less impact of C states is acceptable
 *
 * This rule-of-thumb is implemented using a performance-multiplier:
 * If the exit latency times the performance multiplier is longer than
 * the predicted duration, the C state is not considered a candidate
 * for selection due to a too high performance impact. So the higher
 * this multiplier is, the longer we need to be idle to pick a deep C
 * state, and thus the less likely a busy CPU will hit such a deep
 * C state.
 *
 * Currently there is only one value determining the factor:
 * 10 points are added for each process that is waiting for IO on this CPU.
 * (This value was experimentally determined.)
 * Utilization is no longer a factor as it was shown that it never contributed
 * significantly to the performance multiplier in the first place.
 *
 */

struct menu_device {
@@ -112,19 +87,10 @@ struct menu_device {
	int		interval_ptr;
};

static inline int which_bucket(u64 duration_ns, unsigned int nr_iowaiters)
static inline int which_bucket(u64 duration_ns)
{
	int bucket = 0;

	/*
	 * We keep two groups of stats; one with no
	 * IO pending, one without.
	 * This allows us to calculate
	 * E(duration)|iowait
	 */
	if (nr_iowaiters)
		bucket = BUCKETS/2;

	if (duration_ns < 10ULL * NSEC_PER_USEC)
		return bucket;
	if (duration_ns < 100ULL * NSEC_PER_USEC)
@@ -138,19 +104,6 @@ static inline int which_bucket(u64 duration_ns, unsigned int nr_iowaiters)
	return bucket + 5;
}

/*
 * Return a multiplier for the exit latency that is intended
 * to take performance requirements into account.
 * The more performance critical we estimate the system
 * to be, the higher this multiplier, and thus the higher
 * the barrier to go to an expensive C state.
 */
static inline int performance_multiplier(unsigned int nr_iowaiters)
{
	/* for IO wait tasks (per cpu!) we add 10x each */
	return 1 + 10 * nr_iowaiters;
}

static DEFINE_PER_CPU(struct menu_device, menu_devices);

static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
@@ -258,8 +211,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
	struct menu_device *data = this_cpu_ptr(&menu_devices);
	s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
	u64 predicted_ns;
	u64 interactivity_req;
	unsigned int nr_iowaiters;
	ktime_t delta, delta_tick;
	int i, idx;

@@ -268,8 +219,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
		data->needs_update = 0;
	}

	nr_iowaiters = nr_iowait_cpu(dev->cpu);

	/* Find the shortest expected idle interval. */
	predicted_ns = get_typical_interval(data) * NSEC_PER_USEC;
	if (predicted_ns > RESIDENCY_THRESHOLD_NS) {
@@ -283,7 +232,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
		}

		data->next_timer_ns = delta;
		data->bucket = which_bucket(data->next_timer_ns, nr_iowaiters);
		data->bucket = which_bucket(data->next_timer_ns);

		/* Round up the result for half microseconds. */
		timer_us = div_u64((RESOLUTION * DECAY * NSEC_PER_USEC) / 2 +
@@ -301,7 +250,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
		 */
		data->next_timer_ns = KTIME_MAX;
		delta_tick = TICK_NSEC / 2;
		data->bucket = which_bucket(KTIME_MAX, nr_iowaiters);
		data->bucket = which_bucket(KTIME_MAX);
	}

	if (unlikely(drv->state_count <= 1 || latency_req == 0) ||
@@ -328,15 +277,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
		 */
		if (predicted_ns < TICK_NSEC)
			predicted_ns = data->next_timer_ns;
	} else {
		/*
		 * Use the performance multiplier and the user-configurable
		 * latency_req to determine the maximum exit latency.
		 */
		interactivity_req = div64_u64(predicted_ns,
					      performance_multiplier(nr_iowaiters));
		if (latency_req > interactivity_req)
			latency_req = interactivity_req;
	} else if (latency_req > predicted_ns) {
		latency_req = predicted_ns;
	}

	/*
Loading