drivers/cpuidle/cpuidle-riscv-sbi.c

Source file repositories/reference/linux-study-clean/drivers/cpuidle/cpuidle-riscv-sbi.c

File Facts

System
Linux kernel
Corpus path
drivers/cpuidle/cpuidle-riscv-sbi.c
Extension
.c
Size
13251 bytes
Lines
580
Domain
Driver Families
Bucket
drivers/cpuidle
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 sbi_cpuidle_data {
	u32 *states;
	struct device *dev;
};

struct sbi_domain_state {
	bool available;
	u32 state;
};

static DEFINE_PER_CPU_READ_MOSTLY(struct sbi_cpuidle_data, sbi_cpuidle_data);
static DEFINE_PER_CPU(struct sbi_domain_state, domain_state);
static bool sbi_cpuidle_use_osi;
static bool sbi_cpuidle_use_cpuhp;

static inline void sbi_set_domain_state(u32 state)
{
	struct sbi_domain_state *data = this_cpu_ptr(&domain_state);

	data->available = true;
	data->state = state;
}

static inline u32 sbi_get_domain_state(void)
{
	struct sbi_domain_state *data = this_cpu_ptr(&domain_state);

	return data->state;
}

static inline void sbi_clear_domain_state(void)
{
	struct sbi_domain_state *data = this_cpu_ptr(&domain_state);

	data->available = false;
}

static inline bool sbi_is_domain_state_available(void)
{
	struct sbi_domain_state *data = this_cpu_ptr(&domain_state);

	return data->available;
}

static __cpuidle int sbi_cpuidle_enter_state(struct cpuidle_device *dev,
					     struct cpuidle_driver *drv, int idx)
{
	u32 *states = __this_cpu_read(sbi_cpuidle_data.states);
	u32 state = states[idx];

	if (state & SBI_HSM_SUSP_NON_RET_BIT)
		return CPU_PM_CPU_IDLE_ENTER_PARAM(riscv_sbi_hart_suspend, idx, state);
	else
		return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(riscv_sbi_hart_suspend,
							     idx, state);
}

static __cpuidle int __sbi_enter_domain_idle_state(struct cpuidle_device *dev,
						   struct cpuidle_driver *drv, int idx,
						   bool s2idle)
{
	struct sbi_cpuidle_data *data = this_cpu_ptr(&sbi_cpuidle_data);
	u32 *states = data->states;
	struct device *pd_dev = data->dev;
	u32 state;
	int ret;

	ret = cpu_pm_enter();
	if (ret)
		return -1;

	/* Do runtime PM to manage a hierarchical CPU toplogy. */
	if (s2idle)
		dev_pm_genpd_suspend(pd_dev);
	else
		pm_runtime_put_sync_suspend(pd_dev);

	ct_cpuidle_enter();

	if (sbi_is_domain_state_available())
		state = sbi_get_domain_state();
	else
		state = states[idx];

	ret = riscv_sbi_hart_suspend(state) ? -1 : idx;

	ct_cpuidle_exit();

	if (s2idle)
		dev_pm_genpd_resume(pd_dev);

Annotation

Implementation Notes