[PATCH] ACPI: RISC-V: CPPC: Implement cpc_read_ffh_fb_ctrs()

"Yufan Dou" <[email protected]>
Newsgroups org.kernel.vger.linux-acpi,org.infradead.lists.linux-riscv,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
On RISC-V, each cpc_read_ffh() for a CSR-type FFH register sends a
separate IPI to the target hart via smp_call_function_single().
cppc_get_perf_ctrs() therefore samples the delivered and reference
counters in two separate IPIs, at two different instants. The skew
between the two sampling points distorts the delivered/reference
ratio and thus the frequency reported by cpufreq.

Implement the cpc_read_ffh_fb_ctrs() hook to read both CSR counters
back-to-back in a single IPI, which narrows the sampling window to a
few instructions and halves the number of cross-CPU calls. This
improves the accuracy of the reported frequency in the same way as
the arm64 implementation of the hook, which reads both AMU counters
in a single counters_read_on_cpu() call.

SBI-type FFH registers still fall back to individual reads, since
pairing them would not reduce the number of SBI calls on the target
hart.

Testing was performed while CPU1 was kept busy with:

  # stress-ng --cpu 1 --taskset 1

On a CPU with cpuinfo_max_freq of 3000000 kHz:

Before:

  Maximum observed cpuinfo_cur_freq: 3201369 kHz
  Maximum observed error:            +201369 kHz (+6.71%)

After:

  Maximum observed cpuinfo_cur_freq: 3009646 kHz
  Maximum observed error:              +9646 kHz (+0.32%)

The maximum observed error is reduced by 95.2%.

Signed-off-by: Yufan Dou <[email protected]>
---
 drivers/acpi/riscv/cppc.c | 47 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/acpi/riscv/cppc.c b/drivers/acpi/riscv/cppc.c
index 42c1a9052470..2ca98fa69e9a 100644
--- a/drivers/acpi/riscv/cppc.c
+++ b/drivers/acpi/riscv/cppc.c
@@ -85,6 +85,20 @@ static void cppc_ffh_csr_write(void *write_data)
 	data->ret.error = -EINVAL;
 }
 
+struct sbi_cppc_fb_ctrs_data {
+	struct sbi_cppc_data first;
+	struct sbi_cppc_data second;
+};
+
+static void cppc_ffh_csr_read_fb_ctrs(void *read_data)
+{
+	struct sbi_cppc_fb_ctrs_data *data = read_data;
+
+	cppc_ffh_csr_read(&data->first);
+	if (!data->first.ret.error)
+		cppc_ffh_csr_read(&data->second);
+}
+
 /*
  * Refer to drivers/acpi/cppc_acpi.c for the description of the functions
  * below.
@@ -125,6 +139,39 @@ int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
 	return -EINVAL;
 }
 
+int cpc_read_ffh_fb_ctrs(int cpu, struct cpc_reg *reg1, u64 *val1,
+			 struct cpc_reg *reg2, u64 *val2)
+{
+	struct sbi_cppc_fb_ctrs_data data;
+	int ret;
+
+	if (WARN_ON_ONCE(irqs_disabled()))
+		return -EPERM;
+
+	/* Only CSR counters can be paired within a single IPI. */
+	if (FFH_CPPC_TYPE(reg1->address) != FFH_CPPC_CSR ||
+	    FFH_CPPC_TYPE(reg2->address) != FFH_CPPC_CSR)
+		return -EOPNOTSUPP;
+
+	data.first.reg = FFH_CPPC_CSR_NUM(reg1->address);
+	data.second.reg = FFH_CPPC_CSR_NUM(reg2->address);
+
+	ret = smp_call_function_single(cpu, cppc_ffh_csr_read_fb_ctrs,
+				       &data, 1);
+	if (ret)
+		return ret;
+
+	if (data.first.ret.error)
+		return data.first.ret.error;
+	if (data.second.ret.error)
+		return data.second.ret.error;
+
+	*val1 = data.first.ret.value;
+	*val2 = data.second.ret.value;
+
+	return 0;
+}
+
 int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
 {
 	struct sbi_cppc_data data;

base-commit: 89a312991dc6e638a36adc43ccb91dbc25504c04
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.