From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F93313AD2A for ; Fri, 5 Jul 2024 11:43:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720179821; cv=none; b=GKJRJwGFHCUknSiCBOacvzGt0eizpKEtTu1iamTiExWaFSO05K7nMA47/jWadwKz0J4JheeV5GHpXNb6P9OIeBk1AAmo/mMY+IZmx8Rb571ut9qpgFH1MgJQ1Orc8XYRPK9ZkHRhdxBMHcPXZWpSi5UU+r9633rZafFd8MnE5wY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720179821; c=relaxed/simple; bh=ALy2XMjaRq21wUDXMRtgZdlIJWtg6V1U2dZ3tiwDfhE=; h=Message-ID:Date:MIME-Version:Subject:From:To:Cc:References: In-Reply-To:Content-Type; b=p6Orb+FwJIvHOsBZEyQephAwdVr7vD1y1okRRp7B0gFgRvxOmHAIe6PDFeU0Q1DCoktlfaACa6J4bSZJl4r2wgpfiMfJ1qKJ2HyR3twBWh2PZYzRi5x80JzsHGWxIn9RCntyc2yKPqcEOGojeOMbNwG264l/0g6t2xkY9KPdZSw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Fs2AqiKz; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Fs2AqiKz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720179817; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LM8oqhXjYeJdADlUxmauvnDgdtlNfhUy139keHdjAaM=; b=Fs2AqiKzVAxBmojQ7Af5Fo3FWKOBUjUIPVtS51NrRR4D8BTGiM6Ipu/yiBx1BkXnLPZ+em UwBnBLBGk+AxgO5N9RvVxS14Nm1St8/qhhuPgrjHcr8tQGRiaK8ITW9JQnoRyEuB3Zv3Yu FECj73G0UZFmP5WEUPohJPLx7lgBIXk= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-307-nSufknHKPA6IUBPzH-jQKg-1; Fri, 05 Jul 2024 07:43:36 -0400 X-MC-Unique: nSufknHKPA6IUBPzH-jQKg-1 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-425657ac234so11526505e9.1 for ; Fri, 05 Jul 2024 04:43:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720179815; x=1720784615; h=content-transfer-encoding:in-reply-to:organization:content-language :references:cc:to:from:subject:user-agent:mime-version:date :message-id:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=LM8oqhXjYeJdADlUxmauvnDgdtlNfhUy139keHdjAaM=; b=IsTTzyfrNTrb7R1iJSJdJoC4gVhTUjJD8Tq8dTgMTGV7KAmH7fvkh5Q40bRMJ4JAPk +jm8lJeYep7OtyX5e8K74QDe9vdxQJcpONqf1vgEsdG6rC1NqD4o4Q/jD3VqfxzZh8u2 4cKef/R4Fx0WXbNoy1NQIELKbC3/D+eAdBnzkms9wJY1RfmHyDMf+QzULY2j53I2+FPh QgyKl2qz0/tCb+bxmbKZP9j5ppA7fXq0KIO2Qz/UtaYhP120T8P7BfNoZA8R72yAX0Bh qKZzz3QcOjbmBbPFBLBybm8Tridqw3VBVvFlM4GnZ+zIZTck6GjG0n6dQo6pCUO5K/IQ dM9Q== X-Forwarded-Encrypted: i=1; AJvYcCUmbHSqxL9lSxRPwtL3F5JQs1CZHiq2uawYuovvO4G5yi9QxSLj6yQUyvhzYV3165v8vMQITuPm13lEUS51u5soEVeiIx28vGwEp020zCo= X-Gm-Message-State: AOJu0YxhkNQRR9MLSB+rzb4yfxikSQCcVXpIK1N5JB/2WTLw8CPVlbAt ovzmbXVIcgnX8UabnffamqYO7J7qvhgIu0dP/wDP/KGLY1lsqmaofPqAa9EvZ4ZjRYxQZpwDew1 3F1uNBIoskGl+plu1Mo3LmafuRs1+mn770Oq73LqWCybFuOszM4Mpiyf9W7zX22zZ X-Received: by 2002:a05:600c:4da2:b0:425:7a6b:4e97 with SMTP id 5b1f17b1804b1-4264a3d77admr31802385e9.7.1720179815379; Fri, 05 Jul 2024 04:43:35 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFKehtmjullDi9uAwYSRg74UxYSGZFTEHcu/fG9tLT7dv039fl2Js67daeRwkEXdaqF/sz5QA== X-Received: by 2002:a05:600c:4da2:b0:425:7a6b:4e97 with SMTP id 5b1f17b1804b1-4264a3d77admr31802185e9.7.1720179814765; Fri, 05 Jul 2024 04:43:34 -0700 (PDT) Received: from ?IPV6:2a02:810d:4b3f:ee94:abf:b8ff:feee:998b? ([2a02:810d:4b3f:ee94:abf:b8ff:feee:998b]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3679ac6d60dsm4168526f8f.39.2024.07.05.04.43.33 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 05 Jul 2024 04:43:34 -0700 (PDT) Message-ID: <1d0871c4-3613-492e-8f2f-3ea1b0377849@redhat.com> Date: Fri, 5 Jul 2024 13:43:32 +0200 Precedence: bulk X-Mailing-List: rust-for-linux@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [RFC PATCH V3 6/8] rust: Extend cpufreq bindings for driver registration From: Danilo Krummrich To: Viresh Kumar , "Rafael J. Wysocki" , Miguel Ojeda , Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?UTF-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl Cc: linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?Q?Alex_Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org References: <0f8618610dde586284d8c9971b8bdf215eef0456.1719990273.git.viresh.kumar@linaro.org> Organization: RedHat In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit On 7/5/24 13:39, Danilo Krummrich wrote: > On 7/3/24 09:14, Viresh Kumar wrote: >> This extends the cpufreq bindings with bindings for registering a >> driver. >> >> Signed-off-by: Viresh Kumar >> --- >>   rust/kernel/cpufreq.rs | 482 ++++++++++++++++++++++++++++++++++++++++- >>   1 file changed, 479 insertions(+), 3 deletions(-) >> >> diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs >> index 6f9d34ebbcb0..66dad18f4ab6 100644 >> --- a/rust/kernel/cpufreq.rs >> +++ b/rust/kernel/cpufreq.rs >> @@ -9,14 +9,16 @@ >>   use crate::{ >>       bindings, clk, cpumask, >>       device::Device, >> -    error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR}, >> +    error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR}, >>       prelude::*, >> -    types::{ARef, ForeignOwnable}, >> +    types::ForeignOwnable, >>   }; >>   use core::{ >> +    cell::UnsafeCell, >> +    marker::PhantomData, >>       pin::Pin, >> -    ptr::self, >> +    ptr::{self, addr_of_mut}, >>   }; >>   use macros::vtable; >> @@ -563,3 +565,477 @@ fn register_em(_policy: &mut Policy) { >>           kernel::build_error(VTABLE_DEFAULT_ERROR) >>       } >>   } >> + >> +/// Registration of a cpufreq driver. >> +pub struct Registration { >> +    registered: bool, >> +    drv: UnsafeCell, >> +    _p: PhantomData, >> +} >> + >> +// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads >> +// or CPUs, so it is safe to share it. >> +unsafe impl Sync for Registration {} >> + >> +// SAFETY: Registration with and unregistration from the cpufreq subsystem can happen from any thread. >> +// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is okay to move >> +// `Registration` to different threads. >> +#[allow(clippy::non_send_fields_in_send_ty)] >> +unsafe impl Send for Registration {} >> + >> +impl Registration { >> +    /// Creates new [`Registration`] but does not register it yet. >> +    /// >> +    /// It is allowed to move. >> +    fn new() -> Result> { >> +        Ok(Box::new( >> +            Self { >> +                registered: false, >> +                drv: UnsafeCell::new(bindings::cpufreq_driver::default()), >> +                _p: PhantomData, >> +            }, >> +            GFP_KERNEL, >> +        )?) >> +    } >> + >> +    /// Registers a cpufreq driver with the rest of the kernel. >> +    pub fn register( >> +        name: &'static CStr, >> +        data: T::Data, >> +        flags: u16, >> +        boost: bool, >> +    ) -> Result> { > > If you directly call `register` from `new` you can avoid having `Self::registered`. > It's also a bit cleaner, once you got an instance of `Registration` it means something > is registered, once it's dropped, it's unregistered. Nevermind, I didn't notice `new` is private and you actually already do that. However, this means you can drop `Self::registered`. > >> +        let mut reg = Self::new()?; >> +        let drv = reg.drv.get_mut(); >> + >> +        // Account for the trailing null character. >> +        let len = name.len() + 1; >> +        if len > drv.name.len() { >> +            return Err(EINVAL); >> +        }; >> + >> +        // SAFETY: `name` is a valid Cstr, and we are copying it to an array of equal or larger >> +        // size. >> +        let name = unsafe { &*(name.as_bytes_with_nul() as *const [u8] as *const [i8]) }; >> +        drv.name[..len].copy_from_slice(name); >> + >> +        drv.boost_enabled = boost; >> +        drv.flags = flags; >> + >> +        // Allocate an array of 3 pointers to be passed to the C code. >> +        let mut attr = Box::new([ptr::null_mut(); 3], GFP_KERNEL)?; >> +        let mut next = 0; >> + >> +        // SAFETY: The C code returns a valid pointer here, which is again passed to the C code in >> +        // an array. >> +        attr[next] = >> +            unsafe { addr_of_mut!(bindings::cpufreq_freq_attr_scaling_available_freqs) as *mut _ }; >> +        next += 1; >> + >> +        if boost { >> +            // SAFETY: The C code returns a valid pointer here, which is again passed to the C code >> +            // in an array. >> +            attr[next] = >> +                unsafe { addr_of_mut!(bindings::cpufreq_freq_attr_scaling_boost_freqs) as *mut _ }; >> +            next += 1; >> +        } >> +        attr[next] = ptr::null_mut(); >> + >> +        // Pass the ownership of the memory block to the C code. This will be freed when >> +        // the [`Registration`] object goes out of scope. >> +        drv.attr = Box::leak(attr) as *mut _; >> + >> +        // Initialize mandatory callbacks. >> +        drv.init = Some(Self::init_callback); >> +        drv.verify = Some(Self::verify_callback); >> + >> +        // Initialize optional callbacks. >> +        drv.setpolicy = if T::HAS_SETPOLICY { >> +            Some(Self::setpolicy_callback) >> +        } else { >> +            None >> +        }; >> +        drv.target = if T::HAS_TARGET { >> +            Some(Self::target_callback) >> +        } else { >> +            None >> +        }; >> +        drv.target_index = if T::HAS_TARGET_INDEX { >> +            Some(Self::target_index_callback) >> +        } else { >> +            None >> +        }; >> +        drv.fast_switch = if T::HAS_FAST_SWITCH { >> +            Some(Self::fast_switch_callback) >> +        } else { >> +            None >> +        }; >> +        drv.adjust_perf = if T::HAS_ADJUST_PERF { >> +            Some(Self::adjust_perf_callback) >> +        } else { >> +            None >> +        }; >> +        drv.get_intermediate = if T::HAS_GET_INTERMEDIATE { >> +            Some(Self::get_intermediate_callback) >> +        } else { >> +            None >> +        }; >> +        drv.target_intermediate = if T::HAS_TARGET_INTERMEDIATE { >> +            Some(Self::target_intermediate_callback) >> +        } else { >> +            None >> +        }; >> +        drv.get = if T::HAS_GET { >> +            Some(Self::get_callback) >> +        } else { >> +            None >> +        }; >> +        drv.update_limits = if T::HAS_UPDATE_LIMITS { >> +            Some(Self::update_limits_callback) >> +        } else { >> +            None >> +        }; >> +        drv.bios_limit = if T::HAS_BIOS_LIMIT { >> +            Some(Self::bios_limit_callback) >> +        } else { >> +            None >> +        }; >> +        drv.online = if T::HAS_ONLINE { >> +            Some(Self::online_callback) >> +        } else { >> +            None >> +        }; >> +        drv.offline = if T::HAS_OFFLINE { >> +            Some(Self::offline_callback) >> +        } else { >> +            None >> +        }; >> +        drv.exit = if T::HAS_EXIT { >> +            Some(Self::exit_callback) >> +        } else { >> +            None >> +        }; >> +        drv.suspend = if T::HAS_SUSPEND { >> +            Some(Self::suspend_callback) >> +        } else { >> +            None >> +        }; >> +        drv.resume = if T::HAS_RESUME { >> +            Some(Self::resume_callback) >> +        } else { >> +            None >> +        }; >> +        drv.ready = if T::HAS_READY { >> +            Some(Self::ready_callback) >> +        } else { >> +            None >> +        }; >> +        drv.set_boost = if T::HAS_SET_BOOST { >> +            Some(Self::set_boost_callback) >> +        } else { >> +            None >> +        }; >> +        drv.register_em = if T::HAS_REGISTER_EM { >> +            Some(Self::register_em_callback) >> +        } else { >> +            None >> +        }; >> + >> +        // Set driver data before registering the driver, as the cpufreq core may call few >> +        // callbacks before `cpufreq_register_driver()` returns. >> +        reg.set_data(data)?; >> + >> +        // SAFETY: It is safe to register the driver with the cpufreq core in the C code. >> +        to_result(unsafe { bindings::cpufreq_register_driver(reg.drv.get()) })?; >> +        reg.registered = true; >> +        Ok(reg) >> +    } >> + >> +    /// Returns the previous set data for a cpufreq driver. >> +    pub fn data() -> Option<::Borrowed<'static>> { >> +        // SAFETY: The driver data is earlier set by us from [`set_data()`]. >> +        let data = unsafe { bindings::cpufreq_get_driver_data() }; >> +        if data.is_null() { >> +            None >> +        } else { >> +            // SAFETY: The driver data is earlier set by us from [`set_data()`]. >> +            Some(unsafe { D::borrow(data) }) >> +        } >> +    } >> + >> +    // Sets the data for a cpufreq driver. >> +    fn set_data(&mut self, data: T::Data) -> Result<()> { >> +        let drv = self.drv.get_mut(); >> + >> +        if drv.driver_data.is_null() { >> +            // Pass the ownership of the data to the foreign interface. >> +            drv.driver_data = ::into_foreign(data) as _; >> +            Ok(()) >> +        } else { >> +            Err(EBUSY) >> +        } >> +    } >> + >> +    // Clears and returns the data for a cpufreq driver. >> +    fn clear_data(&mut self) -> Option { >> +        let drv = self.drv.get_mut(); >> + >> +        if drv.driver_data.is_null() { >> +            None >> +        } else { >> +            // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to >> +            // relinquish it now. >> +            let data = Some(unsafe { ::from_foreign(drv.driver_data) }); >> +            drv.driver_data = ptr::null_mut(); >> +            data >> +        } >> +    } >> +} >> + >> +// cpufreq driver callbacks. >> +impl Registration { >> +    // Policy's init callback. >> +    extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> + >> +            let data = T::init(&mut policy)?; >> +            policy.set_data(data)?; >> +            Ok(0) >> +        }) >> +    } >> + >> +    // Policy's exit callback. >> +    extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> + >> +            let data = policy.clear_data(); >> +            T::exit(&mut policy, data).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's online callback. >> +    extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::online(&mut policy).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's offline callback. >> +    extern "C" fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::offline(&mut policy).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's suspend callback. >> +    extern "C" fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::suspend(&mut policy).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's resume callback. >> +    extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::resume(&mut policy).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's ready callback. >> +    extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) { >> +        // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +        // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +        // `ptr`. >> +        let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +        T::ready(&mut policy); >> +    } >> + >> +    // Policy's verify callback. >> +    extern "C" fn verify_callback(ptr: *mut bindings::cpufreq_policy_data) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut data = unsafe { PolicyData::from_raw_policy_data(ptr) }; >> +            T::verify(&mut data).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's setpolicy callback. >> +    extern "C" fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::setpolicy(&mut policy).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's target callback. >> +    extern "C" fn target_callback( >> +        ptr: *mut bindings::cpufreq_policy, >> +        target_freq: u32, >> +        relation: u32, >> +    ) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::target(&mut policy, target_freq, Relation::new(relation)?).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's target_index callback. >> +    extern "C" fn target_index_callback( >> +        ptr: *mut bindings::cpufreq_policy, >> +        index: u32, >> +    ) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::target_index(&mut policy, index).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's fast_switch callback. >> +    extern "C" fn fast_switch_callback( >> +        ptr: *mut bindings::cpufreq_policy, >> +        target_freq: u32, >> +    ) -> core::ffi::c_uint { >> +        // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +        // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +        // `ptr`. >> +        let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +        T::fast_switch(&mut policy, target_freq) >> +    } >> + >> +    // Policy's adjust_perf callback. >> +    extern "C" fn adjust_perf_callback(cpu: u32, min_perf: u64, target_perf: u64, capacity: u64) { >> +        if let Ok(mut policy) = Policy::from_cpu(cpu) { >> +            T::adjust_perf(&mut policy, min_perf, target_perf, capacity); >> +        } >> +    } >> + >> +    // Policy's get_intermediate callback. >> +    extern "C" fn get_intermediate_callback( >> +        ptr: *mut bindings::cpufreq_policy, >> +        index: u32, >> +    ) -> core::ffi::c_uint { >> +        // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +        // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +        // `ptr`. >> +        let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +        T::get_intermediate(&mut policy, index) >> +    } >> + >> +    // Policy's target_intermediate callback. >> +    extern "C" fn target_intermediate_callback( >> +        ptr: *mut bindings::cpufreq_policy, >> +        index: u32, >> +    ) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::target_intermediate(&mut policy, index).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's get callback. >> +    extern "C" fn get_callback(cpu: u32) -> core::ffi::c_uint { >> +        // SAFETY: Get the policy for a CPU. >> +        Policy::from_cpu(cpu).map_or(0, |mut policy| T::get(&mut policy).map_or(0, |f| f)) >> +    } >> + >> +    // Policy's update_limit callback. >> +    extern "C" fn update_limits_callback(cpu: u32) { >> +        // SAFETY: Get the policy for a CPU. >> +        if let Ok(mut policy) = Policy::from_cpu(cpu) { >> +            T::update_limits(&mut policy); >> +        } >> +    } >> + >> +    // Policy's bios_limit callback. >> +    extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> core::ffi::c_int { >> +        from_result(|| { >> +            let mut policy = Policy::from_cpu(cpu as u32)?; >> + >> +            // SAFETY: The pointer is guaranteed by the C code to be valid. >> +            T::bios_limit(&mut policy, &mut (unsafe { *limit })).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's set_boost callback. >> +    extern "C" fn set_boost_callback( >> +        ptr: *mut bindings::cpufreq_policy, >> +        state: i32, >> +    ) -> core::ffi::c_int { >> +        from_result(|| { >> +            // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +            // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +            // `ptr`. >> +            let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +            T::set_boost(&mut policy, state).map(|_| 0) >> +        }) >> +    } >> + >> +    // Policy's register_em callback. >> +    extern "C" fn register_em_callback(ptr: *mut bindings::cpufreq_policy) { >> +        // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for the >> +        // duration of this call, so it is guaranteed to remain alive for the lifetime of >> +        // `ptr`. >> +        let mut policy = unsafe { Policy::from_raw_policy(ptr) }; >> +        T::register_em(&mut policy); >> +    } >> +} >> + >> +impl Drop for Registration { >> +    // Removes the registration from the kernel if it has completed successfully before. >> +    fn drop(&mut self) { >> +        pr_info!("Registration dropped\n"); >> +        let drv = self.drv.get_mut(); >> + >> +        if self.registered { >> +            // SAFETY: The driver was earlier registered from `register()`. >> +            unsafe { bindings::cpufreq_unregister_driver(drv) }; >> +        } >> + >> +        // Free the previously leaked memory to the C code. >> +        if !drv.attr.is_null() { >> +            // SAFETY: The pointer was earlier initialized from the result of `Box::leak`. >> +            unsafe { drop(Box::from_raw(drv.attr)) }; >> +        } >> + >> +        // Free data >> +        drop(self.clear_data()); >> +    } >> +}