drivers/cpufreq/loongson3_cpufreq.c

Source file repositories/reference/linux-study-clean/drivers/cpufreq/loongson3_cpufreq.c

File Facts

System
Linux kernel
Corpus path
drivers/cpufreq/loongson3_cpufreq.c
Extension
.c
Size
8815 bytes
Lines
390
Domain
Driver Families
Bucket
drivers/cpufreq
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 loongson3_freq_data {
	unsigned int def_freq_level;
	struct cpufreq_frequency_table table[];
};

static struct mutex cpufreq_mutex[MAX_PACKAGES];
static struct cpufreq_driver loongson3_cpufreq_driver;
static DEFINE_PER_CPU(struct loongson3_freq_data *, freq_data);

static inline int do_service_request(u32 id, u32 info, u32 cmd, u32 val, u32 extra)
{
	int retries;
	unsigned int cpu = raw_smp_processor_id();
	unsigned int package = cpu_data[cpu].package;
	union smc_message msg, last;

	mutex_lock(&cpufreq_mutex[package]);

	last.value = iocsr_read32(LOONGARCH_IOCSR_SMCMBX);
	if (!last.complete) {
		mutex_unlock(&cpufreq_mutex[package]);
		return -EPERM;
	}

	msg.id		= id;
	msg.info	= info;
	msg.cmd		= cmd;
	msg.val		= val;
	msg.extra	= extra;
	msg.complete	= 0;

	iocsr_write32(msg.value, LOONGARCH_IOCSR_SMCMBX);
	iocsr_write32(iocsr_read32(LOONGARCH_IOCSR_MISC_FUNC) | IOCSR_MISC_FUNC_SOFT_INT,
		      LOONGARCH_IOCSR_MISC_FUNC);

	for (retries = 0; retries < 10000; retries++) {
		msg.value = iocsr_read32(LOONGARCH_IOCSR_SMCMBX);
		if (msg.complete)
			break;

		usleep_range(8, 12);
	}

	if (!msg.complete || msg.cmd != CMD_OK) {
		mutex_unlock(&cpufreq_mutex[package]);
		return -EPERM;
	}

	mutex_unlock(&cpufreq_mutex[package]);

	return msg.val;
}

static unsigned int loongson3_cpufreq_get(unsigned int cpu)
{
	int ret;

	ret = do_service_request(cpu, FREQ_INFO_TYPE_FREQ, CMD_GET_FREQ_INFO, 0, 0);

	return ret * KILO;
}

static int loongson3_cpufreq_target(struct cpufreq_policy *policy, unsigned int index)
{
	int ret;

	ret = do_service_request(cpu_data[policy->cpu].core,
				 FREQ_INFO_TYPE_LEVEL, CMD_SET_FREQ_INFO, index, 0);

	return (ret >= 0) ? 0 : ret;
}

static int configure_freq_table(int cpu)
{
	int i, ret, boost_level, max_level, freq_level;
	struct platform_device *pdev = cpufreq_get_driver_data();
	struct loongson3_freq_data *data;

	if (per_cpu(freq_data, cpu))
		return 0;

	ret = do_service_request(cpu, 0, CMD_GET_FREQ_LEVEL_NUM, 0, 0);
	if (ret < 0)
		return ret;
	max_level = ret;

	ret = do_service_request(cpu, 0, CMD_GET_FREQ_BOOST_LEVEL, 0, 0);
	if (ret < 0)
		return ret;
	boost_level = ret;

Annotation

Implementation Notes