drivers/cpufreq/rcpufreq_dt.rs

Source file repositories/reference/linux-study-clean/drivers/cpufreq/rcpufreq_dt.rs

File Facts

System
Linux kernel
Corpus path
drivers/cpufreq/rcpufreq_dt.rs
Extension
.rs
Size
6943 bytes
Lines
223
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 CPUFreqDTDevice {
    opp_table: opp::Table,
    freq_table: opp::FreqTable,
    _mask: CpumaskVar,
    _token: Option<opp::ConfigToken>,
    _clk: Clk,
}

#[derive(Default)]
struct CPUFreqDTDriver;

#[vtable]
impl opp::ConfigOps for CPUFreqDTDriver {}

#[vtable]
impl cpufreq::Driver for CPUFreqDTDriver {
    const NAME: &'static CStr = c"cpufreq-dt";
    const FLAGS: u16 = cpufreq::flags::NEED_INITIAL_FREQ_CHECK | cpufreq::flags::IS_COOLING_DEV;
    const BOOST_ENABLED: bool = true;

    type PData = Arc<CPUFreqDTDevice>;

    fn init(policy: &mut cpufreq::Policy) -> Result<Self::PData> {
        let cpu = policy.cpu();
        // SAFETY: The CPU device is only used during init; it won't get hot-unplugged. The cpufreq
        // core  registers with CPU notifiers and the cpufreq core/driver won't use the CPU device,
        // once the CPU is hot-unplugged.
        let dev = unsafe { cpu::from_cpu(cpu)? };
        let mut mask = CpumaskVar::new_zero(GFP_KERNEL)?;

        mask.set(cpu);

        let token = find_supply_names(dev, cpu)
            .map(|names| {
                opp::Config::<Self>::new()
                    .set_regulator_names(names)?
                    .set(dev)
            })
            .transpose()?;

        // Get OPP-sharing information from "operating-points-v2" bindings.
        let fallback = match opp::Table::of_sharing_cpus(dev, &mut mask) {
            Ok(()) => false,
            Err(e) if e == ENOENT => {
                // "operating-points-v2" not supported. If the platform hasn't
                // set sharing CPUs, fallback to all CPUs share the `Policy`
                // for backward compatibility.
                opp::Table::sharing_cpus(dev, &mut mask).is_err()
            }
            Err(e) => return Err(e),
        };

        // Initialize OPP tables for all policy cpus.
        //
        // For platforms not using "operating-points-v2" bindings, we do this
        // before updating policy cpus. Otherwise, we will end up creating
        // duplicate OPPs for the CPUs.
        //
        // OPPs might be populated at runtime, don't fail for error here unless
        // it is -EPROBE_DEFER.
        let mut opp_table = match opp::Table::from_of_cpumask(dev, &mut mask) {
            Ok(table) => table,
            Err(e) => {
                if e == EPROBE_DEFER {
                    return Err(e);
                }

                // The table is added dynamically ?
                opp::Table::from_dev(dev)?
            }
        };

        // The OPP table must be initialized, statically or dynamically, by this point.
        opp_table.opp_count()?;

        // Set sharing cpus for fallback scenario.
        if fallback {
            mask.setall();
            opp_table.set_sharing_cpus(&mut mask)?;
        }

        let mut transition_latency = opp_table.max_transition_latency_ns() as u32;
        if transition_latency == 0 {
            transition_latency = cpufreq::DEFAULT_TRANSITION_LATENCY_NS;
        }

        policy
            .set_dvfs_possible_from_any_cpu(true)
            .set_suspend_freq(opp_table.suspend_freq())
            .set_transition_latency_ns(transition_latency);

Annotation

Implementation Notes