mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2026-09-08 18:21:29 +01:00
lib/utils/cppc: Emulate REFERENCE_CTR and DELIVERED_CTR locally
Currently, REFERENCE_CTR and DELIVERED_CTR are always read by sending an RPMI message to the controller. This does not scale well since these registers are typically polled frequently by CPU frequency governors. The reference counter can be simply the TIME csr, so it can be read locally without going over RPMI. If the fast channel is supported, the delivered counter can also be emulated locally: the fast channel exposes the current frequency, which is multiplied by the elapsed TIME csr ticks since the last read to calculate the delivered performance counter. Signed-off-by: Sunil V L <sunilvl@oss.qualcomm.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20260703050530.2460037-3-sunilvl@oss.qualcomm.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
#include <sbi/sbi_cppc.h>
|
#include <sbi/sbi_cppc.h>
|
||||||
#include <sbi/sbi_ecall_interface.h>
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi/sbi_timer.h>
|
||||||
#include <sbi_utils/fdt/fdt_driver.h>
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
#include <sbi_utils/fdt/fdt_helper.h>
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
#include <sbi_utils/mailbox/fdt_mailbox.h>
|
#include <sbi_utils/mailbox/fdt_mailbox.h>
|
||||||
@@ -39,6 +40,8 @@ struct rpmi_cppc {
|
|||||||
ulong fc_db_addr;
|
ulong fc_db_addr;
|
||||||
u64 fc_db_setmask;
|
u64 fc_db_setmask;
|
||||||
u64 fc_db_preservemask;
|
u64 fc_db_preservemask;
|
||||||
|
u64 prev_time_csr;
|
||||||
|
u64 prev_delivered_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned long rpmi_cppc_offset;
|
static unsigned long rpmi_cppc_offset;
|
||||||
@@ -107,6 +110,7 @@ static void rpmi_cppc_fc_db_trigger(struct rpmi_cppc *cppc)
|
|||||||
|
|
||||||
static int rpmi_cppc_read(unsigned long reg, u64 *val)
|
static int rpmi_cppc_read(unsigned long reg, u64 *val)
|
||||||
{
|
{
|
||||||
|
u64 curr_freq, curr_time_csr, time_csr_delta, freq;
|
||||||
int rc = SBI_SUCCESS;
|
int rc = SBI_SUCCESS;
|
||||||
struct rpmi_cppc_read_reg_req req;
|
struct rpmi_cppc_read_reg_req req;
|
||||||
struct rpmi_cppc_read_reg_resp resp;
|
struct rpmi_cppc_read_reg_resp resp;
|
||||||
@@ -116,12 +120,38 @@ static int rpmi_cppc_read(unsigned long reg, u64 *val)
|
|||||||
req.reg_id = reg;
|
req.reg_id = reg;
|
||||||
cppc = rpmi_cppc_get_pointer(req.hart_id);
|
cppc = rpmi_cppc_get_pointer(req.hart_id);
|
||||||
|
|
||||||
rc = rpmi_normal_request_with_status(
|
if ((reg == SBI_CPPC_DELIVERED_CTR) && cppc->fc_supported) {
|
||||||
cppc->chan, RPMI_CPPC_SRV_READ_REG,
|
#if __riscv_xlen != 32
|
||||||
&req, rpmi_u32_count(req), rpmi_u32_count(req),
|
curr_freq = readq((void *)cppc->fc_perf_feedback_addr);
|
||||||
&resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
|
#else
|
||||||
if (rc)
|
curr_freq = readl((void *)cppc->fc_perf_feedback_addr + 4);
|
||||||
return rc;
|
curr_freq <<= 32;
|
||||||
|
curr_freq |= readl((void *)cppc->fc_perf_feedback_addr);
|
||||||
|
#endif
|
||||||
|
curr_time_csr = sbi_timer_value();
|
||||||
|
time_csr_delta = curr_time_csr - cppc->prev_time_csr;
|
||||||
|
cppc->prev_time_csr = curr_time_csr;
|
||||||
|
|
||||||
|
freq = sbi_timer_frequency();
|
||||||
|
if (freq)
|
||||||
|
cppc->prev_delivered_counter +=
|
||||||
|
curr_freq * (time_csr_delta / freq) +
|
||||||
|
(curr_freq * (time_csr_delta % freq)) / freq;
|
||||||
|
|
||||||
|
resp.data_lo = cpu_to_le32(cppc->prev_delivered_counter & UINT32_MAX);
|
||||||
|
resp.data_hi = cpu_to_le32(cppc->prev_delivered_counter >> 32);
|
||||||
|
} else if (reg == SBI_CPPC_REFERENCE_CTR) {
|
||||||
|
curr_time_csr = sbi_timer_value();
|
||||||
|
resp.data_lo = cpu_to_le32(curr_time_csr & UINT32_MAX);
|
||||||
|
resp.data_hi = cpu_to_le32(curr_time_csr >> 32);
|
||||||
|
} else {
|
||||||
|
rc = rpmi_normal_request_with_status(
|
||||||
|
cppc->chan, RPMI_CPPC_SRV_READ_REG,
|
||||||
|
&req, rpmi_u32_count(req), rpmi_u32_count(req),
|
||||||
|
&resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
*val = resp.data_lo;
|
*val = resp.data_lo;
|
||||||
@@ -276,6 +306,8 @@ static int rpmi_cppc_update_hart_scratch(struct mbox_chan *chan)
|
|||||||
if (!cppc)
|
if (!cppc)
|
||||||
return SBI_ENOSYS;
|
return SBI_ENOSYS;
|
||||||
|
|
||||||
|
cppc->prev_time_csr = 0;
|
||||||
|
cppc->prev_delivered_counter = 0;
|
||||||
cppc->chan = chan;
|
cppc->chan = chan;
|
||||||
cppc->mode = cppc_mode;
|
cppc->mode = cppc_mode;
|
||||||
cppc->fc_supported = fc_supported;
|
cppc->fc_supported = fc_supported;
|
||||||
|
|||||||
Reference in New Issue
Block a user