ARM SCMI updates for v5.10

Couple of main additions: SCMI system protocol support and ability to
 build SCMI driver as a single module which is needed by some transports
 like virtio as they may not be ready early during the boot. This also
 includes constification of scmi ops and related function pointers.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEunHlEgbzHrJD3ZPhAEG6vDF+4pgFAl9fEboACgkQAEG6vDF+
 4pgPrQ//b7sHrgiWPu1tKHJFnpZ/fvfxfk5MsjUo+/p1v2XMfBlCanYf6rb31Dkr
 UhN7QjRNklehQvqYm1BkDFOijFZBQfyKZ+Yva+w0XGi/5yQTA0sHUj/01NSiCWsZ
 HAZoCSUrMrrpOl2nLxcM8ZLD6WQfVY+rHJzeLmPl5O8yXWQTPdLuilQZcA9kW9TP
 xuegGSCcvtiBFKNXSsFiAB/SnwEoUR9Y3DgIWGUkFLXg4E59yMMYx5R0ioUc1C1P
 xpQpraWOgzORjKtBMrXO0BTLPyUTkNc8kIJINu8QFZznZN7MCEVI0PIHOMW3Iv/n
 /PDqhD2RsQAgFV/2cLuQU6AhPjRS3q7lVRrZnvd8Ox329YcIyiyIbLzB+qI5ybM7
 Pq15T2w8/KElikO+jw2Y0MVVc9uXHO+3Dq8OKzS43gOH/OakDkqnpnaLYNGJ2nMb
 /lBCKlzS3ZEnPN1QQiWIQXRKJnuimQifD5WB3ubvAMge7Ctu4/aqTa2RHl4kGuEQ
 VXrTuy4BMXkakKcuYxkGi4aHf1XNclRQrietvz2mw7Ufv5BSR2CYgTm8H6AUxVRl
 FbEajHlb9YjGIVVy2sOVhG2cmBAA/rZuOcgeqDd4eseuEgTWD08IMDYqhWj2PQRA
 Yctr4JQdKddiXkWNbrAtBbfZuirZEZ9L79ijnDek8AkJ9vZ5CSg=
 =qToH
 -----END PGP SIGNATURE-----

Merge tag 'scmi-updates-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/drivers

ARM SCMI updates for v5.10

Couple of main additions: SCMI system protocol support and ability to
build SCMI driver as a single module which is needed by some transports
like virtio as they may not be ready early during the boot. This also
includes constification of scmi ops and related function pointers.

* tag 'scmi-updates-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Enable building as a single module
  firmware: arm_scmi: Move scmi protocols registration into the driver
  firmware: arm_scmi: Move scmi bus init and exit calls into the driver
  firmware: smccc: Export both smccc functions
  firmware: arm_scmi: Fix NULL pointer dereference in mailbox_chan_free
  firmware: arm_scmi: Add SCMI device for system power protocol
  firmware: arm_scmi: Add system power protocol support
  firmware: arm_scmi: Constify static scmi-ops
  firmware: arm_scmi: Constify ops pointers in scmi_handle
  cpufreq: arm_scmi: Constify scmi_perf_ops pointers

Link: https://lore.kernel.org/r/20200914075018.2rvytvghxyutcbk4@bogus
Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson 2020-09-15 08:10:40 -07:00
commit 8119f4b91d
18 changed files with 238 additions and 59 deletions

View File

@ -29,7 +29,7 @@ static const struct scmi_handle *handle;
static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
struct scmi_perf_ops *perf_ops = handle->perf_ops;
const struct scmi_perf_ops *perf_ops = handle->perf_ops;
struct scmi_data *priv = policy->driver_data;
unsigned long rate;
int ret;
@ -50,7 +50,7 @@ scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
{
int ret;
struct scmi_data *priv = policy->driver_data;
struct scmi_perf_ops *perf_ops = handle->perf_ops;
const struct scmi_perf_ops *perf_ops = handle->perf_ops;
u64 freq = policy->freq_table[index].frequency;
ret = perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false);
@ -64,7 +64,7 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq)
{
struct scmi_data *priv = policy->driver_data;
struct scmi_perf_ops *perf_ops = handle->perf_ops;
const struct scmi_perf_ops *perf_ops = handle->perf_ops;
if (!perf_ops->freq_set(handle, priv->domain_id,
target_freq * 1000, true)) {

View File

@ -7,7 +7,7 @@
menu "Firmware Drivers"
config ARM_SCMI_PROTOCOL
bool "ARM System Control and Management Interface (SCMI) Message Protocol"
tristate "ARM System Control and Management Interface (SCMI) Message Protocol"
depends on ARM || ARM64 || COMPILE_TEST
depends on MAILBOX
help

View File

@ -22,7 +22,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/
obj-y += arm_scmi/
obj-y += broadcom/
obj-y += meson/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/

View File

@ -1,9 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
scmi-bus-y = bus.o
scmi-driver-y = driver.o notify.o
scmi-transport-y = shmem.o
scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o
scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
$(scmi-transport-y)
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o

View File

@ -230,7 +230,7 @@ static void scmi_devices_unregister(void)
bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister);
}
static int __init scmi_bus_init(void)
int __init scmi_bus_init(void)
{
int retval;
@ -240,12 +240,10 @@ static int __init scmi_bus_init(void)
return retval;
}
subsys_initcall(scmi_bus_init);
static void __exit scmi_bus_exit(void)
void __exit scmi_bus_exit(void)
{
scmi_devices_unregister();
bus_unregister(&scmi_bus_type);
ida_destroy(&scmi_bus_id);
}
module_exit(scmi_bus_exit);

View File

@ -318,7 +318,7 @@ scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id)
return clk;
}
static struct scmi_clk_ops clk_ops = {
static const struct scmi_clk_ops clk_ops = {
.count_get = scmi_clock_count_get,
.info_get = scmi_clock_info_get,
.rate_get = scmi_clock_rate_get,
@ -364,9 +364,4 @@ static int scmi_clock_protocol_init(struct scmi_handle *handle)
return 0;
}
static int __init scmi_clock_init(void)
{
return scmi_protocol_register(SCMI_PROTOCOL_CLOCK,
&scmi_clock_protocol_init);
}
subsys_initcall(scmi_clock_init);
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_CLOCK, clock)

View File

@ -156,6 +156,30 @@ void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
int scmi_base_protocol_init(struct scmi_handle *h);
int __init scmi_bus_init(void);
void __exit scmi_bus_exit(void);
#define DECLARE_SCMI_REGISTER_UNREGISTER(func) \
int __init scmi_##func##_register(void); \
void __exit scmi_##func##_unregister(void)
DECLARE_SCMI_REGISTER_UNREGISTER(clock);
DECLARE_SCMI_REGISTER_UNREGISTER(perf);
DECLARE_SCMI_REGISTER_UNREGISTER(power);
DECLARE_SCMI_REGISTER_UNREGISTER(reset);
DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
DECLARE_SCMI_REGISTER_UNREGISTER(system);
#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(id, name) \
int __init scmi_##name##_register(void) \
{ \
return scmi_protocol_register((id), &scmi_##name##_protocol_init); \
} \
\
void __exit scmi_##name##_unregister(void) \
{ \
scmi_protocol_unregister((id)); \
}
/* SCMI Transport */
/**
* struct scmi_chan_info - Structure representing a SCMI channel information
@ -210,7 +234,7 @@ struct scmi_transport_ops {
* @max_msg_size: Maximum size of data per message that can be handled.
*/
struct scmi_desc {
struct scmi_transport_ops *ops;
const struct scmi_transport_ops *ops;
int max_rx_timeout_ms;
int max_msg;
int max_msg_size;

View File

@ -730,6 +730,7 @@ struct scmi_prot_devnames {
static struct scmi_prot_devnames devnames[] = {
{ SCMI_PROTOCOL_POWER, { "genpd" },},
{ SCMI_PROTOCOL_SYSTEM, { "syspower" },},
{ SCMI_PROTOCOL_PERF, { "cpufreq" },},
{ SCMI_PROTOCOL_CLOCK, { "clocks" },},
{ SCMI_PROTOCOL_SENSOR, { "hwmon" },},
@ -928,7 +929,35 @@ static struct platform_driver scmi_driver = {
.remove = scmi_remove,
};
module_platform_driver(scmi_driver);
static int __init scmi_driver_init(void)
{
scmi_bus_init();
scmi_clock_register();
scmi_perf_register();
scmi_power_register();
scmi_reset_register();
scmi_sensors_register();
scmi_system_register();
return platform_driver_register(&scmi_driver);
}
subsys_initcall(scmi_driver_init);
static void __exit scmi_driver_exit(void)
{
scmi_bus_exit();
scmi_clock_unregister();
scmi_perf_unregister();
scmi_power_unregister();
scmi_reset_unregister();
scmi_sensors_unregister();
scmi_system_unregister();
platform_driver_unregister(&scmi_driver);
}
module_exit(scmi_driver_exit);
MODULE_ALIAS("platform: arm-scmi");
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");

View File

@ -110,7 +110,7 @@ static int mailbox_chan_free(int id, void *p, void *data)
struct scmi_chan_info *cinfo = p;
struct scmi_mailbox *smbox = cinfo->transport_info;
if (!IS_ERR(smbox->chan)) {
if (smbox && !IS_ERR(smbox->chan)) {
mbox_free_channel(smbox->chan);
cinfo->transport_info = NULL;
smbox->chan = NULL;
@ -181,7 +181,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
return shmem_poll_done(smbox->shmem, xfer);
}
static struct scmi_transport_ops scmi_mailbox_ops = {
static const struct scmi_transport_ops scmi_mailbox_ops = {
.chan_available = mailbox_chan_available,
.chan_setup = mailbox_chan_setup,
.chan_free = mailbox_chan_free,

View File

@ -1421,7 +1421,7 @@ static void scmi_protocols_late_init(struct work_struct *work)
* notify_ops are attached to the handle so that can be accessed
* directly from an scmi_driver to register its own notifiers.
*/
static struct scmi_notify_ops notify_ops = {
static const struct scmi_notify_ops notify_ops = {
.register_event_notifier = scmi_register_notifier,
.unregister_event_notifier = scmi_unregister_notifier,
};

View File

@ -748,7 +748,7 @@ static bool scmi_fast_switch_possible(const struct scmi_handle *handle,
return dom->fc_info && dom->fc_info->level_set_addr;
}
static struct scmi_perf_ops perf_ops = {
static const struct scmi_perf_ops perf_ops = {
.limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get,
.level_set = scmi_perf_level_set,
@ -890,9 +890,4 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
return 0;
}
static int __init scmi_perf_init(void)
{
return scmi_protocol_register(SCMI_PROTOCOL_PERF,
&scmi_perf_protocol_init);
}
subsys_initcall(scmi_perf_init);
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_PERF, perf)

View File

@ -184,7 +184,7 @@ static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain)
return dom->name;
}
static struct scmi_power_ops power_ops = {
static const struct scmi_power_ops power_ops = {
.num_domains_get = scmi_power_num_domains_get,
.name_get = scmi_power_name_get,
.state_set = scmi_power_state_set,
@ -301,9 +301,4 @@ static int scmi_power_protocol_init(struct scmi_handle *handle)
return 0;
}
static int __init scmi_power_init(void)
{
return scmi_protocol_register(SCMI_PROTOCOL_POWER,
&scmi_power_protocol_init);
}
subsys_initcall(scmi_power_init);
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_POWER, power)

View File

@ -194,7 +194,7 @@ scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET);
}
static struct scmi_reset_ops reset_ops = {
static const struct scmi_reset_ops reset_ops = {
.num_domains_get = scmi_reset_num_domains_get,
.name_get = scmi_reset_name_get,
.latency_get = scmi_reset_latency_get,
@ -313,9 +313,4 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle)
return 0;
}
static int __init scmi_reset_init(void)
{
return scmi_protocol_register(SCMI_PROTOCOL_RESET,
&scmi_reset_protocol_init);
}
subsys_initcall(scmi_reset_init);
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_RESET, reset)

View File

@ -275,7 +275,7 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle)
return si->num_sensors;
}
static struct scmi_sensor_ops sensor_ops = {
static const struct scmi_sensor_ops sensor_ops = {
.count_get = scmi_sensor_count_get,
.info_get = scmi_sensor_info_get,
.trip_point_config = scmi_sensor_trip_point_config,
@ -365,9 +365,4 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
return 0;
}
static int __init scmi_sensors_init(void)
{
return scmi_protocol_register(SCMI_PROTOCOL_SENSOR,
&scmi_sensors_protocol_init);
}
subsys_initcall(scmi_sensors_init);
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SENSOR, sensors)

View File

@ -137,7 +137,7 @@ smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
return shmem_poll_done(scmi_info->shmem, xfer);
}
static struct scmi_transport_ops scmi_smc_ops = {
static const struct scmi_transport_ops scmi_smc_ops = {
.chan_available = smc_chan_available,
.chan_setup = smc_chan_setup,
.chan_free = smc_chan_free,

View File

@ -0,0 +1,131 @@
// SPDX-License-Identifier: GPL-2.0
/*
* System Control and Management Interface (SCMI) System Power Protocol
*
* Copyright (C) 2020 ARM Ltd.
*/
#define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt
#include <linux/scmi_protocol.h>
#include "common.h"
#include "notify.h"
#define SCMI_SYSTEM_NUM_SOURCES 1
enum scmi_system_protocol_cmd {
SYSTEM_POWER_STATE_NOTIFY = 0x5,
};
struct scmi_system_power_state_notify {
__le32 notify_enable;
};
struct scmi_system_power_state_notifier_payld {
__le32 agent_id;
__le32 flags;
__le32 system_state;
};
struct scmi_system_info {
u32 version;
};
static int scmi_system_request_notify(const struct scmi_handle *handle,
bool enable)
{
int ret;
struct scmi_xfer *t;
struct scmi_system_power_state_notify *notify;
ret = scmi_xfer_get_init(handle, SYSTEM_POWER_STATE_NOTIFY,
SCMI_PROTOCOL_SYSTEM, sizeof(*notify), 0, &t);
if (ret)
return ret;
notify = t->tx.buf;
notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
ret = scmi_do_xfer(handle, t);
scmi_xfer_put(handle, t);
return ret;
}
static int scmi_system_set_notify_enabled(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
ret = scmi_system_request_notify(handle, enable);
if (ret)
pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret);
return ret;
}
static void *scmi_system_fill_custom_report(const struct scmi_handle *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
const struct scmi_system_power_state_notifier_payld *p = payld;
struct scmi_system_power_state_notifier_report *r = report;
if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER ||
sizeof(*p) != payld_sz)
return NULL;
r->timestamp = timestamp;
r->agent_id = le32_to_cpu(p->agent_id);
r->flags = le32_to_cpu(p->flags);
r->system_state = le32_to_cpu(p->system_state);
*src_id = 0;
return r;
}
static const struct scmi_event system_events[] = {
{
.id = SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER,
.max_payld_sz =
sizeof(struct scmi_system_power_state_notifier_payld),
.max_report_sz =
sizeof(struct scmi_system_power_state_notifier_report),
},
};
static const struct scmi_event_ops system_event_ops = {
.set_notify_enabled = scmi_system_set_notify_enabled,
.fill_custom_report = scmi_system_fill_custom_report,
};
static int scmi_system_protocol_init(struct scmi_handle *handle)
{
u32 version;
struct scmi_system_info *pinfo;
scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version);
dev_dbg(handle->dev, "System Power Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
scmi_register_protocol_events(handle,
SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ,
&system_event_ops,
system_events,
ARRAY_SIZE(system_events),
SCMI_SYSTEM_NUM_SOURCES);
pinfo->version = version;
handle->system_priv = pinfo;
return 0;
}
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SYSTEM, system)

View File

@ -24,8 +24,10 @@ enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
return smccc_conduit;
}
EXPORT_SYMBOL_GPL(arm_smccc_1_1_get_conduit);
u32 arm_smccc_get_version(void)
{
return smccc_version;
}
EXPORT_SYMBOL_GPL(arm_smccc_get_version);

View File

@ -279,12 +279,12 @@ struct scmi_notify_ops {
struct scmi_handle {
struct device *dev;
struct scmi_revision_info *version;
struct scmi_perf_ops *perf_ops;
struct scmi_clk_ops *clk_ops;
struct scmi_power_ops *power_ops;
struct scmi_sensor_ops *sensor_ops;
struct scmi_reset_ops *reset_ops;
struct scmi_notify_ops *notify_ops;
const struct scmi_perf_ops *perf_ops;
const struct scmi_clk_ops *clk_ops;
const struct scmi_power_ops *power_ops;
const struct scmi_sensor_ops *sensor_ops;
const struct scmi_reset_ops *reset_ops;
const struct scmi_notify_ops *notify_ops;
/* for protocol internal use */
void *perf_priv;
void *clk_priv;
@ -292,6 +292,7 @@ struct scmi_handle {
void *sensor_priv;
void *reset_priv;
void *notify_priv;
void *system_priv;
};
enum scmi_std_protocol {
@ -304,6 +305,15 @@ enum scmi_std_protocol {
SCMI_PROTOCOL_RESET = 0x16,
};
enum scmi_system_events {
SCMI_SYSTEM_SHUTDOWN,
SCMI_SYSTEM_COLDRESET,
SCMI_SYSTEM_WARMRESET,
SCMI_SYSTEM_POWERUP,
SCMI_SYSTEM_SUSPEND,
SCMI_SYSTEM_MAX
};
struct scmi_device {
u32 id;
u8 protocol_id;
@ -335,7 +345,7 @@ struct scmi_driver {
#define to_scmi_driver(d) container_of(d, struct scmi_driver, driver)
#ifdef CONFIG_ARM_SCMI_PROTOCOL
#if IS_REACHABLE(CONFIG_ARM_SCMI_PROTOCOL)
int scmi_driver_register(struct scmi_driver *driver,
struct module *owner, const char *mod_name);
void scmi_driver_unregister(struct scmi_driver *driver);
@ -378,6 +388,7 @@ enum scmi_notification_events {
SCMI_EVENT_SENSOR_TRIP_POINT_EVENT = 0x0,
SCMI_EVENT_RESET_ISSUED = 0x0,
SCMI_EVENT_BASE_ERROR_EVENT = 0x0,
SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER = 0x0,
};
struct scmi_power_state_changed_report {
@ -387,6 +398,13 @@ struct scmi_power_state_changed_report {
unsigned int power_state;
};
struct scmi_system_power_state_notifier_report {
ktime_t timestamp;
unsigned int agent_id;
unsigned int flags;
unsigned int system_state;
};
struct scmi_perf_limits_report {
ktime_t timestamp;
unsigned int agent_id;