From patchwork Thu Aug 15 08:29:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre Gondois X-Patchwork-Id: 819660 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 62F9B19D09E; Thu, 15 Aug 2024 08:29:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710600; cv=none; b=Z6PIW3Y1pW+sxYqWgBvOoI/lYMGqPJe3hfQy/AVML/YH09+RuJcx/K5cwClfQX7TdG6Q1vdtQ84uQ1nqAzX+tl5y+eQBRIAY++jaUPfuqSLa1szQWxnxRwTKkswt7Wmb2/ZiroOlGJqYuWmZLJDLN0M7/INQwUYVOV7Zk4xu5ys= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710600; c=relaxed/simple; bh=jwyni+JvZIOku6vVjMN4zUjW3UUzN984UojAWvc/JYc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=qI/OqC3hI/gVHcVox12CpdGRHzOEZWKsmrNCPZpyuoq4ra2bZxQ0aZHAar+R2Dv3stJeGAq/Mj6oxk4hp/tvmEgkg3gCdC0rwPTj/dw0RFIi7X96VXChVyWo/Dz99hN33xf+AHWZ6uN9KUs9/UXETKPJVCLec4ECXfgsdV14+B4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id DBF9616A3; Thu, 15 Aug 2024 01:30:22 -0700 (PDT) Received: from e126645.nice.arm.com (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 8416F3F6A8; Thu, 15 Aug 2024 01:29:51 -0700 (PDT) From: Pierre Gondois To: linux-kernel@vger.kernel.org Cc: Pierre Gondois , "Rafael J. Wysocki" , Len Brown , Viresh Kumar , Robert Moore , 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 , Martin Rodriguez Reboredo , FUJITA Tomonori , Mika Westerberg , Manos Pitsidianakis , Thomas Bertschinger , Danilo Krummrich , linux-acpi@vger.kernel.org, linux-pm@vger.kernel.org, acpica-devel@lists.linux.dev, rust-for-linux@vger.kernel.org Subject: [RFC PATCH 1/6] ACPI: CPPC: Move struct cppc_cpudata to cppc_cpufreq driver Date: Thu, 15 Aug 2024 10:29:05 +0200 Message-Id: <20240815082916.1210110-2-pierre.gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240815082916.1210110-1-pierre.gondois@arm.com> References: <20240815082916.1210110-1-pierre.gondois@arm.com> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The `struct cppc_cpudata` is populated by the cppc_cpufreq driver. Outside of the driver's code, it is only used acpi_get_psd_map(). To facilitate a re-implementation of the cppc_cpufreq driver and its internal data structure in rust: - Move the structure definition to the driver's code - Udate acpi_get_psd_map() to take individual parameters instead Signed-off-by: Pierre Gondois --- drivers/acpi/cppc_acpi.c | 26 ++++++++++++++++---------- drivers/cpufreq/cppc_cpufreq.c | 13 ++++++++++++- include/acpi/cppc_acpi.h | 13 ++----------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 1d857978f5f4..b0fd141acb9d 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -468,17 +468,23 @@ EXPORT_SYMBOL_GPL(cppc_allow_fast_switch); /** * acpi_get_psd_map - Map the CPUs in the freq domain of a given cpu * @cpu: Find all CPUs that share a domain with cpu. - * @cpu_data: Pointer to CPU specific CPPC data including PSD info. + * @shared_cpu_map: cpumask to populate with CPUs belonging to the same _PSD + * domain. + * @shared_type: P-state coordination type for CPUs in the same _PSD as @cpu. * * Return: 0 for success or negative value for err. */ -int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data) +int acpi_get_psd_map(unsigned int cpu, cpumask_var_t shared_cpu_map, + unsigned int *shared_type) { struct cpc_desc *cpc_ptr, *match_cpc_ptr; struct acpi_psd_package *match_pdomain; struct acpi_psd_package *pdomain; int count_target, i; + if (!shared_cpu_map || !shared_type) + return -EINVAL; + /* * Now that we have _PSD data from all CPUs, let's setup P-state * domain info. @@ -488,18 +494,18 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data) return -EFAULT; pdomain = &(cpc_ptr->domain_info); - cpumask_set_cpu(cpu, cpu_data->shared_cpu_map); + cpumask_set_cpu(cpu, shared_cpu_map); if (pdomain->num_processors <= 1) return 0; /* Validate the Domain info */ count_target = pdomain->num_processors; if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL) - cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ALL; + *shared_type = CPUFREQ_SHARED_TYPE_ALL; else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) - cpu_data->shared_type = CPUFREQ_SHARED_TYPE_HW; + *shared_type = CPUFREQ_SHARED_TYPE_HW; else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) - cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY; + *shared_type = CPUFREQ_SHARED_TYPE_ANY; for_each_possible_cpu(i) { if (i == cpu) @@ -520,16 +526,16 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data) if (pdomain->coord_type != match_pdomain->coord_type) goto err_fault; - cpumask_set_cpu(i, cpu_data->shared_cpu_map); + cpumask_set_cpu(i, shared_cpu_map); } return 0; err_fault: /* Assume no coordination on any error parsing domain info */ - cpumask_clear(cpu_data->shared_cpu_map); - cpumask_set_cpu(cpu, cpu_data->shared_cpu_map); - cpu_data->shared_type = CPUFREQ_SHARED_TYPE_NONE; + cpumask_clear(shared_cpu_map); + cpumask_set_cpu(cpu, shared_cpu_map); + *shared_type = CPUFREQ_SHARED_TYPE_NONE; return -EFAULT; } diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 32780bb4e911..208d7b176fd0 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -26,6 +26,16 @@ #include +/* Per CPU container for runtime CPPC management. */ +struct cppc_cpudata { + struct list_head node; + struct cppc_perf_caps perf_caps; + struct cppc_perf_ctrls perf_ctrls; + struct cppc_perf_fb_ctrs perf_fb_ctrs; + unsigned int shared_type; + cpumask_var_t shared_cpu_map; +}; + /* * This list contains information parsed from per CPU ACPI _CPC and _PSD * structures: e.g. the highest and lowest supported performance, capabilities, @@ -572,7 +582,8 @@ static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu) if (!zalloc_cpumask_var(&cpu_data->shared_cpu_map, GFP_KERNEL)) goto free_cpu; - ret = acpi_get_psd_map(cpu, cpu_data); + ret = acpi_get_psd_map(cpu, cpu_data->shared_cpu_map, + &cpu_data->shared_type); if (ret) { pr_debug("Err parsing CPU%d PSD data: ret:%d\n", cpu, ret); goto free_mask; diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index 930b6afba6f4..5164aaca7eb0 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h @@ -126,16 +126,6 @@ struct cppc_perf_fb_ctrs { u64 wraparound_time; }; -/* Per CPU container for runtime CPPC management. */ -struct cppc_cpudata { - struct list_head node; - struct cppc_perf_caps perf_caps; - struct cppc_perf_ctrls perf_ctrls; - struct cppc_perf_fb_ctrs perf_fb_ctrs; - unsigned int shared_type; - cpumask_var_t shared_cpu_map; -}; - #ifdef CONFIG_ACPI_CPPC_LIB extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf); extern int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf); @@ -149,7 +139,8 @@ extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int p extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq); extern bool acpi_cpc_valid(void); extern bool cppc_allow_fast_switch(void); -extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data); +extern int acpi_get_psd_map(unsigned int cpu, cpumask_var_t shared_cpu_map, + unsigned int *shared_type); extern unsigned int cppc_get_transition_latency(int cpu); extern bool cpc_ffh_supported(void); extern bool cpc_supported_by_cpu(void); From patchwork Thu Aug 15 08:29:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre Gondois X-Patchwork-Id: 819975 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 74A2F47796; Thu, 15 Aug 2024 08:30:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710610; cv=none; b=qmXSiYKkBqAgYDa//G4Y7sX6bMOSTsbmtybYhJwnONa+PJc+2pSb4DxHQRWgQ2uvrJSwYN7rgT/RWfuKLbxk3d7TeOPN6GMia2UoNg8dVvgTybgXBhe4TmMquNF3CPecbM35HBwfpWtzIQmpkRTecXdGzHeiSK31WoKmOC6l3ss= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710610; c=relaxed/simple; bh=IK2m7aY43gBFQ3nrhXyqf1FDZA/bFXXuKuTGjetWlok=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rWX7e/lxrc8e36v62+LlQoPbH0IXrCu9iTKckIKg4lUWI46fZCKqKnpxTO1pFhVyBQ+S+hVMNCs9A7weUsi9BmGJQqEKEFz5tff3P8U0ICpCxANytzlbVbVGuvH0xoEhFPRtXaLwr6XKozz6EtOt4UQdMy9av7xNxwmCx5OzVwg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E3D3C16F2; Thu, 15 Aug 2024 01:30:34 -0700 (PDT) Received: from e126645.nice.arm.com (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 0BDA23F6A8; Thu, 15 Aug 2024 01:30:03 -0700 (PDT) From: Pierre Gondois To: linux-kernel@vger.kernel.org Cc: Pierre Gondois , "Rafael J. Wysocki" , Len Brown , Viresh Kumar , Robert Moore , 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 , Martin Rodriguez Reboredo , FUJITA Tomonori , Asahi Lina , Mika Westerberg , Manos Pitsidianakis , Danilo Krummrich , Thomas Bertschinger , linux-acpi@vger.kernel.org, linux-pm@vger.kernel.org, acpica-devel@lists.linux.dev, rust-for-linux@vger.kernel.org Subject: [RFC PATCH 2/6] cpufreq: cppc: Remove perf_fb_ctrs field from struct cppc_cpudata Date: Thu, 15 Aug 2024 10:29:06 +0200 Message-Id: <20240815082916.1210110-3-pierre.gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240815082916.1210110-1-pierre.gondois@arm.com> References: <20240815082916.1210110-1-pierre.gondois@arm.com> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Remove the perf_fb_ctrs field from `struct cppc_cpudata` as it was never used. Signed-off-by: Pierre Gondois --- drivers/cpufreq/cppc_cpufreq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 208d7b176fd0..632f2caebbb5 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -31,7 +31,6 @@ struct cppc_cpudata { struct list_head node; struct cppc_perf_caps perf_caps; struct cppc_perf_ctrls perf_ctrls; - struct cppc_perf_fb_ctrs perf_fb_ctrs; unsigned int shared_type; cpumask_var_t shared_cpu_map; }; From patchwork Thu Aug 15 08:29:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre Gondois X-Patchwork-Id: 819974 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E31FE19D8A2; Thu, 15 Aug 2024 08:30:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710625; cv=none; b=BM9enkN9Cmey9ZGHQHGx4GnqdT/3LMEthID2nu9+I4rBTCqXKYejLqXpK00YZ2c9hiGyNyO3eITFYngN2MqMWTvxHKATVBCXIEkiskfjHOmPEsG0vc37/7fFm9TE7mk7LzNH5dgn1Rv72gsCA8k0xpTZyhvqfAcDflLkHk2gPgI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710625; c=relaxed/simple; bh=YRHVBaMdiGeTfmNJBTAk8FDw3gwW5aAfCPOCG88bRTw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SFgejkM0OXF7m4cKUquPsApkJF+T1EtafI/b3TtRDtvdtvjyrjD+g8d/+RVVklWxHoSeGVwFOSb56cWiC053k2mIpfjRzcgl1hyPW3MpbnjtOZYoMvjNQ39zS5idwYx7pEg0u9ACJoeAIzKfLSOxOWcO+tzIcbt2L9ENkVj7eEE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4F35D16F8; Thu, 15 Aug 2024 01:30:49 -0700 (PDT) Received: from e126645.nice.arm.com (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id D15D53F6A8; Thu, 15 Aug 2024 01:30:17 -0700 (PDT) From: Pierre Gondois To: linux-kernel@vger.kernel.org Cc: Pierre Gondois , "Rafael J. Wysocki" , Len Brown , Viresh Kumar , Robert Moore , 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 , Martin Rodriguez Reboredo , Asahi Lina , Danilo Krummrich , "Rob Herring (Arm)" , FUJITA Tomonori , Mika Westerberg , Manos Pitsidianakis , Thomas Bertschinger , linux-acpi@vger.kernel.org, linux-pm@vger.kernel.org, acpica-devel@lists.linux.dev, rust-for-linux@vger.kernel.org Subject: [RFC PATCH 3/6] rust: module: Allow modules to specify initcall section Date: Thu, 15 Aug 2024 10:29:07 +0200 Message-Id: <20240815082916.1210110-4-pierre.gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240815082916.1210110-1-pierre.gondois@arm.com> References: <20240815082916.1210110-1-pierre.gondois@arm.com> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 To give more flexibility to modules regarding their initialization, add an `initcall` field allowing to specify the initicall section their initialization function belongs to. Signed-off-by: Pierre Gondois --- rust/macros/module.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/rust/macros/module.rs b/rust/macros/module.rs index be03b2cf77a1..8724738f2a52 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -97,14 +97,22 @@ struct ModuleInfo { author: Option, description: Option, alias: Option>, + initcall: Option, } impl ModuleInfo { fn parse(it: &mut token_stream::IntoIter) -> Self { let mut info = ModuleInfo::default(); - const EXPECTED_KEYS: &[&str] = - &["type", "name", "author", "description", "license", "alias"]; + const EXPECTED_KEYS: &[&str] = &[ + "type", + "name", + "author", + "description", + "license", + "alias", + "initcall", + ]; const REQUIRED_KEYS: &[&str] = &["type", "name", "license"]; let mut seen_keys = Vec::new(); @@ -131,6 +139,7 @@ fn parse(it: &mut token_stream::IntoIter) -> Self { "description" => info.description = Some(expect_string(it)), "license" => info.license = expect_string_ascii(it), "alias" => info.alias = Some(expect_string_array(it)), + "initcall" => info.initcall = Some(expect_string(it)), _ => panic!( "Unknown key \"{}\". Valid keys are: {:?}.", key, EXPECTED_KEYS @@ -187,6 +196,12 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { } } + let initcall_section = if let Some(section) = info.initcall { + section + } else { + String::from(".initcall6.init") + }; + // Built-in modules also export the `file` modinfo string. let file = std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable"); @@ -335,7 +350,7 @@ unsafe fn __exit() {{ type_ = info.type_, name = info.name, modinfo = modinfo.buffer, - initcall_section = ".initcall6.init" + initcall_section = initcall_section, ) .parse() .expect("Error parsing formatted string into token stream.") From patchwork Thu Aug 15 08:29:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre Gondois X-Patchwork-Id: 819659 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 32C4B177980; Thu, 15 Aug 2024 08:30:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710638; cv=none; b=JMX6d7P19V+P0HeI1G2yWVGMnj6CRPuqE0ekbplk03bLej1NKtEaR4sHTxSzQwbYt5q11/Au1dr3Kpgdr5WK/XHYlS7ZVGodWShoUCjR1aYmcrsTvgytaOCIyZJq36EyXn5gEj0V5/qkChXRbkm6HOP8uH8WEVOR3SPXGXicFW8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710638; c=relaxed/simple; bh=ZDbEQnYH376ogFQyuTaYXdGy5SLbLU9ts6dCAXzOXoc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=GeTMDkRY+PL9Czkt+jhpKLsb4KuR3khgmPpO0fRh3Y407Jgz+jdmX4wYY44LsBQZwj1rIUXPyKw19hv8VyX1IdC1XZcFvT2h+J+x2udqIA+1XTjSnKOrh/JhvwFVik3VEi6z6NDI2mjVe7+iOQc6/GyY+HoGbMK8EBiKUkaeZoY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id B3B3B1713; Thu, 15 Aug 2024 01:31:02 -0700 (PDT) Received: from e126645.nice.arm.com (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id F20753F6A8; Thu, 15 Aug 2024 01:30:31 -0700 (PDT) From: Pierre Gondois To: linux-kernel@vger.kernel.org Cc: Pierre Gondois , "Rafael J. Wysocki" , Len Brown , Viresh Kumar , Robert Moore , 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 , Martin Rodriguez Reboredo , Manos Pitsidianakis , Danilo Krummrich , "Rob Herring (Arm)" , FUJITA Tomonori , Mika Westerberg , Thomas Bertschinger , linux-acpi@vger.kernel.org, linux-pm@vger.kernel.org, acpica-devel@lists.linux.dev, rust-for-linux@vger.kernel.org Subject: [RFC PATCH 4/6] rust: cpufreq: Add methods to struct Cpufreq Date: Thu, 15 Aug 2024 10:29:08 +0200 Message-Id: <20240815082916.1210110-5-pierre.gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240815082916.1210110-1-pierre.gondois@arm.com> References: <20240815082916.1210110-1-pierre.gondois@arm.com> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The following methods are added and seamlessly allow to get/set the matching fields in the C definition of the `struct cpufreq`: - set_min() - set_max() - set_cur() - fast_switch_possible() - set_fast_switch_possible() - set_cpuinfo_min_freq() - set_cpuinfo_max_freq() - set_transition_delay_us() - set_shared_type() Signed-off-by: Pierre Gondois --- rust/kernel/cpufreq.rs | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index b395694de6c4..588080724fbf 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -318,16 +318,34 @@ pub fn min(&self) -> u32 { self.as_ref().min } + /// Set the minimum frequency for a cpufreq policy. + pub fn set_min(&mut self, min: u32) -> &mut Self { + self.as_mut_ref().min = min; + self + } + /// Returns the maximum frequency for a cpufreq policy. pub fn max(&self) -> u32 { self.as_ref().max } + /// Set the maximum frequency for a cpufreq policy. + pub fn set_max(&mut self, max: u32) -> &mut Self { + self.as_mut_ref().max = max; + self + } + /// Returns the current frequency for a cpufreq policy. pub fn cur(&self) -> u32 { self.as_ref().cur } + /// Set the current frequency for a cpufreq policy. + pub fn set_cur(&mut self, cur: u32) -> &mut Self { + self.as_mut_ref().cur = cur; + self + } + /// Sets the suspend frequency for a cpufreq policy. pub fn set_suspend_freq(&mut self, freq: u32) -> &mut Self { self.as_mut_ref().suspend_freq = freq; @@ -378,12 +396,47 @@ pub fn set_dvfs_possible_from_any_cpu(&mut self) -> &mut Self { self } + /// Get fast_switch_possible value. + pub fn fast_switch_possible(&self) -> bool { + self.as_ref().fast_switch_possible + } + + /// Enable/disable fast frequency switching. + pub fn set_fast_switch_possible(&mut self, val: bool) -> &mut Self { + self.as_mut_ref().fast_switch_possible = val; + self + } + /// Sets transition latency for a cpufreq policy. pub fn set_transition_latency(&mut self, latency: u32) -> &mut Self { self.as_mut_ref().cpuinfo.transition_latency = latency; self } + /// Set cpuinfo.min_freq. + pub fn set_cpuinfo_min_freq(&mut self, min_freq: u32) -> &mut Self { + self.as_mut_ref().cpuinfo.min_freq = min_freq; + self + } + + /// Set cpuinfo.max_freq. + pub fn set_cpuinfo_max_freq(&mut self, max_freq: u32) -> &mut Self { + self.as_mut_ref().cpuinfo.max_freq = max_freq; + self + } + + /// Set transition_delay_us, i.e. time between successive freq. change requests. + pub fn set_transition_delay_us(&mut self, transition_delay_us: u32) -> &mut Self { + self.as_mut_ref().transition_delay_us = transition_delay_us; + self + } + + /// Set shared_type, how CPUs coordinate freq. requests (ACPI only). + pub fn set_shared_type(&mut self, shared_type: u32) -> &mut Self { + self.as_mut_ref().shared_type = shared_type; + self + } + /// Returns the cpufreq table for a cpufreq policy. The cpufreq table is recreated in a /// light-weight manner from the raw pointer. The table in C code is not freed once this table /// is dropped. From patchwork Thu Aug 15 08:29:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre Gondois X-Patchwork-Id: 819973 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8F7AF1C2301; Thu, 15 Aug 2024 08:30:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710652; cv=none; b=jx2cIfgQOJ3wmMblfmwBDZslamxRynNXcwhNdLg7q15ry4POwTz9h3iCtFzTRB7clOvwcmATaLIBCiNGZcHkK7qcfs2GvTYBHVZd5iNrXsc9RFi3L37dbydnt99UOoxwnc7LAV+auH46n4MSn+4HvR1cChm1wK8Sjec3MQnV5F8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710652; c=relaxed/simple; bh=UCKGBoCnmN1loLFN5J/skTKjHoNsWsvh3M3lDR6/A44=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=VK1DqtmvNJ18YwXN+RHsPVZtdqFEQ30762iq8xo7Mu1X6M4LyCthtEoTvibD/RMuf9UXLxUR2heQejqUSftPF8eBIazhEtd19CgkUHXO1+aX0A1CjGi6sWBZNXO2Z4qrKCXTmFyyE+UoMW7aYt0cvkxgJA3xvHTw9FYrrjRMNfk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 12C931756; Thu, 15 Aug 2024 01:31:17 -0700 (PDT) Received: from e126645.nice.arm.com (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 94E103F6A8; Thu, 15 Aug 2024 01:30:45 -0700 (PDT) From: Pierre Gondois To: linux-kernel@vger.kernel.org Cc: Pierre Gondois , "Rafael J. Wysocki" , Len Brown , Viresh Kumar , Robert Moore , 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 , Martin Rodriguez Reboredo , "Rob Herring (Arm)" , FUJITA Tomonori , Mika Westerberg , Manos Pitsidianakis , Danilo Krummrich , Thomas Bertschinger , linux-acpi@vger.kernel.org, linux-pm@vger.kernel.org, acpica-devel@lists.linux.dev, rust-for-linux@vger.kernel.org Subject: [RFC PATCH 5/6] rust: bindings: Add bindings for rcppc_cpufreq driver Date: Thu, 15 Aug 2024 10:29:09 +0200 Message-Id: <20240815082916.1210110-6-pierre.gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240815082916.1210110-1-pierre.gondois@arm.com> References: <20240815082916.1210110-1-pierre.gondois@arm.com> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add bindings to prepare the enablement of the rcppc_cpufreq driver. Signed-off-by: Pierre Gondois --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index bee2b6013690..a7ba64b5614b 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -22,6 +22,7 @@ #include #include #include +#include /* `bindgen` gets confused at certain things. */ const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN; diff --git a/rust/helpers.c b/rust/helpers.c index 3b2850a11859..624b5c94dad6 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -370,6 +370,12 @@ void rust_helper_cpufreq_register_em_with_opp(struct cpufreq_policy *policy) cpufreq_register_em_with_opp(policy); } EXPORT_SYMBOL_GPL(rust_helper_cpufreq_register_em_with_opp); + +void rust_helper_cpufreq_verify_within_cpu_limits(struct cpufreq_policy_data *policy) +{ + cpufreq_verify_within_cpu_limits(policy); +} +EXPORT_SYMBOL_GPL(rust_helper_cpufreq_verify_within_cpu_limits); #endif #ifndef CONFIG_OF_DYNAMIC From patchwork Thu Aug 15 08:29:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre Gondois X-Patchwork-Id: 819658 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6DDA019D8BA; Thu, 15 Aug 2024 08:31:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710667; cv=none; b=lWzJatIB2/8vRt/+vYoMUaX/HoB95BgImPA+Kc7cAuF0WhUt2rfQAYLzhUL45sSJXBBonJ85Mv66TcitzeWzcwgo7SE9QJ0l+du8FWLjgXA1UL1o66ZcbkUKSDIo7G5g3mw9EwW3it3MGKtYK+p17XBKyAe17INl3UBrD/3BHR0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723710667; c=relaxed/simple; bh=yCf+HKHuM6f2qoMtzJkk0v/WG1j9KRG1+IxcRU8fI0g=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=TZRVXnOk9jRpSkruxnboQ/j7BDFisBV0xfKSPNkPgptG5bPdgQdjrQvycyguK7ZesXbXa8vKqfObqHHdrRzAXh0SSLnVJsCOps6xhLn6b02njuYXIQ5GlJeJ9qZ25nYdd2AG+J85o3JxmU61mftxITpVC30R0n+G1Y7+m3/e8EM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id DAEE81756; Thu, 15 Aug 2024 01:31:30 -0700 (PDT) Received: from e126645.nice.arm.com (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id E6A7B3F6A8; Thu, 15 Aug 2024 01:30:59 -0700 (PDT) From: Pierre Gondois To: linux-kernel@vger.kernel.org Cc: Pierre Gondois , "Rafael J. Wysocki" , Len Brown , Viresh Kumar , Robert Moore , 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 , Martin Rodriguez Reboredo , Manos Pitsidianakis , Mika Westerberg , FUJITA Tomonori , Thomas Bertschinger , Danilo Krummrich , linux-acpi@vger.kernel.org, linux-pm@vger.kernel.org, acpica-devel@lists.linux.dev, rust-for-linux@vger.kernel.org Subject: [RFC PATCH 6/6] rust: cpufreq: Add rust implementation of cppc_cpufreq driver Date: Thu, 15 Aug 2024 10:29:10 +0200 Message-Id: <20240815082916.1210110-7-pierre.gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240815082916.1210110-1-pierre.gondois@arm.com> References: <20240815082916.1210110-1-pierre.gondois@arm.com> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 In an effort to add test/support the cpufreq framework in rust, add a rust implementation of the cppc_cpufreq driver named: `rcppc_cpufreq`. This implementation doesn't support/implement: - vendor specific workarounds - Frequency Invariance Engine (FIE) - artificial Energy Model (EM) - (struct cpufreq_driver).attr field - QoS requests Basic support is provided to get/set the frequency on a platform implementing the CPPC section of the ACPI spec. Signed-off-by: Pierre Gondois --- drivers/cpufreq/Kconfig | 16 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/rcppc_cpufreq.rs | 333 +++++++++++++++++++++++++++++++ 3 files changed, 350 insertions(+) create mode 100644 drivers/cpufreq/rcppc_cpufreq.rs diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index eb9359bd3c5c..57130d0789b0 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -343,4 +343,20 @@ config ACPI_CPPC_CPUFREQ_FIE If in doubt, say N. +config ACPI_CPPC_CPUFREQ_RUST + tristate "Rust based CPUFreq driver based on the ACPI CPPC spec" + depends on ACPI_PROCESSOR + depends on ARM || ARM64 || RISCV + select ACPI_CPPC_LIB + help + This adds a Rust based CPUFreq driver based on the ACPI CPPC spec. + Basic support is only available for now, i.e. the following are + not supported: + - vendor specific workarounds + - Frequency Invariance Engine (FIE) + - artificial Energy Model (EM) + - QoS requests + + If in doubt, say N. + endmenu diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 4981d908b803..5e17db481a50 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET) += cpufreq_governor_attr_set.o obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o obj-$(CONFIG_CPUFREQ_DT_RUST) += rcpufreq_dt.o +obj-$(CONFIG_ACPI_CPPC_CPUFREQ_RUST) += rcppc_cpufreq.o obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o # Traces diff --git a/drivers/cpufreq/rcppc_cpufreq.rs b/drivers/cpufreq/rcppc_cpufreq.rs new file mode 100644 index 000000000000..198857a5b966 --- /dev/null +++ b/drivers/cpufreq/rcppc_cpufreq.rs @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust based implementation of the cppc_cpufreq driver. + +use core::format_args; + +use kernel::prelude::*; + +use kernel::{ + bindings, c_str, cpufreq, + cpumask::Cpumask, + error::{to_result, Result}, + sync::Arc, +}; + +/// 2 usec delay between sampling +const COUNTERS_SAMPLING_DELAY_US: u64 = 2; + +// Whether boost is supported +static mut BOOST_SUPPORTED: bool = false; + +struct CPUFreqCppcDriver { + _drv: cpufreq::Registration, +} + +struct CPUFreqCppcData { + perf_caps: bindings::cppc_perf_caps, + perf_ctrls: bindings::cppc_perf_ctrls, + shared_type: u32, + shared_cpu_map: Cpumask, +} + +impl CPUFreqCppcData { + fn new(cpu: u32) -> Result { + let mut shared_type = bindings::CPUFREQ_SHARED_TYPE_NONE; + let mut perf_caps = bindings::cppc_perf_caps::default(); + let mut shared_cpu_map = Cpumask::new()?; + + match acpi_get_psd_map(cpu, &mut shared_cpu_map, &mut shared_type) { + Err(e) => { + pr_debug!("Err parsing CPU{cpu} PSD data: err:{e:?}\n"); + return Err(e); + } + _ => {} + } + + match cppc_get_perf_caps(cpu as i32, &mut perf_caps) { + Err(e) => { + pr_debug!("Err reading CPU{cpu} perf caps: e:{e:?}\n"); + return Err(e); + } + _ => {} + } + + Ok(Self { + perf_caps: perf_caps, + perf_ctrls: bindings::cppc_perf_ctrls::default(), + shared_type: shared_type, + shared_cpu_map: shared_cpu_map, + }) + } +} + +fn acpi_get_psd_map(cpu: u32, shared_cpu_map: &mut Cpumask, shared_type: &mut u32) -> Result<()> { + unsafe { + to_result(bindings::acpi_get_psd_map( + cpu, + shared_cpu_map.as_mut_ptr(), + shared_type, + )) + } +} + +fn cppc_get_perf_caps(cpu: i32, perf_caps: &mut bindings::cppc_perf_caps) -> Result<()> { + unsafe { to_result(bindings::cppc_get_perf_caps(cpu, perf_caps)) } +} + +fn cppc_perf_to_khz(caps: &mut bindings::cppc_perf_caps, perf: u32) -> u32 { + unsafe { bindings::cppc_perf_to_khz(caps, perf) } +} + +fn cppc_khz_to_perf(caps: &mut bindings::cppc_perf_caps, freq: u32) -> u32 { + unsafe { bindings::cppc_khz_to_perf(caps, freq) } +} + +fn cppc_set_perf(cpu: u32, perf_ctrls: &mut bindings::cppc_perf_ctrls) -> Result<()> { + unsafe { to_result(bindings::cppc_set_perf(cpu as i32, perf_ctrls)) } +} + +fn cpufreq_freq_transition_begin( + policy: &mut cpufreq::Policy, + freqs: &mut bindings::cpufreq_freqs, +) { + unsafe { bindings::cpufreq_freq_transition_begin(policy.as_raw(), freqs) } +} + +fn cpufreq_freq_transition_end( + policy: &mut cpufreq::Policy, + freqs: &mut bindings::cpufreq_freqs, + transition_failed: bool, +) { + unsafe { + bindings::cpufreq_freq_transition_end(policy.as_raw(), freqs, transition_failed as i32) + } +} + +fn cppc_get_perf_ctrs(cpu: u32, fb_ctrs: &mut bindings::cppc_perf_fb_ctrs) -> Result<()> { + unsafe { to_result(bindings::cppc_get_perf_ctrs(cpu as i32, fb_ctrs)) } +} + +fn cppc_perf_from_fbctrs( + desired_perf: u32, + fb_ctrs_t0: bindings::cppc_perf_fb_ctrs, + fb_ctrs_t1: bindings::cppc_perf_fb_ctrs, +) -> u32 { + let reference_perf = fb_ctrs_t0.reference_perf; + let delta_reference = fb_ctrs_t1.reference.wrapping_sub(fb_ctrs_t0.reference); + let delta_delivered = fb_ctrs_t1.delivered.wrapping_sub(fb_ctrs_t0.delivered); + + if delta_reference == 0 || delta_delivered == 0 { + return desired_perf; + } + + return ((reference_perf - delta_delivered) / delta_reference) as u32; +} + +#[vtable] +impl cpufreq::Driver for CPUFreqCppcDriver { + type Data = (); + type PData = Arc; + + fn init(policy: &mut cpufreq::Policy) -> Result { + let cpu = policy.cpu(); + let mut data = CPUFreqCppcData::new(cpu)?; + + // Set min to lowest nonlinear perf to avoid any efficiency penalty + // (see Section 8.4.7.1.1.5 of ACPI 6.1 spec) + policy + .set_min(data.perf_caps.lowest_nonlinear_perf) + .set_max(data.perf_caps.nominal_perf); + + let lowest_nonlinear_perf = data.perf_caps.lowest_nonlinear_perf; + let nominal_perf = data.perf_caps.nominal_perf; + let highest_perf = data.perf_caps.highest_perf; + + // Set cpuinfo.min_freq to Lowest to make the full range of performance + // available if userspace wants to use any perf between lowest & lowest + // nonlinear perf + policy + .set_cpuinfo_min_freq(cppc_perf_to_khz(&mut data.perf_caps, lowest_nonlinear_perf)) + .set_cpuinfo_max_freq(cppc_perf_to_khz(&mut data.perf_caps, nominal_perf)); + + policy + .set_transition_delay_us(unsafe { bindings::cppc_get_transition_latency(cpu as i32) }) + .set_shared_type(data.shared_type); + + match data.shared_type { + bindings::CPUFREQ_SHARED_TYPE_HW => {} + bindings::CPUFREQ_SHARED_TYPE_NONE => {} + bindings::CPUFREQ_SHARED_TYPE_ANY => { + // All CPUs in the domain will share a policy and all cpufreq + // operations will use the same CPUFreqCppcData struct. + let cpus = policy.cpus(); + data.shared_cpu_map.copy(cpus); + } + default => { + pr_err!("Unsupported CPU co-ord type: {default}\n"); + return Err(EFAULT); + } + } + + if unsafe { bindings::cppc_allow_fast_switch() } { + policy.set_fast_switch_possible(true); + } + + // If 'highest_perf' is greater than 'nominal_perf', we assume CPU Boost + // is supported. + if highest_perf > nominal_perf { + unsafe { BOOST_SUPPORTED = true }; + } + + // Set policy->cur to max now. The governors will adjust later. + policy + .set_dvfs_possible_from_any_cpu() + .set_cur(cppc_perf_to_khz(&mut data.perf_caps, highest_perf)); + + cppc_set_perf(cpu, &mut data.perf_ctrls)?; + + Ok(Arc::new(data, GFP_KERNEL)?) + } + + fn exit(_policy: &mut cpufreq::Policy, _data: Option) -> Result<()> { + Ok(()) + } + + fn verify(policy_data: &mut cpufreq::PolicyData) -> Result<()> { + unsafe { bindings::cpufreq_verify_within_cpu_limits(policy_data.as_raw()) }; + Ok(()) + } + + fn target( + policy: &mut cpufreq::Policy, + target_freq: u32, + _relation: cpufreq::Relation, + ) -> Result<()> { + let data = match policy.data::() { + Some(data) => data, + None => return Err(ENOENT), + }; + + let mut perf_ctrls: bindings::cppc_perf_ctrls = data.perf_ctrls; + let mut perf_caps: bindings::cppc_perf_caps = data.perf_caps; + let desired_perf: u32 = cppc_khz_to_perf(&mut perf_caps, target_freq); + let cpu = policy.cpu(); + + // Return if it is exactly the same perf. + if desired_perf == perf_ctrls.desired_perf { + return Ok(()); + } + + perf_ctrls.desired_perf = desired_perf; + + let mut freqs = bindings::cpufreq_freqs::default(); + freqs.old = policy.cur(); + freqs.new = target_freq; + + cpufreq_freq_transition_begin(policy, &mut freqs); + let ret = cppc_set_perf(cpu, &mut perf_ctrls); + let transition_failed = match ret { + Ok(_) => false, + Err(e) => { + pr_debug!("Failed to set target on CPU:{cpu}. err:{e:?}\n"); + true + } + }; + cpufreq_freq_transition_end(policy, &mut freqs, transition_failed); + + ret + } + + fn fast_switch(policy: &mut cpufreq::Policy, target_freq: u32) -> u32 { + let data = match policy.data::() { + Some(data) => data, + None => return 0, + }; + + let mut perf_caps = data.perf_caps; + let mut perf_ctrls = data.perf_ctrls; + let desired_perf = cppc_khz_to_perf(&mut perf_caps, target_freq); + let cpu = policy.cpu(); + + perf_ctrls.desired_perf = desired_perf; + + if let Err(ret) = cppc_set_perf(cpu, &mut perf_ctrls) { + pr_debug!("Failed to set target on CPU:{cpu}. ret:{ret:?}\n"); + return 0; + } + + return target_freq; + } + + fn get(policy: &mut cpufreq::Policy) -> Result { + let mut fb_ctrs_t0 = bindings::cppc_perf_fb_ctrs::default(); + let mut fb_ctrs_t1 = bindings::cppc_perf_fb_ctrs::default(); + let cpu = policy.cpu(); + + let data = match policy.data::() { + Some(data) => data, + None => return Err(ENOENT), + }; + + let mut perf_caps = data.perf_caps; + let desired_perf = data.perf_ctrls.desired_perf; + + cppc_get_perf_ctrs(cpu, &mut fb_ctrs_t0)?; + unsafe { bindings::__udelay(COUNTERS_SAMPLING_DELAY_US) }; + cppc_get_perf_ctrs(cpu, &mut fb_ctrs_t1)?; + + let delivered_perf = cppc_perf_from_fbctrs(desired_perf, fb_ctrs_t0, fb_ctrs_t1); + let freq = cppc_perf_to_khz(&mut perf_caps, delivered_perf); + + Ok(freq) + } + + fn set_boost(policy: &mut cpufreq::Policy, state: i32) -> Result<()> { + if unsafe { !BOOST_SUPPORTED } { + pr_err!("BOOST not supported by CPU or firmware\n"); + return Err(EINVAL); + } + + let data = match policy.data::() { + Some(data) => data, + None => return Err(ENOENT), + }; + let mut caps = data.perf_caps; + let highest_perf = caps.highest_perf; + let nominal_perf = caps.nominal_perf; + + let max_freq = if state != 0 { + cppc_perf_to_khz(&mut caps, highest_perf) + } else { + cppc_perf_to_khz(&mut caps, nominal_perf) + }; + + policy + .set_max(max_freq) + .set_cpuinfo_max_freq(max_freq); + + Ok(()) + } +} + +module! { + type: CPUFreqCppcDriver, + name: "cppc_cpufreq", + author: "Pierre Gondois", + description: "CPPC cpufreq driver", + license: "GPL v2", + initcall: ".initcall7.init", +} + +impl kernel::Module for CPUFreqCppcDriver { + fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result { + let drv = cpufreq::Registration::::register( + c_str!("rcppc-cpufreq"), + (), + cpufreq::flags::CONST_LOOPS, + false, + )?; + + Ok(CPUFreqCppcDriver { _drv: drv }) + } +}