Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

Merge branches 'pm-sleep' and 'pm-runtime'

* pm-sleep:
  PM / sleep: trace_device_pm_callback coverage in dpm_prepare/complete
  PM / wakeup: add a dummy wakeup_source to record statistics
  PM / sleep: Make suspend-to-idle-specific code depend on CONFIG_SUSPEND
  PM / sleep: Return -EBUSY from suspend_enter() on wakeup detection
  PM / tick: Add tracepoints for suspend-to-idle diagnostics
  PM / sleep: Fix symbol name in a comment in kernel/power/main.c
  leds / PM: fix hibernation on arm when gpio-led used with CPU led trigger
  ARM: omap-device: use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS
  bus: omap_l3_noc: add missed callbacks for suspend-to-disk
  PM / sleep: Add macro to define common noirq system PM callbacks
  PM / sleep: Refine diagnostic messages in enter_state()
  PM / wakeup: validate wakeup source before activating it.

* pm-runtime:
  PM / Runtime: Update last_busy in rpm_resume
  PM / runtime: add note about re-calling in during device probe()
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -556,6 +556,12 @@ helper functions described in Section 4. In that case, pm_runtime_resume()
should be used.  Of course, for this purpose the device's runtime PM has to be
enabled earlier by calling pm_runtime_enable().

Note, if the device may execute pm_runtime calls during the probe (such as
if it is registers with a subsystem that may call back in) then the
pm_runtime_get_sync() call paired with a pm_runtime_put() call will be
appropriate to ensure that the device is not put back to sleep during the
probe. This can happen with systems such as the network device layer.

It may be desirable to suspend the device once ->probe() has finished.
Therefore the driver core uses the asyncronous pm_request_idle() to submit a
request to execute the subsystem-level idle callback for the device at that
+2 −5
Original line number Diff line number Diff line
@@ -688,11 +688,8 @@ struct dev_pm_domain omap_device_pm_domain = {
		SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
				   NULL)
		USE_PLATFORM_PM_SLEEP_OPS
		.suspend_noirq = _od_suspend_noirq,
		.resume_noirq = _od_resume_noirq,
		.freeze_noirq = _od_suspend_noirq,
		.thaw_noirq = _od_resume_noirq,
		.restore_noirq = _od_resume_noirq,
		SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(_od_suspend_noirq,
					      _od_resume_noirq)
	}
};

+5 −6
Original line number Diff line number Diff line
@@ -920,9 +920,7 @@ static void device_complete(struct device *dev, pm_message_t state)

	if (callback) {
		pm_dev_dbg(dev, state, info);
		trace_device_pm_callback_start(dev, info, state.event);
		callback(dev);
		trace_device_pm_callback_end(dev, 0);
	}

	device_unlock(dev);
@@ -954,7 +952,9 @@ void dpm_complete(pm_message_t state)
		list_move(&dev->power.entry, &list);
		mutex_unlock(&dpm_list_mtx);

		trace_device_pm_callback_start(dev, "", state.event);
		device_complete(dev, state);
		trace_device_pm_callback_end(dev, 0);

		mutex_lock(&dpm_list_mtx);
		put_device(dev);
@@ -1585,11 +1585,8 @@ static int device_prepare(struct device *dev, pm_message_t state)
		callback = dev->driver->pm->prepare;
	}

	if (callback) {
		trace_device_pm_callback_start(dev, info, state.event);
	if (callback)
		ret = callback(dev);
		trace_device_pm_callback_end(dev, ret);
	}

	device_unlock(dev);

@@ -1631,7 +1628,9 @@ int dpm_prepare(pm_message_t state)
		get_device(dev);
		mutex_unlock(&dpm_list_mtx);

		trace_device_pm_callback_start(dev, "", state.event);
		error = device_prepare(dev, state);
		trace_device_pm_callback_end(dev, error);

		mutex_lock(&dpm_list_mtx);
		if (error) {
+1 −0
Original line number Diff line number Diff line
@@ -741,6 +741,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
	} else {
 no_callback:
		__update_runtime_status(dev, RPM_ACTIVE);
		pm_runtime_mark_last_busy(dev);
		if (parent)
			atomic_inc(&parent->power.child_count);
	}
+54 −0
Original line number Diff line number Diff line
@@ -56,6 +56,11 @@ static LIST_HEAD(wakeup_sources);

static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);

static struct wakeup_source deleted_ws = {
	.name = "deleted",
	.lock =  __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
};

/**
 * wakeup_source_prepare - Prepare a new wakeup source for initialization.
 * @ws: Wakeup source to prepare.
@@ -107,6 +112,34 @@ void wakeup_source_drop(struct wakeup_source *ws)
}
EXPORT_SYMBOL_GPL(wakeup_source_drop);

/*
 * Record wakeup_source statistics being deleted into a dummy wakeup_source.
 */
static void wakeup_source_record(struct wakeup_source *ws)
{
	unsigned long flags;

	spin_lock_irqsave(&deleted_ws.lock, flags);

	if (ws->event_count) {
		deleted_ws.total_time =
			ktime_add(deleted_ws.total_time, ws->total_time);
		deleted_ws.prevent_sleep_time =
			ktime_add(deleted_ws.prevent_sleep_time,
				  ws->prevent_sleep_time);
		deleted_ws.max_time =
			ktime_compare(deleted_ws.max_time, ws->max_time) > 0 ?
				deleted_ws.max_time : ws->max_time;
		deleted_ws.event_count += ws->event_count;
		deleted_ws.active_count += ws->active_count;
		deleted_ws.relax_count += ws->relax_count;
		deleted_ws.expire_count += ws->expire_count;
		deleted_ws.wakeup_count += ws->wakeup_count;
	}

	spin_unlock_irqrestore(&deleted_ws.lock, flags);
}

/**
 * wakeup_source_destroy - Destroy a struct wakeup_source object.
 * @ws: Wakeup source to destroy.
@@ -119,6 +152,7 @@ void wakeup_source_destroy(struct wakeup_source *ws)
		return;

	wakeup_source_drop(ws);
	wakeup_source_record(ws);
	kfree(ws->name);
	kfree(ws);
}
@@ -351,6 +385,20 @@ int device_set_wakeup_enable(struct device *dev, bool enable)
}
EXPORT_SYMBOL_GPL(device_set_wakeup_enable);

/**
 * wakeup_source_not_registered - validate the given wakeup source.
 * @ws: Wakeup source to be validated.
 */
static bool wakeup_source_not_registered(struct wakeup_source *ws)
{
	/*
	 * Use timer struct to check if the given source is initialized
	 * by wakeup_source_add.
	 */
	return ws->timer.function != pm_wakeup_timer_fn ||
		   ws->timer.data != (unsigned long)ws;
}

/*
 * The functions below use the observation that each wakeup event starts a
 * period in which the system should not be suspended.  The moment this period
@@ -391,6 +439,10 @@ static void wakeup_source_activate(struct wakeup_source *ws)
{
	unsigned int cec;

	if (WARN_ONCE(wakeup_source_not_registered(ws),
			"unregistered wakeup source\n"))
		return;

	/*
	 * active wakeup source should bring the system
	 * out of PM_SUSPEND_FREEZE state
@@ -894,6 +946,8 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
		print_wakeup_source_stats(m, ws);
	rcu_read_unlock();

	print_wakeup_source_stats(m, &deleted_ws);

	return 0;
}

Loading