drivers/firmware/arm_scmi/scmi_power_control.c

Source file repositories/reference/linux-study-clean/drivers/firmware/arm_scmi/scmi_power_control.c

File Facts

System
Linux kernel
Corpus path
drivers/firmware/arm_scmi/scmi_power_control.c
Extension
.c
Size
12141 bytes
Lines
394
Domain
Driver Families
Bucket
drivers/firmware
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct scmi_syspower_conf {
	struct device *dev;
	enum scmi_syspower_state state;
	/* Protect access to state */
	struct mutex state_mtx;
	enum scmi_system_events required_transition;

	struct notifier_block userspace_nb;
	struct notifier_block reboot_nb;

	struct delayed_work forceful_work;
	struct work_struct suspend_work;
};

#define userspace_nb_to_sconf(x)	\
	container_of(x, struct scmi_syspower_conf, userspace_nb)

#define reboot_nb_to_sconf(x)		\
	container_of(x, struct scmi_syspower_conf, reboot_nb)

#define dwork_to_sconf(x)		\
	container_of(x, struct scmi_syspower_conf, forceful_work)

/**
 * scmi_reboot_notifier  - A reboot notifier to catch an ongoing successful
 * system transition
 * @nb: Reference to the related notifier block
 * @reason: The reason for the ongoing reboot
 * @__unused: The cmd being executed on a restart request (unused)
 *
 * When an ongoing system transition is detected, compatible with the one
 * requested by SCMI, cancel the delayed work.
 *
 * Return: NOTIFY_OK in any case
 */
static int scmi_reboot_notifier(struct notifier_block *nb,
				unsigned long reason, void *__unused)
{
	struct scmi_syspower_conf *sc = reboot_nb_to_sconf(nb);

	mutex_lock(&sc->state_mtx);
	switch (reason) {
	case SYS_HALT:
	case SYS_POWER_OFF:
		if (sc->required_transition == SCMI_SYSTEM_SHUTDOWN)
			sc->state = SCMI_SYSPOWER_REBOOTING;
		break;
	case SYS_RESTART:
		if (sc->required_transition == SCMI_SYSTEM_COLDRESET ||
		    sc->required_transition == SCMI_SYSTEM_WARMRESET)
			sc->state = SCMI_SYSPOWER_REBOOTING;
		break;
	default:
		break;
	}

	if (sc->state == SCMI_SYSPOWER_REBOOTING) {
		dev_dbg(sc->dev, "Reboot in progress...cancel delayed work.\n");
		cancel_delayed_work_sync(&sc->forceful_work);
	}
	mutex_unlock(&sc->state_mtx);

	return NOTIFY_OK;
}

/**
 * scmi_request_forceful_transition  - Request forceful SystemPower transition
 * @sc: A reference to the configuration data
 *
 * Initiates the required SystemPower transition without involving userspace:
 * just trigger the action at the kernel level after issuing an emergency
 * sync. (if possible at all)
 */
static inline void
scmi_request_forceful_transition(struct scmi_syspower_conf *sc)
{
	dev_dbg(sc->dev, "Serving forceful request:%d\n",
		sc->required_transition);

#ifndef MODULE
	emergency_sync();
#endif
	switch (sc->required_transition) {
	case SCMI_SYSTEM_SHUTDOWN:
		kernel_power_off();
		break;
	case SCMI_SYSTEM_COLDRESET:
	case SCMI_SYSTEM_WARMRESET:
		kernel_restart(NULL);
		break;

Annotation

Implementation Notes