drivers: firmware: arm_scmi: Add snapshot of dcvs scmi drivers

Add dcvs scmi drivers. This snapshot is taken as of msm-5.15
commit 250869d2bdc2192 ("sched: improve the scheduler").

Change-Id: Id8408e23a11c60de4ac7fa7e3205f907af68ea08
Signed-off-by: Amir Vajid <quic_avajid@quicinc.com>
This commit is contained in:
Amir Vajid 2022-08-29 23:03:01 -07:00
parent edb19769c0
commit 0076ed22a3
5 changed files with 695 additions and 0 deletions

View File

@ -134,6 +134,41 @@ config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE
in atomic context too, at the price of using a number of busy-waiting
primitives all over instead. If unsure say N.
config QTI_SCMI_PMU_PROTOCOL
tristate "Qualcomm Technologies, Inc. SCMI PMU vendor Protocol"
depends on ARM || ARM64 || COMPILE_TEST
depends on ARM_SCMI_PROTOCOL && QCOM_CPUCP
help
System Control and Management Interface (SCMI) pmu vendor protocol.
This protocol provides interface to communicate with micro controller
which maintains the PMU configuration for multiple clients.
This driver defines the comands or message ID's used for this
communication and also exposes the ops used by clients.
config QTI_SCMI_C1DCVS_PROTOCOL
tristate "Qualcomm Technologies, Inc. SCMI C1DCVS vendor Protocol"
depends on ARM || ARM64 || COMPILE_TEST
depends on ARM_SCMI_PROTOCOL && QCOM_CPUCP
help
System Control and Management Interface (SCMI) c1dcvs vendor protocol.
This protocol provides interface to communicate with micro controller
which maintains the c1dcvs algorithm.
This driver defines the comands or message ID's used for this
communication and also exposes the ops used by clients.
config QTI_SCMI_MEMLAT_PROTOCOL
tristate "Qualcomm Technologies, Inc. SCMI MEMLAT vendor Protocol"
depends on ARM || ARM64 || COMPILE_TEST
depends on ARM_SCMI_PROTOCOL && QCOM_CPUCP
help
System Control and Management Interface (SCMI) memlat vendor protocol.
This protocol provides interface to communicate with micro controller
which is executing the hw memlat governor. This driver defines the
commands or message ID's used for this communication and also exposes
the ops used by clients.
endif #ARM_SCMI_PROTOCOL
config ARM_SCMI_POWER_DOMAIN

View File

@ -13,6 +13,9 @@ scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o
obj-$(CONFIG_QTI_SCMI_PMU_PROTOCOL) += pmu_vendor.o
obj-$(CONFIG_QTI_SCMI_C1DCVS_PROTOCOL) += c1dcvs_vendor.o
obj-$(CONFIG_QTI_SCMI_MEMLAT_PROTOCOL) += memlat_vendor.o
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame

View File

@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/scmi_c1dcvs.h>
#include "common.h"
#define SCMI_MAX_RX_SIZE 128
enum scmi_c1dcvs_protocol_cmd {
SET_ENABLE_C1DCVS = 11,
GET_ENABLE_C1DCVS,
SET_ENABLE_TRACE,
GET_ENABLE_TRACE,
SET_IPC_THRESH,
GET_IPC_THRESH,
SET_EFREQ_THRESH,
GET_EFREQ_THRESH,
SET_HYSTERESIS,
GET_HYSTERESIS,
};
struct c1dcvs_thresh {
unsigned int cluster;
unsigned int thresh;
};
static int scmi_send_tunable_c1dcvs(const struct scmi_protocol_handle *ph,
void *buf, u32 msg_id)
{
int ret;
struct scmi_xfer *t;
unsigned int *msg;
unsigned int *src = buf;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg),
&t);
if (ret)
return ret;
msg = t->tx.buf;
*msg = cpu_to_le32(*src);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_get_tunable_c1dcvs(const struct scmi_protocol_handle *ph,
void *buf, u32 msg_id)
{
int ret;
struct scmi_xfer *t;
struct c1dcvs_thresh *msg;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), SCMI_MAX_RX_SIZE,
&t);
if (ret)
return ret;
ret = ph->xops->do_xfer(ph, t);
memcpy(buf, t->rx.buf, t->rx.len);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_send_thresh_c1dcvs(const struct scmi_protocol_handle *ph,
void *buf, u32 msg_id)
{
int ret;
struct scmi_xfer *t;
struct c1dcvs_thresh *msg;
unsigned int *src = buf;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg),
&t);
if (ret)
return ret;
msg = t->tx.buf;
msg->cluster = cpu_to_le32(src[0]);
msg->thresh = cpu_to_le32(src[1]);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_set_enable_c1dcvs(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_send_tunable_c1dcvs(ph, buf, SET_ENABLE_C1DCVS);
}
static int scmi_get_enable_c1dcvs(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_get_tunable_c1dcvs(ph, buf, GET_ENABLE_C1DCVS);
}
static int scmi_set_enable_trace(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_send_tunable_c1dcvs(ph, buf, SET_ENABLE_TRACE);
}
static int scmi_get_enable_trace(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_get_tunable_c1dcvs(ph, buf, GET_ENABLE_TRACE);
}
static int scmi_set_ipc_thresh(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_send_thresh_c1dcvs(ph, buf, SET_IPC_THRESH);
}
static int scmi_get_ipc_thresh(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_get_tunable_c1dcvs(ph, buf, GET_IPC_THRESH);
}
static int scmi_set_efreq_thresh(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_send_thresh_c1dcvs(ph, buf, SET_EFREQ_THRESH);
}
static int scmi_get_efreq_thresh(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_get_tunable_c1dcvs(ph, buf, GET_EFREQ_THRESH);
}
static int scmi_set_hysteresis(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_send_tunable_c1dcvs(ph, buf, SET_HYSTERESIS);
}
static int scmi_get_hysteresis(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_get_tunable_c1dcvs(ph, buf, GET_HYSTERESIS);
}
static struct scmi_c1dcvs_vendor_ops c1dcvs_config_ops = {
.set_enable_c1dcvs = scmi_set_enable_c1dcvs,
.get_enable_c1dcvs = scmi_get_enable_c1dcvs,
.set_enable_trace = scmi_set_enable_trace,
.get_enable_trace = scmi_get_enable_trace,
.set_ipc_thresh = scmi_set_ipc_thresh,
.get_ipc_thresh = scmi_get_ipc_thresh,
.set_efreq_thresh = scmi_set_efreq_thresh,
.get_efreq_thresh = scmi_get_efreq_thresh,
.set_hysteresis = scmi_set_hysteresis,
.get_hysteresis = scmi_get_hysteresis,
};
static int scmi_c1dcvs_protocol_init(const struct scmi_protocol_handle *ph)
{
u32 version;
ph->xops->version_get(ph, &version);
dev_dbg(ph->dev, "version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
return 0;
}
static const struct scmi_protocol scmi_c1dcvs = {
.id = SCMI_C1DCVS_PROTOCOL,
.owner = THIS_MODULE,
.instance_init = &scmi_c1dcvs_protocol_init,
.ops = &c1dcvs_config_ops,
};
module_scmi_protocol(scmi_c1dcvs);
MODULE_DESCRIPTION("SCMI C1DCVS vendor Protocol");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,387 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/scmi_memlat.h>
#include "common.h"
#define MAX_MAP_ENTRIES 14
#define SCMI_VENDOR_MSG_START (3)
#define SCMI_VENDOR_MSG_MODULE_START (16)
#define SCMI_MAX_RX_SIZE 128
#define SCMI_MAX_GET_DATA_SIZE 124
#define INVALID_IDX 0xFF
enum scmi_memlat_protocol_cmd {
MEMLAT_SET_LOG_LEVEL = SCMI_VENDOR_MSG_START,
MEMLAT_FLUSH_LOGBUF,
MEMLAT_SET_MEM_GROUP = SCMI_VENDOR_MSG_MODULE_START,
MEMLAT_SET_MONITOR,
MEMLAT_SET_COMMON_EV_MAP,
MEMLAT_SET_GRP_EV_MAP,
MEMLAT_ADAPTIVE_LOW_FREQ,
MEMLAT_ADAPTIVE_HIGH_FREQ,
MEMLAT_GET_ADAPTIVE_CUR_FREQ,
MEMLAT_IPM_CEIL,
MEMLAT_FE_STALL_FLOOR,
MEMLAT_BE_STALL_FLOOR,
MEMLAT_WB_PCT,
MEMLAT_IPM_FILTER,
MEMLAT_FREQ_SCALE_PCT,
MEMLAT_FREQ_SCALE_LIMIT_MHZ,
MEMLAT_SAMPLE_MS,
MEMLAT_MON_FREQ_MAP,
MEMLAT_SET_MIN_FREQ,
MEMLAT_SET_MAX_FREQ,
MEMLAT_GET_CUR_FREQ,
MEMLAT_START_TIMER,
MEMLAT_STOP_TIMER,
MEMLAT_GET_TIMESTAMP,
MEMLAT_MAX_MSG
};
struct node_msg {
uint32_t cpumask;
uint32_t hw_type;
uint32_t mon_type;
uint32_t mon_idx;
char mon_name[MAX_NAME_LEN];
};
struct scalar_param_msg {
uint32_t hw_type;
uint32_t mon_idx;
uint32_t val;
};
struct map_table {
uint32_t v1;
uint32_t v2;
};
struct map_param_msg {
uint32_t hw_type;
uint32_t mon_idx;
uint32_t nr_rows;
struct map_table tbl[MAX_MAP_ENTRIES];
};
struct ev_map_msg {
uint32_t num_evs;
uint32_t hw_type;
uint8_t cid[MAX_EV_CNTRS];
};
static int scmi_set_ev_map(const struct scmi_protocol_handle *ph, u32 hw_type,
void *buf, u32 msg_id, u32 num_evs)
{
int ret, i = 0;
struct scmi_xfer *t;
struct ev_map_msg *msg;
uint8_t *src = buf;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg),
&t);
if (ret)
return ret;
msg = t->tx.buf;
msg->num_evs = cpu_to_le32(num_evs);
msg->hw_type = cpu_to_le32(hw_type);
for (i = 0; i < num_evs; i++)
msg->cid[i] = src[i];
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_set_grp_map(const struct scmi_protocol_handle *ph, u32 hw_type,
void *buf, u32 num_evs)
{
return scmi_set_ev_map(ph, hw_type, buf, MEMLAT_SET_GRP_EV_MAP, num_evs);
}
static int scmi_set_common_map(const struct scmi_protocol_handle *ph, void *buf, u32 num_evs)
{
return scmi_set_ev_map(ph, INVALID_IDX, buf, MEMLAT_SET_COMMON_EV_MAP, num_evs);
}
static int scmi_set_memgrp_mon(const struct scmi_protocol_handle *ph,
u32 cpus_mpidr, u32 hw_type, u32 mon_type,
u32 mon_idx, const char *mon_name, u32 msg_id)
{
int ret = 0;
struct scmi_xfer *t;
struct node_msg *msg;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg),
&t);
if (ret)
return ret;
msg = t->tx.buf;
msg->cpumask = cpu_to_le32(cpus_mpidr);
msg->hw_type = cpu_to_le32(hw_type);
msg->mon_type = cpu_to_le32(mon_type);
msg->mon_idx = cpu_to_le32(mon_idx);
if (mon_name)
snprintf(msg->mon_name, MAX_NAME_LEN, mon_name);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_set_mon(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
u32 hw_type, u32 mon_type, u32 mon_idx, const char *mon_name)
{
return scmi_set_memgrp_mon(ph, cpus_mpidr, hw_type, mon_type,
mon_idx, mon_name, MEMLAT_SET_MONITOR);
}
static int scmi_set_mem_grp(const struct scmi_protocol_handle *ph,
u32 cpus_mpidr, u32 hw_type)
{
return scmi_set_memgrp_mon(ph, cpus_mpidr, hw_type, 0,
0, NULL, MEMLAT_SET_MEM_GROUP);
}
static int scmi_freq_map(const struct scmi_protocol_handle *ph, u32 hw_type,
u32 mon_idx, u32 nr_rows, void *buf)
{
int ret, i = 0;
struct scmi_xfer *t;
struct map_param_msg *msg;
struct map_table *tbl, *src = buf;
if (nr_rows > MAX_MAP_ENTRIES)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, MEMLAT_MON_FREQ_MAP, sizeof(*msg),
sizeof(*msg), &t);
if (ret)
return ret;
msg = t->tx.buf;
msg->hw_type = cpu_to_le32(hw_type);
msg->mon_idx = cpu_to_le32(mon_idx);
msg->nr_rows = cpu_to_le32(nr_rows);
tbl = msg->tbl;
for (i = 0; i < nr_rows; i++) {
tbl[i].v1 = cpu_to_le32(src[i].v1);
tbl[i].v2 = cpu_to_le32(src[i].v2);
}
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_set_tunable(const struct scmi_protocol_handle *ph,
u32 hw_type, u32 msg_id, u32 mon_idx, u32 val)
{
int ret = 0;
struct scmi_xfer *t;
struct scalar_param_msg *msg;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg),
sizeof(*msg), &t);
if (ret)
return ret;
msg = t->tx.buf;
msg->hw_type = cpu_to_le32(hw_type);
msg->mon_idx = cpu_to_le32(mon_idx);
msg->val = cpu_to_le32(val);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
#define scmi_send_cmd(name, _msg_id) \
static int scmi_##name(const struct scmi_protocol_handle *ph, \
u32 hw_type, u32 mon_idx, u32 val) \
{ \
return scmi_set_tunable(ph, hw_type, _msg_id, mon_idx, val); \
} \
scmi_send_cmd(ipm_ceil, MEMLAT_IPM_CEIL);
scmi_send_cmd(fe_stall_floor, MEMLAT_FE_STALL_FLOOR);
scmi_send_cmd(be_stall_floor, MEMLAT_BE_STALL_FLOOR);
scmi_send_cmd(wb_pct_thres, MEMLAT_WB_PCT);
scmi_send_cmd(wb_filter_ipm, MEMLAT_IPM_FILTER);
scmi_send_cmd(freq_scale_pct, MEMLAT_FREQ_SCALE_PCT);
scmi_send_cmd(freq_scale_limit_mhz, MEMLAT_FREQ_SCALE_LIMIT_MHZ);
scmi_send_cmd(min_freq, MEMLAT_SET_MIN_FREQ);
scmi_send_cmd(max_freq, MEMLAT_SET_MAX_FREQ);
scmi_send_cmd(adaptive_low_freq, MEMLAT_ADAPTIVE_LOW_FREQ);
scmi_send_cmd(adaptive_high_freq, MEMLAT_ADAPTIVE_HIGH_FREQ);
static int scmi_send_start_stop(const struct scmi_protocol_handle *ph, u32 msg_id)
{
int ret = 0;
struct scmi_xfer *t;
ret = ph->xops->xfer_get_init(ph, msg_id, 0, 0, &t);
if (ret)
return ret;
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_stop_timer(const struct scmi_protocol_handle *ph)
{
return scmi_send_start_stop(ph, MEMLAT_STOP_TIMER);
}
static int scmi_start_timer(const struct scmi_protocol_handle *ph)
{
return scmi_send_start_stop(ph, MEMLAT_START_TIMER);
}
static int scmi_flush_cpucp_log(const struct scmi_protocol_handle *ph)
{
return scmi_send_start_stop(ph, MEMLAT_FLUSH_LOGBUF);
}
static int scmi_set_global_var(const struct scmi_protocol_handle *ph, u32 val, u32 msg_id)
{
int ret = 0;
struct scmi_xfer *t;
u32 *ptr;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), sizeof(u32), &t);
if (ret)
return ret;
ptr = (u32 *)t->tx.buf;
*ptr = cpu_to_le32(val);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_set_log_level(const struct scmi_protocol_handle *ph, u32 val)
{
return scmi_set_global_var(ph, val, MEMLAT_SET_LOG_LEVEL);
}
static int scmi_set_sample_ms(const struct scmi_protocol_handle *ph, u32 val)
{
return scmi_set_global_var(ph, val, MEMLAT_SAMPLE_MS);
}
static int scmi_get_timestamp(const struct scmi_protocol_handle *ph, void *buf)
{
int ret = 0;
struct scmi_xfer *t;
ret = ph->xops->xfer_get_init(ph, MEMLAT_GET_TIMESTAMP, sizeof(u32),
SCMI_MAX_RX_SIZE, &t);
if (ret)
return ret;
ret = ph->xops->do_xfer(ph, t);
if (t->rx.len != sizeof(u64))
return -EMSGSIZE;
memcpy(buf, t->rx.buf, t->rx.len);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_get_freq(const struct scmi_protocol_handle *ph, uint32_t hw_type,
uint32_t mon_idx, void *buf, uint32_t msg_id)
{
int ret = 0;
struct scmi_xfer *t;
struct scalar_param_msg *msg;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg),
SCMI_MAX_RX_SIZE, &t);
if (ret)
return ret;
msg = t->tx.buf;
msg->hw_type = cpu_to_le32(hw_type);
msg->mon_idx = cpu_to_le32(mon_idx);
ret = ph->xops->do_xfer(ph, t);
if (t->rx.len != sizeof(u32))
return -EMSGSIZE;
memcpy(buf, t->rx.buf, t->rx.len);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_get_cur_freq(const struct scmi_protocol_handle *ph, uint32_t hw_type,
uint32_t mon_idx, void *buf)
{
return scmi_get_freq(ph, hw_type, mon_idx, buf, MEMLAT_GET_CUR_FREQ);
}
static int scmi_get_adaptive_cur_freq(const struct scmi_protocol_handle *ph, uint32_t hw_type,
uint32_t mon_idx, void *buf)
{
return scmi_get_freq(ph, hw_type, mon_idx, buf, MEMLAT_GET_ADAPTIVE_CUR_FREQ);
}
static struct scmi_memlat_vendor_ops memlat_proto_ops = {
.set_mem_grp = scmi_set_mem_grp,
.freq_map = scmi_freq_map,
.set_mon = scmi_set_mon,
.set_common_ev_map = scmi_set_common_map,
.set_grp_ev_map = scmi_set_grp_map,
.adaptive_low_freq = scmi_adaptive_low_freq,
.adaptive_high_freq = scmi_adaptive_high_freq,
.get_adaptive_cur_freq = scmi_get_adaptive_cur_freq,
.ipm_ceil = scmi_ipm_ceil,
.fe_stall_floor = scmi_fe_stall_floor,
.be_stall_floor = scmi_be_stall_floor,
.sample_ms = scmi_set_sample_ms,
.wb_filter_ipm = scmi_wb_filter_ipm,
.wb_pct_thres = scmi_wb_pct_thres,
.freq_scale_pct = scmi_freq_scale_pct,
.freq_scale_limit_mhz = scmi_freq_scale_limit_mhz,
.min_freq = scmi_min_freq,
.max_freq = scmi_max_freq,
.get_cur_freq = scmi_get_cur_freq,
.start_timer = scmi_start_timer,
.stop_timer = scmi_stop_timer,
.set_log_level = scmi_set_log_level,
.flush_cpucp_log = scmi_flush_cpucp_log,
.get_timestamp = scmi_get_timestamp,
};
static int scmi_memlat_vendor_protocol_init(const struct scmi_protocol_handle *ph)
{
u32 version;
ph->xops->version_get(ph, &version);
dev_dbg(ph->dev, "memlat version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
return 0;
}
static const struct scmi_protocol scmi_memlat_vendor = {
.id = SCMI_PROTOCOL_MEMLAT,
.owner = THIS_MODULE,
.instance_init = &scmi_memlat_vendor_protocol_init,
.ops = &memlat_proto_ops,
};
module_scmi_protocol(scmi_memlat_vendor);
MODULE_DESCRIPTION("SCMI memlat vendor Protocol");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/scmi_pmu.h>
#include "common.h"
enum scmi_c1dcvs_protocol_cmd {
SET_PMU_MAP = 11,
SET_ENABLE_TRACE,
SET_ENABLE_CACHING,
};
struct pmu_map_msg {
uint8_t hw_cntrs[MAX_NUM_CPUS][MAX_CPUCP_EVT];
};
static int scmi_send_pmu_map(const struct scmi_protocol_handle *ph,
void *buf, u32 msg_id)
{
int ret, i, j;
struct scmi_xfer *t;
struct pmu_map_msg *msg;
uint8_t *src = buf;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg),
&t);
if (ret)
return ret;
msg = t->tx.buf;
for (i = 0; i < MAX_NUM_CPUS; i++)
for (j = 0; j < MAX_CPUCP_EVT; j++)
msg->hw_cntrs[i][j] = *((src + i * MAX_CPUCP_EVT) + j);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_send_tunable_pmu(const struct scmi_protocol_handle *ph,
void *buf, u32 msg_id)
{
int ret;
struct scmi_xfer *t;
unsigned int *msg;
unsigned int *src = buf;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg),
&t);
if (ret)
return ret;
msg = t->tx.buf;
*msg = cpu_to_le32(*src);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_pmu_map(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_send_pmu_map(ph, buf, SET_PMU_MAP);
}
static int scmi_set_enable_trace(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_send_tunable_pmu(ph, buf, SET_ENABLE_TRACE);
}
static int scmi_set_caching_enable(const struct scmi_protocol_handle *ph, void *buf)
{
return scmi_send_tunable_pmu(ph, buf, SET_ENABLE_CACHING);
}
static struct scmi_pmu_vendor_ops pmu_config_ops = {
.set_pmu_map = scmi_pmu_map,
.set_enable_trace = scmi_set_enable_trace,
.set_cache_enable = scmi_set_caching_enable,
};
static int scmi_pmu_protocol_init(const struct scmi_protocol_handle *ph)
{
u32 version;
ph->xops->version_get(ph, &version);
dev_dbg(ph->dev, "version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
return 0;
}
static const struct scmi_protocol scmi_pmu = {
.id = SCMI_PMU_PROTOCOL,
.owner = THIS_MODULE,
.instance_init = &scmi_pmu_protocol_init,
.ops = &pmu_config_ops,
};
module_scmi_protocol(scmi_pmu);
MODULE_DESCRIPTION("SCMI PMU vendor Protocol");
MODULE_LICENSE("GPL");