Hi all,
The current SCMI implementation does not provide an interface to easily
develop and include a custom vendor protocol implementation as prescribed
by the SCMI standard, also because, there is not currently any custom
protocol in the upstream to justify the development of a custom interface
and its maintenance.
Moreover the current interface exposes protocol operations to the SCMI
driver users attaching per-protocol operations directly to the handle
structure, which, in this way, tends to grow indefinitely for each new
protocol addition.
Beside this, protocols private data are also exposed via handle *_priv
pointers, making such private data accessible also to the SCMI drivers
even if neither really needed nor advisable.
This series wants to address this by simplifying the SCMI protocols
interface and reducing it, roughly, to these common generic operations:
handle->devm_get_ops() / handle->devm_put_ops() / handle->notify_ops()
All protocols' private data pointers are removed from handle too and made
accessible only to the protocols code through dedicated internal helpers.
The concept of protocol handle is introduced in the SCMI protocol code
to represent a protocol instance initialized against a specific SCMI
instance (handle), so that all the new protocol code uses such protocol
handles wherever previously SCMI handle was used: this enable tighter
control of what is exposed to the protocol code vs the SCMI drivers.
Moreover protocol initialization is moved away from device probe and now
happens on demand when the first user shows up (first .get_ops), while
de-initialization is performed once the last user of the protocol (even in
terms of notifications) is gone, with the SCMI core taking care to perform
all the needed underlying resource accounting.
This way any new future standard or custom protocol implementation will
expose a common unified interface which does not need to be extended
endlessly: no need to maintain a custom interface only for vendor protos.
SCMI drivers written on top of standard or custom protocols will use this
same common interface to access any protocol operations.
All existent upstream SCMI drivers are converted to this new interface.
Patch [4/37] ("firmware: arm_scmi: introduce bare get/put protocols ops")
is marked as RFC because I was not sure if this non devres methods are
really needed (probbaly not).
In order to make this migration painless and to avoid the need of a big
un-mergeable jumbo patch touching all over the protocols and drivers (like
it was in v2), since v3 the migration process has been heavily split with a
bit of transient code added along the way (to preserve bisectability) and
finally removed towards the ends of the series.
Protocols and SCMI drivers migration to the new interface happens along
patches 11->30.
Note that in v4 all the related SCMI drivers maintainers are still NOT
CC'ed given I am still sort of gather consensus about the interface itself.
Leveraging this new centralized and common initialization flow we took
care also to refactor and simplify protocol-events registration and remove
*notify_priv from the handle interface making it accessible only to the
notification core.
Patch 36 builds on top of this new interface and introduces a mechanism to
define an SCMI protocol as a full blown module (possibly loadable) while
leaving the core dealing with proper resource accounting.
Standard protocols are still kept as builtins in this series, though.
Finally, patch 37 introduces dynamic SCMI devices creation to avoid having
to update the static module device table in the core each time a new driver
is added.
The whole SCMI stack can still be built alternatively as a module (including
all the standard protocols in scmi-module.ko in that case).
On top of this series an example SCMI Custom protocol 0x99 and related
SCMI Custom Dummy driver has been built and it is available at [1] as a
series of DEBUG patches on top this same series.
The series is currently based on for-next/scmi [2] on top of:
commit 6054d97ab512 MAINTAINERS: Update ARM SCMI entry
Any feedback welcome.
Thanks,
Cristian
---
v3 --> v4
- rebased on sudeep/for-next/scmi v5.11-rc1
- added a few comments more
v2 --> v3
- added dynamic SCMI devices creation (getting rid of static device table)
- heavy split of protocols and drivers migrations to the new interface
- rebased on top of next-20201201 so migrating also:
+ SCMIv3.0 Voltage Domain protocol & SCMI Regulator
+ SCMIv3.0 Sensor Extensions
v1 --> v2
- rebased on for-next/scmi v5.10-rc1
- introduced protocol handles
- added devres managed devm_ variant for protocols operations
- made all scmi_protocol refs const
- introduced IDR to handle protocols instead of static array
- refactored code around fast path
[1]:https://gitlab.arm.com/linux-arm/linux-cm/-/commits/scmi_modules_ext_V4/
[2]:https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/log/?h=for-next/scmi
Cristian Marussi (37):
firmware: arm_scmi: review protocol registration interface
firmware: arm_scmi: introduce protocol handle definitions
firmware: arm_scmi: introduce devres get/put protocols operations
[RFC] firmware: arm_scmi: introduce bare get/put protocols ops
firmware: arm_scmi: make notifications aware of protocols users
firmware: arm_scmi: introduce new devres notification ops
firmware: arm_scmi: refactor events registration
firmware: arm_scmi: convert events registration to protocol handles
firmware: arm_scmi: add new protocol handle core xfer ops
firmware: arm_scmi: add helper to access revision area memory
firmware: arm_scmi: port Base protocol to new interface
firmware: arm_scmi: port Perf protocol to new protocols interface
cpufreq: scmi: port driver to the new scmi_perf_proto_ops interface
firmware: arm_scmi: remove legacy scmi_perf_ops protocol interface
firmware: arm_scmi: port Power protocol to new protocols interface
firmware: arm_scmi: port GenPD driver to the new scmi_power_proto_ops
interface
firmware: arm_scmi: remove legacy scmi_power_ops protocol interface
firmware: arm_scmi: port Clock protocol to new protocols interface
clk: scmi: port driver to the new scmi_clk_proto_ops interface
firmware: arm_scmi: remove legacy scmi_clk_ops protocol interface
firmware: arm_scmi: port Reset protocol to new protocols interface
reset: reset-scmi: port driver to the new scmi_reset_proto_ops
interface
firmware: arm_scmi: remove legacy scmi_reset_ops protocol interface
firmware: arm_scmi: port Sensor protocol to new protocols interface
hwmon: (scmi) port driver to the new scmi_sensor_proto_ops interface
firmware: arm_scmi: remove legacy scmi_sensor_ops protocol interface
firmware: arm_scmi: port SystemPower protocol to new protocols
interface
firmware: arm_scmi: port Voltage protocol to new protocols interface
regulator: scmi: port driver to the new scmi_voltage_proto_ops
interface
firmware: arm_scmi: remove legacy scmi_voltage_ops protocol interface
firmware: arm_scmi: make references to handle const
firmware: arm_scmi: cleanup legacy protocol init code
firmware: arm_scmi: cleanup unused core xfer wrappers
firmware: arm_scmi: cleanup events registration transient code
firmware: arm_scmi: make notify_priv really private
firmware: arm_scmi: add protocol modularization support
firmware: arm_scmi: add dynamic scmi devices creation
drivers/clk/clk-scmi.c | 27 +-
drivers/cpufreq/scmi-cpufreq.c | 37 +-
drivers/firmware/arm_scmi/base.c | 140 ++--
drivers/firmware/arm_scmi/bus.c | 100 ++-
drivers/firmware/arm_scmi/clock.c | 129 ++--
drivers/firmware/arm_scmi/common.h | 117 +++-
drivers/firmware/arm_scmi/driver.c | 780 +++++++++++++++++++--
drivers/firmware/arm_scmi/notify.c | 297 ++++++--
drivers/firmware/arm_scmi/notify.h | 38 +-
drivers/firmware/arm_scmi/perf.c | 262 +++----
drivers/firmware/arm_scmi/power.c | 134 ++--
drivers/firmware/arm_scmi/reset.c | 146 ++--
drivers/firmware/arm_scmi/scmi_pm_domain.c | 26 +-
drivers/firmware/arm_scmi/sensors.c | 230 +++---
drivers/firmware/arm_scmi/system.c | 61 +-
drivers/firmware/arm_scmi/voltage.c | 122 ++--
drivers/hwmon/scmi-hwmon.c | 24 +-
drivers/regulator/scmi-regulator.c | 39 +-
drivers/reset/reset-scmi.c | 33 +-
include/linux/scmi_protocol.h | 191 ++---
20 files changed, 2024 insertions(+), 909 deletions(-)
--
2.17.1
Convert internals of protocol implementation to use protocol handles and
expose a new protocol operations interface for SCMI driver using the new
get/put common operations, while keeping the old handle->voltage_ops still
around to ease transition.
Remove handle->voltage_priv now unused.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/voltage.c | 179 ++++++++++++++++++----------
include/linux/scmi_protocol.h | 24 ++--
2 files changed, 136 insertions(+), 67 deletions(-)
diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c
index 8145ee79bb19..7b390426028e 100644
--- a/drivers/firmware/arm_scmi/voltage.c
+++ b/drivers/firmware/arm_scmi/voltage.c
@@ -59,23 +59,23 @@ struct voltage_info {
struct scmi_voltage_info *domains;
};
-static int scmi_protocol_attributes_get(const struct scmi_handle *handle,
+static int scmi_protocol_attributes_get(const struct scmi_protocol_handle *ph,
struct voltage_info *vinfo)
{
int ret;
struct scmi_xfer *t;
- ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
- SCMI_PROTOCOL_VOLTAGE, 0, sizeof(__le32), &t);
+ ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
+ sizeof(__le32), &t);
if (ret)
return ret;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
vinfo->num_domains =
NUM_VOLTAGE_DOMAINS(get_unaligned_le32(t->rx.buf));
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -109,24 +109,23 @@ static int scmi_init_voltage_levels(struct device *dev,
return 0;
}
-static int scmi_voltage_descriptors_get(const struct scmi_handle *handle,
+static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
struct voltage_info *vinfo)
{
int ret, dom;
struct scmi_xfer *td, *tl;
- struct device *dev = handle->dev;
+ struct device *dev = ph->dev;
struct scmi_msg_resp_domain_attributes *resp_dom;
struct scmi_msg_resp_describe_levels *resp_levels;
- ret = scmi_xfer_get_init(handle, VOLTAGE_DOMAIN_ATTRIBUTES,
- SCMI_PROTOCOL_VOLTAGE, sizeof(__le32),
- sizeof(*resp_dom), &td);
+ ret = ph->xops->xfer_get_init(ph, VOLTAGE_DOMAIN_ATTRIBUTES,
+ sizeof(__le32), sizeof(*resp_dom), &td);
if (ret)
return ret;
resp_dom = td->rx.buf;
- ret = scmi_xfer_get_init(handle, VOLTAGE_DESCRIBE_LEVELS,
- SCMI_PROTOCOL_VOLTAGE, sizeof(__le64), 0, &tl);
+ ret = ph->xops->xfer_get_init(ph, VOLTAGE_DESCRIBE_LEVELS,
+ sizeof(__le64), 0, &tl);
if (ret)
goto outd;
resp_levels = tl->rx.buf;
@@ -139,7 +138,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle,
/* Retrieve domain attributes at first ... */
put_unaligned_le32(dom, td->tx.buf);
- ret = scmi_do_xfer(handle, td);
+ ret = ph->xops->do_xfer(ph, td);
/* Skip domain on comms error */
if (ret)
continue;
@@ -157,7 +156,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle,
cmd->domain_id = cpu_to_le32(v->id);
cmd->level_index = desc_index;
- ret = scmi_do_xfer(handle, tl);
+ ret = ph->xops->do_xfer(ph, tl);
if (ret)
break;
@@ -176,7 +175,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle,
}
if (desc_index + num_returned > v->num_levels) {
- dev_err(handle->dev,
+ dev_err(ph->dev,
"No. of voltage levels can't exceed %d\n",
v->num_levels);
ret = -EINVAL;
@@ -195,7 +194,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle,
desc_index += num_returned;
- scmi_reset_rx_to_maxsz(handle, tl);
+ ph->xops->reset_rx_to_maxsz(ph, tl);
/* check both to avoid infinite loop due to buggy fw */
} while (num_returned && num_remaining);
@@ -204,55 +203,52 @@ static int scmi_voltage_descriptors_get(const struct scmi_handle *handle,
devm_kfree(dev, v->levels_uv);
}
- scmi_reset_rx_to_maxsz(handle, td);
+ ph->xops->reset_rx_to_maxsz(ph, td);
}
- scmi_xfer_put(handle, tl);
+ ph->xops->xfer_put(ph, tl);
outd:
- scmi_xfer_put(handle, td);
+ ph->xops->xfer_put(ph, td);
return ret;
}
-static int __scmi_voltage_get_u32(const struct scmi_handle *handle,
+static int __scmi_voltage_get_u32(const struct scmi_protocol_handle *ph,
u8 cmd_id, u32 domain_id, u32 *value)
{
int ret;
struct scmi_xfer *t;
- struct voltage_info *vinfo = handle->voltage_priv;
+ struct voltage_info *vinfo = ph->get_priv(ph);
if (domain_id >= vinfo->num_domains)
return -EINVAL;
- ret = scmi_xfer_get_init(handle, cmd_id,
- SCMI_PROTOCOL_VOLTAGE,
- sizeof(__le32), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(__le32), 0, &t);
if (ret)
return ret;
put_unaligned_le32(domain_id, t->tx.buf);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
*value = get_unaligned_le32(t->rx.buf);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_voltage_config_set(const struct scmi_handle *handle,
+static int scmi_voltage_config_set(const struct scmi_protocol_handle *ph,
u32 domain_id, u32 config)
{
int ret;
struct scmi_xfer *t;
- struct voltage_info *vinfo = handle->voltage_priv;
+ struct voltage_info *vinfo = ph->get_priv(ph);
struct scmi_msg_cmd_config_set *cmd;
if (domain_id >= vinfo->num_domains)
return -EINVAL;
- ret = scmi_xfer_get_init(handle, VOLTAGE_CONFIG_SET,
- SCMI_PROTOCOL_VOLTAGE,
- sizeof(*cmd), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, VOLTAGE_CONFIG_SET,
+ sizeof(*cmd), 0, &t);
if (ret)
return ret;
@@ -260,33 +256,50 @@ static int scmi_voltage_config_set(const struct scmi_handle *handle,
cmd->domain_id = cpu_to_le32(domain_id);
cmd->config = cpu_to_le32(config & GENMASK(3, 0));
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_voltage_config_get(const struct scmi_handle *handle,
+static int __scmi_voltage_config_set(const struct scmi_handle *handle,
+ u32 domain_id, u32 config)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
+
+ return scmi_voltage_config_set(ph, domain_id, config);
+}
+
+static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph,
u32 domain_id, u32 *config)
{
- return __scmi_voltage_get_u32(handle, VOLTAGE_CONFIG_GET,
+ return __scmi_voltage_get_u32(ph, VOLTAGE_CONFIG_GET,
domain_id, config);
}
-static int scmi_voltage_level_set(const struct scmi_handle *handle,
+static int __scmi_voltage_config_get(const struct scmi_handle *handle,
+ u32 domain_id, u32 *config)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
+
+ return scmi_voltage_config_get(ph, domain_id, config);
+}
+
+static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
u32 domain_id, u32 flags, s32 volt_uV)
{
int ret;
struct scmi_xfer *t;
- struct voltage_info *vinfo = handle->voltage_priv;
+ struct voltage_info *vinfo = ph->get_priv(ph);
struct scmi_msg_cmd_level_set *cmd;
if (domain_id >= vinfo->num_domains)
return -EINVAL;
- ret = scmi_xfer_get_init(handle, VOLTAGE_LEVEL_SET,
- SCMI_PROTOCOL_VOLTAGE,
- sizeof(*cmd), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, VOLTAGE_LEVEL_SET,
+ sizeof(*cmd), 0, &t);
if (ret)
return ret;
@@ -295,23 +308,41 @@ static int scmi_voltage_level_set(const struct scmi_handle *handle,
cmd->flags = cpu_to_le32(flags);
cmd->voltage_level = cpu_to_le32(volt_uV);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_voltage_level_get(const struct scmi_handle *handle,
+static int __scmi_voltage_level_set(const struct scmi_handle *handle,
+ u32 domain_id, u32 flags, s32 volt_uV)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
+
+ return scmi_voltage_level_set(ph, domain_id, flags, volt_uV);
+}
+
+static int scmi_voltage_level_get(const struct scmi_protocol_handle *ph,
u32 domain_id, s32 *volt_uV)
{
- return __scmi_voltage_get_u32(handle, VOLTAGE_LEVEL_GET,
+ return __scmi_voltage_get_u32(ph, VOLTAGE_LEVEL_GET,
domain_id, (u32 *)volt_uV);
}
+static int __scmi_voltage_level_get(const struct scmi_handle *handle,
+ u32 domain_id, s32 *volt_uV)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
+
+ return scmi_voltage_level_get(ph, domain_id, volt_uV);
+}
+
static const struct scmi_voltage_info * __must_check
-scmi_voltage_info_get(const struct scmi_handle *handle, u32 domain_id)
+scmi_voltage_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
{
- struct voltage_info *vinfo = handle->voltage_priv;
+ struct voltage_info *vinfo = ph->get_priv(ph);
if (domain_id >= vinfo->num_domains ||
!vinfo->domains[domain_id].num_levels)
@@ -320,14 +351,40 @@ scmi_voltage_info_get(const struct scmi_handle *handle, u32 domain_id)
return vinfo->domains + domain_id;
}
-static int scmi_voltage_domains_num_get(const struct scmi_handle *handle)
+static const struct scmi_voltage_info * __must_check
+__scmi_voltage_info_get(const struct scmi_handle *handle, u32 domain_id)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
+
+ return scmi_voltage_info_get(ph, domain_id);
+}
+
+static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle *ph)
{
- struct voltage_info *vinfo = handle->voltage_priv;
+ struct voltage_info *vinfo = ph->get_priv(ph);
return vinfo->num_domains;
}
+static int __scmi_voltage_domains_num_get(const struct scmi_handle *handle)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
+
+ return scmi_voltage_domains_num_get(ph);
+}
+
static struct scmi_voltage_ops voltage_ops = {
+ .num_domains_get = __scmi_voltage_domains_num_get,
+ .info_get = __scmi_voltage_info_get,
+ .config_set = __scmi_voltage_config_set,
+ .config_get = __scmi_voltage_config_get,
+ .level_set = __scmi_voltage_level_set,
+ .level_get = __scmi_voltage_level_get,
+};
+
+static struct scmi_voltage_proto_ops voltage_proto_ops = {
.num_domains_get = scmi_voltage_domains_num_get,
.info_get = scmi_voltage_info_get,
.config_set = scmi_voltage_config_set,
@@ -336,51 +393,53 @@ static struct scmi_voltage_ops voltage_ops = {
.level_get = scmi_voltage_level_get,
};
-static int scmi_voltage_protocol_init(struct scmi_handle *handle)
+static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
{
int ret;
u32 version;
struct voltage_info *vinfo;
+ struct scmi_handle *handle;
- ret = scmi_version_get(handle, SCMI_PROTOCOL_VOLTAGE, &version);
+ ret = ph->xops->version_get(ph, &version);
if (ret)
return ret;
- dev_dbg(handle->dev, "Voltage Version %d.%d\n",
+ dev_dbg(ph->dev, "Voltage Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
- vinfo = devm_kzalloc(handle->dev, sizeof(*vinfo), GFP_KERNEL);
+ vinfo = devm_kzalloc(ph->dev, sizeof(*vinfo), GFP_KERNEL);
if (!vinfo)
return -ENOMEM;
vinfo->version = version;
- ret = scmi_protocol_attributes_get(handle, vinfo);
+ ret = scmi_protocol_attributes_get(ph, vinfo);
if (ret)
return ret;
if (vinfo->num_domains) {
- vinfo->domains = devm_kcalloc(handle->dev, vinfo->num_domains,
+ vinfo->domains = devm_kcalloc(ph->dev, vinfo->num_domains,
sizeof(*vinfo->domains),
GFP_KERNEL);
if (!vinfo->domains)
return -ENOMEM;
- ret = scmi_voltage_descriptors_get(handle, vinfo);
+ ret = scmi_voltage_descriptors_get(ph, vinfo);
if (ret)
return ret;
} else {
- dev_warn(handle->dev, "No Voltage domains found.\n");
+ dev_warn(ph->dev, "No Voltage domains found.\n");
}
+ /* Transient code for legacy ops interface */
+ handle = scmi_map_scmi_handle(ph);
handle->voltage_ops = &voltage_ops;
- handle->voltage_priv = vinfo;
- return 0;
+ return ph->set_priv(ph, vinfo);
}
static const struct scmi_protocol scmi_voltage = {
.id = SCMI_PROTOCOL_VOLTAGE,
- .init = &scmi_voltage_protocol_init,
- .ops = &voltage_ops,
+ .init_instance = &scmi_voltage_protocol_init,
+ .ops = &voltage_proto_ops,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage)
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 24972b798f79..a36f3fa33a5f 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -515,7 +515,7 @@ struct scmi_voltage_info {
};
/**
- * struct scmi_voltage_ops - represents the various operations provided
+ * struct scmi_voltage_proto_ops - represents the various operations provided
* by SCMI Voltage Protocol
*
* @num_domains_get: get the count of voltage domains provided by SCMI
@@ -525,14 +525,28 @@ struct scmi_voltage_info {
* @level_set: set the voltage level for the specified domain
* @level_get: get the voltage level of the specified domain
*/
+struct scmi_voltage_proto_ops {
+ int (*num_domains_get)(const struct scmi_protocol_handle *ph);
+ const struct scmi_voltage_info __must_check *(*info_get)
+ (const struct scmi_protocol_handle *ph, u32 domain_id);
+ int (*config_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
+ u32 config);
+#define SCMI_VOLTAGE_ARCH_STATE_OFF 0x0
+#define SCMI_VOLTAGE_ARCH_STATE_ON 0x7
+ int (*config_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
+ u32 *config);
+ int (*level_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
+ u32 flags, s32 volt_uV);
+ int (*level_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
+ s32 *volt_uV);
+};
+
struct scmi_voltage_ops {
int (*num_domains_get)(const struct scmi_handle *handle);
const struct scmi_voltage_info __must_check *(*info_get)
(const struct scmi_handle *handle, u32 domain_id);
int (*config_set)(const struct scmi_handle *handle, u32 domain_id,
u32 config);
-#define SCMI_VOLTAGE_ARCH_STATE_OFF 0x0
-#define SCMI_VOLTAGE_ARCH_STATE_ON 0x7
int (*config_get)(const struct scmi_handle *handle, u32 domain_id,
u32 *config);
int (*level_set)(const struct scmi_handle *handle, u32 domain_id,
@@ -610,8 +624,6 @@ struct scmi_notify_ops {
* dedicated protocol handler
* @put_ops: method to release a protocol
* @notify_ops: pointer to set of notifications related operations
- * @voltage_priv: pointer to private data structure specific to voltage
- * protocol(for internal use only)
* @notify_priv: pointer to private data structure specific to notifications
* (for internal use only)
*/
@@ -631,8 +643,6 @@ struct scmi_handle {
void (*put_ops)(struct scmi_handle *handle, u8 proto);
const struct scmi_notify_ops *notify_ops;
- /* for protocol internal use */
- void *voltage_priv;
void *notify_priv;
};
--
2.17.1
Expose to the SCMI drivers a non managed version of a common protocols API
based on generic get/put methods and protocol handles.
All drivers still keep using the old API, no functional change.
Signed-off-by: Cristian Marussi <[email protected]>
---
These non devres methods are probably not needed, given the devm_ ones are
already provided and any SCMI driver (user of the API) has surely available
an scmi_device reference to use in the devm_ flavour...so the RFC
---
drivers/firmware/arm_scmi/driver.c | 34 ++++++++++++++++++++++++++++++
include/linux/scmi_protocol.h | 8 +++++++
2 files changed, 42 insertions(+)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index fbc3ba1b69f6..e6e760501587 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -710,6 +710,38 @@ void scmi_release_protocol(struct scmi_handle *handle, u8 protocol_id)
mutex_unlock(&info->protocols_mtx);
}
+/**
+ * scmi_get_protocol_operations - Get protocol operations
+ * @handle: A reference to the SCMI platform instance.
+ * @protocol_id: The protocol being requested.
+ * @ph: A pointer reference used to pass back the associated protocol handle.
+ *
+ * Get hold of a protocol accounting for its usage, eventually triggering its
+ * initialization, and returning the protocol specific operations and related
+ * protocol handle which will be used as first argument in most of the protocols
+ * operations methods.
+ *
+ * Return: A reference to the requested protocol operations or error.
+ * Must be checked for errors by caller.
+ */
+static const void __must_check *
+scmi_get_protocol_operations(struct scmi_handle *handle, u8 protocol_id,
+ struct scmi_protocol_handle **ph)
+{
+ struct scmi_protocol_instance *pi;
+
+ if (!ph)
+ return ERR_PTR(-EINVAL);
+
+ pi = scmi_get_protocol_instance(handle, protocol_id);
+ if (IS_ERR(pi))
+ return pi;
+
+ *ph = &pi->ph;
+
+ return pi->proto->ops;
+}
+
void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
u8 *prot_imp)
{
@@ -1078,6 +1110,8 @@ static int scmi_probe(struct platform_device *pdev)
handle->version = &info->version;
handle->devm_get_ops = scmi_devm_get_protocol_ops;
handle->devm_put_ops = scmi_devm_put_protocol_ops;
+ handle->get_ops = scmi_get_protocol_operations;
+ handle->put_ops = scmi_release_protocol;
ret = scmi_txrx_setup(info, dev, SCMI_PROTOCOL_BASE);
if (ret)
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 2fd2fffb4024..8a2bb723602f 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -598,6 +598,9 @@ struct scmi_notify_ops {
* @devm_get_ops: devres managed method to acquire a protocol and get specific
* operations and a dedicated protocol handler
* @devm_put_ops: devres managed method to release a protocol
+ * @get_ops: method to acquire a protocol and get specific operations and a
+ * dedicated protocol handler
+ * @put_ops: method to release a protocol
* @notify_ops: pointer to set of notifications related operations
* @perf_priv: pointer to private data structure specific to performance
* protocol(for internal use only)
@@ -629,6 +632,11 @@ struct scmi_handle {
struct scmi_protocol_handle **ph);
void (*devm_put_ops)(struct scmi_device *sdev, u8 proto);
+ const void __must_check *
+ (*get_ops)(struct scmi_handle *handle, u8 proto,
+ struct scmi_protocol_handle **ph);
+ void (*put_ops)(struct scmi_handle *handle, u8 proto);
+
const struct scmi_notify_ops *notify_ops;
/* for protocol internal use */
void *perf_priv;
--
2.17.1
Now that all the SCMI driver users have been migrated to the new interface
remove the legacy interface and all the transient code.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/power.c | 47 -------------------------------
include/linux/scmi_protocol.h | 11 --------
2 files changed, 58 deletions(-)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index b3d1c032218c..06e3ab17a0eb 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -146,15 +146,6 @@ static int scmi_power_state_set(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_power_state_set(const struct scmi_handle *handle,
- u32 domain, u32 state)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_POWER);
-
- return scmi_power_state_set(ph, domain, state);
-}
-
static int scmi_power_state_get(const struct scmi_protocol_handle *ph,
u32 domain, u32 *state)
{
@@ -175,15 +166,6 @@ static int scmi_power_state_get(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_power_state_get(const struct scmi_handle *handle,
- u32 domain, u32 *state)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_POWER);
-
- return scmi_power_state_get(ph, domain, state);
-}
-
static int scmi_power_num_domains_get(const struct scmi_protocol_handle *ph)
{
struct scmi_power_info *pi = ph->get_priv(ph);
@@ -191,14 +173,6 @@ static int scmi_power_num_domains_get(const struct scmi_protocol_handle *ph)
return pi->num_domains;
}
-static int __scmi_power_num_domains_get(const struct scmi_handle *handle)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_POWER);
-
- return scmi_power_num_domains_get(ph);
-}
-
static char *scmi_power_name_get(const struct scmi_protocol_handle *ph,
u32 domain)
{
@@ -208,22 +182,6 @@ static char *scmi_power_name_get(const struct scmi_protocol_handle *ph,
return dom->name;
}
-static char *__scmi_power_name_get(const struct scmi_handle *handle,
- u32 domain)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_POWER);
-
- return scmi_power_name_get(ph, domain);
-}
-
-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,
- .state_get = __scmi_power_state_get,
-};
-
static const struct scmi_power_proto_ops power_proto_ops = {
.num_domains_get = scmi_power_num_domains_get,
.name_get = scmi_power_name_get,
@@ -324,7 +282,6 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
int domain;
u32 version;
struct scmi_power_info *pinfo;
- struct scmi_handle *handle;
ph->xops->version_get(ph, &version);
@@ -350,10 +307,6 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
pinfo->version = version;
- /* Transient code for legacy ops interface */
- handle = scmi_map_scmi_handle(ph);
- handle->power_ops = &power_ops;
-
return ph->set_priv(ph, pinfo);
}
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index c038994e8adc..73d734eda954 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -152,15 +152,6 @@ struct scmi_power_proto_ops {
u32 *state);
};
-struct scmi_power_ops {
- int (*num_domains_get)(const struct scmi_handle *handle);
- char *(*name_get)(const struct scmi_handle *handle, u32 domain);
- int (*state_set)(const struct scmi_handle *handle, u32 domain,
- u32 state);
- int (*state_get)(const struct scmi_handle *handle, u32 domain,
- u32 *state);
-};
-
/**
* scmi_sensor_reading - represent a timestamped read
*
@@ -611,7 +602,6 @@ struct scmi_notify_ops {
*
* @dev: pointer to the SCMI device
* @version: pointer to the structure containing SCMI version information
- * @power_ops: pointer to set of power protocol operations
* @clk_ops: pointer to set of clock protocol operations
* @sensor_ops: pointer to set of sensor protocol operations
* @reset_ops: pointer to set of reset protocol operations
@@ -638,7 +628,6 @@ struct scmi_handle {
struct device *dev;
struct scmi_revision_info *version;
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_voltage_ops *voltage_ops;
--
2.17.1
Now that all the SCMI driver users have been migrated to the new interface
remove the legacy interface and all the transient code.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/clock.c | 67 -------------------------------
include/linux/scmi_protocol.h | 15 -------
2 files changed, 82 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index bf7dcd537fce..a0a6593f464f 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -235,16 +235,6 @@ scmi_clock_rate_get(const struct scmi_protocol_handle *ph,
return ret;
}
-static int
-__scmi_clock_rate_get(const struct scmi_handle *handle,
- u32 clk_id, u64 *value)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
-
- return scmi_clock_rate_get(ph, clk_id, value);
-}
-
static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
u32 clk_id, u64 rate)
{
@@ -280,15 +270,6 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_clock_rate_set(const struct scmi_handle *handle,
- u32 clk_id, u64 rate)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
-
- return scmi_clock_rate_set(ph, clk_id, rate);
-}
-
static int
scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
u32 config)
@@ -317,27 +298,11 @@ static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id)
return scmi_clock_config_set(ph, clk_id, CLOCK_ENABLE);
}
-static int __scmi_clock_enable(const struct scmi_handle *handle, u32 clk_id)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
-
- return scmi_clock_enable(ph, clk_id);
-}
-
static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id)
{
return scmi_clock_config_set(ph, clk_id, 0);
}
-static int __scmi_clock_disable(const struct scmi_handle *handle, u32 clk_id)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
-
- return scmi_clock_disable(ph, clk_id);
-}
-
static int scmi_clock_count_get(const struct scmi_protocol_handle *ph)
{
struct clock_info *ci = ph->get_priv(ph);
@@ -345,14 +310,6 @@ static int scmi_clock_count_get(const struct scmi_protocol_handle *ph)
return ci->num_clocks;
}
-static int __scmi_clock_count_get(const struct scmi_handle *handle)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
-
- return scmi_clock_count_get(ph);
-}
-
static const struct scmi_clock_info *
scmi_clock_info_get(const struct scmi_protocol_handle *ph, u32 clk_id)
{
@@ -365,24 +322,6 @@ scmi_clock_info_get(const struct scmi_protocol_handle *ph, u32 clk_id)
return clk;
}
-static const struct scmi_clock_info *
-__scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
-
- return scmi_clock_info_get(ph, clk_id);
-}
-
-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,
- .rate_set = __scmi_clock_rate_set,
- .enable = __scmi_clock_enable,
- .disable = __scmi_clock_disable,
-};
-
static const struct scmi_clk_proto_ops clk_proto_ops = {
.count_get = scmi_clock_count_get,
.info_get = scmi_clock_info_get,
@@ -397,7 +336,6 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
u32 version;
int clkid, ret;
struct clock_info *cinfo;
- struct scmi_handle *handle;
ph->xops->version_get(ph, &version);
@@ -424,11 +362,6 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
}
cinfo->version = version;
-
- /* Transient code for legacy ops interface */
- handle = scmi_map_scmi_handle(ph);
- handle->clk_ops = &clk_ops;
-
return ph->set_priv(ph, cinfo);
}
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index a403035df0ef..6605b75f4577 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -84,19 +84,6 @@ struct scmi_clk_proto_ops {
int (*disable)(const struct scmi_protocol_handle *ph, u32 clk_id);
};
-struct scmi_clk_ops {
- int (*count_get)(const struct scmi_handle *hamdle);
-
- const struct scmi_clock_info *(*info_get)
- (const struct scmi_handle *handle, u32 clk_id);
- int (*rate_get)(const struct scmi_handle *handle, u32 clk_id,
- u64 *rate);
- int (*rate_set)(const struct scmi_handle *handle, u32 clk_id,
- u64 rate);
- int (*enable)(const struct scmi_handle *handle, u32 clk_id);
- int (*disable)(const struct scmi_handle *handle, u32 clk_id);
-};
-
/**
* struct scmi_perf_proto_ops - represents the various operations provided
* by SCMI Performance Protocol
@@ -615,7 +602,6 @@ struct scmi_notify_ops {
*
* @dev: pointer to the SCMI device
* @version: pointer to the structure containing SCMI version information
- * @clk_ops: pointer to set of clock protocol operations
* @sensor_ops: pointer to set of sensor protocol operations
* @reset_ops: pointer to set of reset protocol operations
* @voltage_ops: pointer to set of voltage protocol operations
@@ -638,7 +624,6 @@ struct scmi_notify_ops {
struct scmi_handle {
struct device *dev;
struct scmi_revision_info *version;
- const struct scmi_clk_ops *clk_ops;
const struct scmi_sensor_ops *sensor_ops;
const struct scmi_reset_ops *reset_ops;
const struct scmi_voltage_ops *voltage_ops;
--
2.17.1
Now that all the SCMI driver users have been migrated to the new interface
remove the legacy interface and all the transient code.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/reset.c | 68 -------------------------------
include/linux/scmi_protocol.h | 11 -----
2 files changed, 79 deletions(-)
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index 9c808f5add7e..3856ceed2bd7 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -125,14 +125,6 @@ static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph)
return pi->num_domains;
}
-static int __scmi_reset_num_domains_get(const struct scmi_handle *handle)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
-
- return scmi_reset_num_domains_get(ph);
-}
-
static char *scmi_reset_name_get(const struct scmi_protocol_handle *ph,
u32 domain)
{
@@ -143,15 +135,6 @@ static char *scmi_reset_name_get(const struct scmi_protocol_handle *ph,
return dom->name;
}
-static char *__scmi_reset_name_get(const struct scmi_handle *handle,
- u32 domain)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
-
- return scmi_reset_name_get(ph, domain);
-}
-
static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph,
u32 domain)
{
@@ -161,15 +144,6 @@ static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph,
return dom->latency_us;
}
-static int __scmi_reset_latency_get(const struct scmi_handle *handle,
- u32 domain)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
-
- return scmi_reset_latency_get(ph, domain);
-}
-
static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain,
u32 flags, u32 state)
{
@@ -207,15 +181,6 @@ static int scmi_reset_domain_reset(const struct scmi_protocol_handle *ph,
ARCH_COLD_RESET);
}
-static int __scmi_reset_domain_reset(const struct scmi_handle *handle,
- u32 domain)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
-
- return scmi_reset_domain_reset(ph, domain);
-}
-
static int
scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain)
{
@@ -223,39 +188,12 @@ scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain)
ARCH_COLD_RESET);
}
-static int
-__scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
-
- return scmi_reset_domain_assert(ph, domain);
-}
-
static int
scmi_reset_domain_deassert(const struct scmi_protocol_handle *ph, u32 domain)
{
return scmi_domain_reset(ph, domain, 0, ARCH_COLD_RESET);
}
-static int
-__scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
-
- return scmi_reset_domain_deassert(ph, domain);
-}
-
-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,
- .reset = __scmi_reset_domain_reset,
- .assert = __scmi_reset_domain_assert,
- .deassert = __scmi_reset_domain_deassert,
-};
-
static const struct scmi_reset_proto_ops reset_proto_ops = {
.num_domains_get = scmi_reset_num_domains_get,
.name_get = scmi_reset_name_get,
@@ -357,7 +295,6 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
int domain;
u32 version;
struct scmi_reset_info *pinfo;
- struct scmi_handle *handle;
ph->xops->version_get(ph, &version);
@@ -382,11 +319,6 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
}
pinfo->version = version;
-
- /* Transient code for legacy ops interface */
- handle = scmi_map_scmi_handle(ph);
- handle->reset_ops = &reset_ops;
-
return ph->set_priv(ph, pinfo);
}
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 58a33d0b6f90..d1a052cc5162 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -483,15 +483,6 @@ struct scmi_reset_proto_ops {
int (*deassert)(const struct scmi_protocol_handle *ph, u32 domain);
};
-struct scmi_reset_ops {
- int (*num_domains_get)(const struct scmi_handle *handle);
- char *(*name_get)(const struct scmi_handle *handle, u32 domain);
- int (*latency_get)(const struct scmi_handle *handle, u32 domain);
- int (*reset)(const struct scmi_handle *handle, u32 domain);
- int (*assert)(const struct scmi_handle *handle, u32 domain);
- int (*deassert)(const struct scmi_handle *handle, u32 domain);
-};
-
/**
* struct scmi_voltage_info - describe one available SCMI Voltage Domain
*
@@ -612,7 +603,6 @@ struct scmi_notify_ops {
* @dev: pointer to the SCMI device
* @version: pointer to the structure containing SCMI version information
* @sensor_ops: pointer to set of sensor protocol operations
- * @reset_ops: pointer to set of reset protocol operations
* @voltage_ops: pointer to set of voltage protocol operations
* @devm_get_ops: devres managed method to acquire a protocol and get specific
* operations and a dedicated protocol handler
@@ -632,7 +622,6 @@ struct scmi_handle {
struct device *dev;
struct scmi_revision_info *version;
const struct scmi_sensor_ops *sensor_ops;
- const struct scmi_reset_ops *reset_ops;
const struct scmi_voltage_ops *voltage_ops;
const void __must_check *
--
2.17.1
Expose to the SCMI drivers a new alternative devres managed notifications
API based on protocol handles.
All drivers still keep using the old API, no functional change.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/notify.c | 123 +++++++++++++++++++++++++++++
include/linux/scmi_protocol.h | 15 +++-
2 files changed, 137 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index cdaf0f962d84..70e8eb4e33c6 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -1408,6 +1408,127 @@ static int scmi_unregister_notifier(const struct scmi_handle *handle,
return 0;
}
+struct scmi_notifier_devres {
+ const struct scmi_handle *handle;
+ u8 proto_id;
+ u8 evt_id;
+ u32 __src_id;
+ u32 *src_id;
+ struct notifier_block *nb;
+};
+
+static void scmi_devm_release_notifier(struct device *dev, void *res)
+{
+ struct scmi_notifier_devres *dres = res;
+
+ scmi_unregister_notifier(dres->handle, dres->proto_id, dres->evt_id,
+ dres->src_id, dres->nb);
+}
+
+/**
+ * scmi_devm_register_notifier() - Managed registration of a notifier_block
+ * for an event
+ * @sdev: A reference to an scmi_device whose embedded struct device is to
+ * be used for devres accounting.
+ * @proto_id: Protocol ID
+ * @evt_id: Event ID
+ * @src_id: Source ID, when NULL register for events coming form ALL possible
+ * sources
+ * @nb: A standard notifier block to register for the specified event
+ *
+ * Generic devres managed helper to register a notifier_block against a
+ * protocol event.
+ */
+static int scmi_devm_register_notifier(struct scmi_device *sdev,
+ u8 proto_id, u8 evt_id, u32 *src_id,
+ struct notifier_block *nb)
+{
+ int ret;
+ struct scmi_notifier_devres *dres;
+
+ dres = devres_alloc(scmi_devm_release_notifier,
+ sizeof(*dres), GFP_KERNEL);
+ if (!dres)
+ return -ENOMEM;
+
+ ret = scmi_register_notifier(sdev->handle, proto_id,
+ evt_id, src_id, nb);
+ if (ret) {
+ devres_free(dres);
+ return ret;
+ }
+
+ dres->handle = sdev->handle;
+ dres->proto_id = proto_id;
+ dres->evt_id = evt_id;
+ dres->nb = nb;
+ if (src_id) {
+ dres->__src_id = *src_id;
+ dres->src_id = &dres->__src_id;
+ } else {
+ dres->src_id = NULL;
+ }
+ devres_add(&sdev->dev, dres);
+
+ return ret;
+}
+
+static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
+{
+ struct scmi_notifier_devres *dres = res;
+ struct scmi_notifier_devres *xres = data;
+
+ if (WARN_ON(!dres || !xres))
+ return 0;
+
+ return dres->proto_id == xres->proto_id &&
+ dres->evt_id == xres->evt_id &&
+ dres->nb == xres->nb &&
+ ((!dres->src_id && !xres->src_id) ||
+ (dres->src_id && xres->src_id &&
+ dres->__src_id == xres->__src_id));
+}
+
+/**
+ * scmi_devm_unregister_notifier() - Managed un-registration of a
+ * notifier_block for an event
+ * @sdev: A reference to an scmi_device whose embedded struct device is to
+ * be used for devres accounting.
+ * @proto_id: Protocol ID
+ * @evt_id: Event ID
+ * @src_id: Source ID, when NULL register for events coming form ALL possible
+ * sources
+ * @nb: A standard notifier block to register for the specified event
+ *
+ * Generic devres managed helper to explicitly un-register a notifier_block
+ * against a protocol event, which was previously registered using the above
+ * @scmi_devm_register_notifier.
+ */
+static int scmi_devm_unregister_notifier(struct scmi_device *sdev,
+ u8 proto_id, u8 evt_id, u32 *src_id,
+ struct notifier_block *nb)
+{
+ int ret;
+ struct scmi_notifier_devres dres;
+
+ dres.handle = sdev->handle;
+ dres.proto_id = proto_id;
+ dres.evt_id = evt_id;
+ if (src_id) {
+ dres.__src_id = *src_id;
+ dres.src_id = &dres.__src_id;
+ } else {
+ dres.src_id = NULL;
+ }
+
+ ret = devres_release(&sdev->dev, scmi_devm_release_notifier,
+ scmi_devm_notifier_match, &dres);
+
+ WARN_ON(ret);
+
+ return ret;
+}
+
/**
* scmi_protocols_late_init() - Worker for late initialization
* @work: The work item to use associated to the proper SCMI instance
@@ -1465,6 +1586,8 @@ static void scmi_protocols_late_init(struct work_struct *work)
* directly from an scmi_driver to register its own notifiers.
*/
static const struct scmi_notify_ops notify_ops = {
+ .devm_register_event_notifier = scmi_devm_register_notifier,
+ .devm_unregister_event_notifier = scmi_devm_unregister_notifier,
.register_event_notifier = scmi_register_notifier,
.unregister_event_notifier = scmi_unregister_notifier,
};
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 8a2bb723602f..88757639f790 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -544,6 +544,10 @@ struct scmi_voltage_ops {
/**
* struct scmi_notify_ops - represents notifications' operations provided by
* SCMI core
+ * @devm_register_event_notifier: Managed registration of a notifier_block for
+ * the requested event
+ * @devm_unregister_event_notifier: Managed unregistration of a notifier_block
+ * for the requested event
* @register_event_notifier: Register a notifier_block for the requested event
* @unregister_event_notifier: Unregister a notifier_block for the requested
* event
@@ -553,7 +557,9 @@ struct scmi_voltage_ops {
* tuple: (proto_id, evt_id, src_id) using the provided register/unregister
* interface where:
*
- * @handle: The handle identifying the platform instance to use
+ * @sdev: The scmi_device to use when calling the devres managed ops devm_
+ * @handle: The handle identifying the platform instance to use, when not
+ * calling the managed ops devm_
* @proto_id: The protocol ID as in SCMI Specification
* @evt_id: The message ID of the desired event as in SCMI Specification
* @src_id: A pointer to the desired source ID if different sources are
@@ -576,6 +582,13 @@ struct scmi_voltage_ops {
* @report: A custom struct describing the specific event delivered
*/
struct scmi_notify_ops {
+ int (*devm_register_event_notifier)(struct scmi_device *sdev,
+ u8 proto_id, u8 evt_id, u32 *src_id,
+ struct notifier_block *nb);
+ int (*devm_unregister_event_notifier)(struct scmi_device *sdev,
+ u8 proto_id, u8 evt_id,
+ u32 *src_id,
+ struct notifier_block *nb);
int (*register_event_notifier)(const struct scmi_handle *handle,
u8 proto_id, u8 evt_id, u32 *src_id,
struct notifier_block *nb);
--
2.17.1
Convert internals of protocol implementation to use protocol handles and
expose a new protocol operations interface for SCMI driver using the new
get/put common operations, while keeping the old handle->perf_ops still
around to ease transition.
Remove handle->perf_priv now unused.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/perf.c | 349 ++++++++++++++++++++-----------
include/linux/scmi_protocol.h | 30 ++-
2 files changed, 258 insertions(+), 121 deletions(-)
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index f27a0afbe65a..99144a70ded6 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -175,21 +175,21 @@ static enum scmi_performance_protocol_cmd evt_2_cmd[] = {
PERF_NOTIFY_LEVEL,
};
-static int scmi_perf_attributes_get(const struct scmi_handle *handle,
+static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_perf_info *pi)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_perf_attributes *attr;
- ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
- SCMI_PROTOCOL_PERF, 0, sizeof(*attr), &t);
+ ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
+ sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
u16 flags = le16_to_cpu(attr->flags);
@@ -200,28 +200,27 @@ static int scmi_perf_attributes_get(const struct scmi_handle *handle,
pi->stats_size = le32_to_cpu(attr->stats_size);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
static int
-scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
- struct perf_dom_info *dom_info)
+scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
+ u32 domain, struct perf_dom_info *dom_info)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_perf_domain_attributes *attr;
- ret = scmi_xfer_get_init(handle, PERF_DOMAIN_ATTRIBUTES,
- SCMI_PROTOCOL_PERF, sizeof(domain),
- sizeof(*attr), &t);
+ ret = ph->xops->xfer_get_init(ph, PERF_DOMAIN_ATTRIBUTES,
+ sizeof(domain), sizeof(*attr), &t);
if (ret)
return ret;
put_unaligned_le32(domain, t->tx.buf);
attr = t->rx.buf;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
u32 flags = le32_to_cpu(attr->flags);
@@ -245,7 +244,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -257,7 +256,7 @@ static int opp_cmp_func(const void *opp1, const void *opp2)
}
static int
-scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
+scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain,
struct perf_dom_info *perf_dom)
{
int ret, cnt;
@@ -268,8 +267,8 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
struct scmi_msg_perf_describe_levels *dom_info;
struct scmi_msg_resp_perf_describe_levels *level_info;
- ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_LEVELS,
- SCMI_PROTOCOL_PERF, sizeof(*dom_info), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_LEVELS,
+ sizeof(*dom_info), 0, &t);
if (ret)
return ret;
@@ -281,14 +280,14 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
/* Set the number of OPPs to be skipped/already read */
dom_info->level_index = cpu_to_le32(tot_opp_cnt);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (ret)
break;
num_returned = le16_to_cpu(level_info->num_returned);
num_remaining = le16_to_cpu(level_info->num_remaining);
if (tot_opp_cnt + num_returned > MAX_OPPS) {
- dev_err(handle->dev, "No. of OPPs exceeded MAX_OPPS");
+ dev_err(ph->dev, "No. of OPPs exceeded MAX_OPPS");
break;
}
@@ -299,13 +298,13 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
opp->trans_latency_us = le16_to_cpu
(level_info->opp[cnt].transition_latency_us);
- dev_dbg(handle->dev, "Level %d Power %d Latency %dus\n",
+ dev_dbg(ph->dev, "Level %d Power %d Latency %dus\n",
opp->perf, opp->power, opp->trans_latency_us);
}
tot_opp_cnt += num_returned;
- scmi_reset_rx_to_maxsz(handle, t);
+ ph->xops->reset_rx_to_maxsz(ph, t);
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
@@ -313,7 +312,7 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
} while (num_returned && num_remaining);
perf_dom->opp_count = tot_opp_cnt;
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
sort(perf_dom->opp, tot_opp_cnt, sizeof(*opp), opp_cmp_func, NULL);
return ret;
@@ -353,15 +352,15 @@ static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
#endif
}
-static int scmi_perf_mb_limits_set(const struct scmi_handle *handle, u32 domain,
- u32 max_perf, u32 min_perf)
+static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 max_perf, u32 min_perf)
{
int ret;
struct scmi_xfer *t;
struct scmi_perf_set_limits *limits;
- ret = scmi_xfer_get_init(handle, PERF_LIMITS_SET, SCMI_PROTOCOL_PERF,
- sizeof(*limits), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, PERF_LIMITS_SET,
+ sizeof(*limits), 0, &t);
if (ret)
return ret;
@@ -370,16 +369,16 @@ static int scmi_perf_mb_limits_set(const struct scmi_handle *handle, u32 domain,
limits->max_level = cpu_to_le32(max_perf);
limits->min_level = cpu_to_le32(min_perf);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
- u32 max_perf, u32 min_perf)
+static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 max_perf, u32 min_perf)
{
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
struct perf_dom_info *dom = pi->dom_info + domain;
if (dom->fc_info && dom->fc_info->limit_set_addr) {
@@ -389,24 +388,33 @@ static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
return 0;
}
- return scmi_perf_mb_limits_set(handle, domain, max_perf, min_perf);
+ return scmi_perf_mb_limits_set(ph, domain, max_perf, min_perf);
}
-static int scmi_perf_mb_limits_get(const struct scmi_handle *handle, u32 domain,
- u32 *max_perf, u32 *min_perf)
+static int __scmi_perf_limits_set(const struct scmi_handle *handle,
+ u32 domain, u32 max_perf, u32 min_perf)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_perf_limits_set(ph, domain, max_perf, min_perf);
+}
+
+static int scmi_perf_mb_limits_get(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 *max_perf, u32 *min_perf)
{
int ret;
struct scmi_xfer *t;
struct scmi_perf_get_limits *limits;
- ret = scmi_xfer_get_init(handle, PERF_LIMITS_GET, SCMI_PROTOCOL_PERF,
- sizeof(__le32), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, PERF_LIMITS_GET,
+ sizeof(__le32), 0, &t);
if (ret)
return ret;
put_unaligned_le32(domain, t->tx.buf);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
limits = t->rx.buf;
@@ -414,14 +422,14 @@ static int scmi_perf_mb_limits_get(const struct scmi_handle *handle, u32 domain,
*min_perf = le32_to_cpu(limits->min_level);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
- u32 *max_perf, u32 *min_perf)
+static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 *max_perf, u32 *min_perf)
{
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
struct perf_dom_info *dom = pi->dom_info + domain;
if (dom->fc_info && dom->fc_info->limit_get_addr) {
@@ -430,18 +438,26 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
return 0;
}
- return scmi_perf_mb_limits_get(handle, domain, max_perf, min_perf);
+ return scmi_perf_mb_limits_get(ph, domain, max_perf, min_perf);
}
-static int scmi_perf_mb_level_set(const struct scmi_handle *handle, u32 domain,
- u32 level, bool poll)
+static int __scmi_perf_limits_get(const struct scmi_handle *handle,
+ u32 domain, u32 *max_perf, u32 *min_perf)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_perf_limits_get(ph, domain, max_perf, min_perf);
+}
+
+static int scmi_perf_mb_level_set(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 level, bool poll)
{
int ret;
struct scmi_xfer *t;
struct scmi_perf_set_level *lvl;
- ret = scmi_xfer_get_init(handle, PERF_LEVEL_SET, SCMI_PROTOCOL_PERF,
- sizeof(*lvl), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, PERF_LEVEL_SET, sizeof(*lvl), 0, &t);
if (ret)
return ret;
@@ -450,16 +466,16 @@ static int scmi_perf_mb_level_set(const struct scmi_handle *handle, u32 domain,
lvl->domain = cpu_to_le32(domain);
lvl->level = cpu_to_le32(level);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
- u32 level, bool poll)
+static int scmi_perf_level_set(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 level, bool poll)
{
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
struct perf_dom_info *dom = pi->dom_info + domain;
if (dom->fc_info && dom->fc_info->level_set_addr) {
@@ -468,35 +484,44 @@ static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
return 0;
}
- return scmi_perf_mb_level_set(handle, domain, level, poll);
+ return scmi_perf_mb_level_set(ph, domain, level, poll);
+}
+
+static int __scmi_perf_level_set(const struct scmi_handle *handle,
+ u32 domain, u32 level, bool poll)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_perf_level_set(ph, domain, level, poll);
}
-static int scmi_perf_mb_level_get(const struct scmi_handle *handle, u32 domain,
- u32 *level, bool poll)
+static int scmi_perf_mb_level_get(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 *level, bool poll)
{
int ret;
struct scmi_xfer *t;
- ret = scmi_xfer_get_init(handle, PERF_LEVEL_GET, SCMI_PROTOCOL_PERF,
- sizeof(u32), sizeof(u32), &t);
+ ret = ph->xops->xfer_get_init(ph, PERF_LEVEL_GET,
+ sizeof(u32), sizeof(u32), &t);
if (ret)
return ret;
t->hdr.poll_completion = poll;
put_unaligned_le32(domain, t->tx.buf);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
*level = get_unaligned_le32(t->rx.buf);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
- u32 *level, bool poll)
+static int scmi_perf_level_get(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 *level, bool poll)
{
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
struct perf_dom_info *dom = pi->dom_info + domain;
if (dom->fc_info && dom->fc_info->level_get_addr) {
@@ -504,10 +529,19 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
return 0;
}
- return scmi_perf_mb_level_get(handle, domain, level, poll);
+ return scmi_perf_mb_level_get(ph, domain, level, poll);
+}
+
+static int __scmi_perf_level_get(const struct scmi_handle *handle,
+ u32 domain, u32 *level, bool poll)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_perf_level_get(ph, domain, level, poll);
}
-static int scmi_perf_level_limits_notify(const struct scmi_handle *handle,
+static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph,
u32 domain, int message_id,
bool enable)
{
@@ -515,8 +549,7 @@ static int scmi_perf_level_limits_notify(const struct scmi_handle *handle,
struct scmi_xfer *t;
struct scmi_perf_notify_level_or_limits *notify;
- ret = scmi_xfer_get_init(handle, message_id, SCMI_PROTOCOL_PERF,
- sizeof(*notify), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*notify), 0, &t);
if (ret)
return ret;
@@ -524,9 +557,9 @@ static int scmi_perf_level_limits_notify(const struct scmi_handle *handle,
notify->domain = cpu_to_le32(domain);
notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -540,7 +573,7 @@ static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
}
static void
-scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain,
+scmi_perf_domain_desc_fc(const struct scmi_protocol_handle *ph, u32 domain,
u32 message_id, void __iomem **p_addr,
struct scmi_fc_db_info **p_db)
{
@@ -557,9 +590,8 @@ scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain,
if (!p_addr)
return;
- ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_FASTCHANNEL,
- SCMI_PROTOCOL_PERF,
- sizeof(*info), sizeof(*resp), &t);
+ ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_FASTCHANNEL,
+ sizeof(*info), sizeof(*resp), &t);
if (ret)
return;
@@ -567,7 +599,7 @@ scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain,
info->domain = cpu_to_le32(domain);
info->message_id = cpu_to_le32(message_id);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (ret)
goto err_xfer;
@@ -579,20 +611,20 @@ scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain,
phys_addr = le32_to_cpu(resp->chan_addr_low);
phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
- addr = devm_ioremap(handle->dev, phys_addr, size);
+ addr = devm_ioremap(ph->dev, phys_addr, size);
if (!addr)
goto err_xfer;
*p_addr = addr;
if (p_db && SUPPORTS_DOORBELL(flags)) {
- db = devm_kzalloc(handle->dev, sizeof(*db), GFP_KERNEL);
+ db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL);
if (!db)
goto err_xfer;
size = 1 << DOORBELL_REG_WIDTH(flags);
phys_addr = le32_to_cpu(resp->db_addr_low);
phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
- addr = devm_ioremap(handle->dev, phys_addr, size);
+ addr = devm_ioremap(ph->dev, phys_addr, size);
if (!addr)
goto err_xfer;
@@ -605,25 +637,25 @@ scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain,
*p_db = db;
}
err_xfer:
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
}
-static void scmi_perf_domain_init_fc(const struct scmi_handle *handle,
+static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
u32 domain, struct scmi_fc_info **p_fc)
{
struct scmi_fc_info *fc;
- fc = devm_kzalloc(handle->dev, sizeof(*fc), GFP_KERNEL);
+ fc = devm_kzalloc(ph->dev, sizeof(*fc), GFP_KERNEL);
if (!fc)
return;
- scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_SET,
+ scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_SET,
&fc->level_set_addr, &fc->level_set_db);
- scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_GET,
+ scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_GET,
&fc->level_get_addr, NULL);
- scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_SET,
+ scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_SET,
&fc->limit_set_addr, &fc->limit_set_db);
- scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_GET,
+ scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_GET,
&fc->limit_get_addr, NULL);
*p_fc = fc;
}
@@ -640,14 +672,14 @@ static int scmi_dev_domain_id(struct device *dev)
return clkspec.args[0];
}
-static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle,
+static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
struct device *dev)
{
int idx, ret, domain;
unsigned long freq;
struct scmi_opp *opp;
struct perf_dom_info *dom;
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
domain = scmi_dev_domain_id(dev);
if (domain < 0)
@@ -672,11 +704,21 @@ static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle,
return 0;
}
-static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle,
- struct device *dev)
+static int __scmi_dvfs_device_opps_add(const struct scmi_handle *handle,
+ struct device *dev)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_dvfs_device_opps_add(ph, dev);
+}
+
+static int
+scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph,
+ struct device *dev)
{
struct perf_dom_info *dom;
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
int domain = scmi_dev_domain_id(dev);
if (domain < 0)
@@ -687,35 +729,63 @@ static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle,
return dom->opp[dom->opp_count - 1].trans_latency_us * 1000;
}
-static int scmi_dvfs_freq_set(const struct scmi_handle *handle, u32 domain,
+static int
+__scmi_dvfs_transition_latency_get(const struct scmi_handle *handle,
+ struct device *dev)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_dvfs_transition_latency_get(ph, dev);
+}
+
+static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain,
unsigned long freq, bool poll)
{
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
struct perf_dom_info *dom = pi->dom_info + domain;
- return scmi_perf_level_set(handle, domain, freq / dom->mult_factor,
- poll);
+ return scmi_perf_level_set(ph, domain, freq / dom->mult_factor, poll);
}
-static int scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain,
+static int __scmi_dvfs_freq_set(const struct scmi_handle *handle,
+ u32 domain, unsigned long freq, bool poll)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_dvfs_freq_set(ph, domain, freq, poll);
+}
+
+static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain,
unsigned long *freq, bool poll)
{
int ret;
u32 level;
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
struct perf_dom_info *dom = pi->dom_info + domain;
- ret = scmi_perf_level_get(handle, domain, &level, poll);
+ ret = scmi_perf_level_get(ph, domain, &level, poll);
if (!ret)
*freq = level * dom->mult_factor;
return ret;
}
-static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain,
- unsigned long *freq, unsigned long *power)
+static int __scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain,
+ unsigned long *freq, bool poll)
{
- struct scmi_perf_info *pi = handle->perf_priv;
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_dvfs_freq_get(ph, domain, freq, poll);
+}
+
+static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph,
+ u32 domain, unsigned long *freq,
+ unsigned long *power)
+{
+ struct scmi_perf_info *pi = ph->get_priv(ph);
struct perf_dom_info *dom;
unsigned long opp_freq;
int idx, ret = -EINVAL;
@@ -739,25 +809,67 @@ static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain,
return ret;
}
-static bool scmi_fast_switch_possible(const struct scmi_handle *handle,
+static int __scmi_dvfs_est_power_get(const struct scmi_handle *handle,
+ u32 domain, unsigned long *freq,
+ unsigned long *power)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_dvfs_est_power_get(ph, domain, freq, power);
+}
+
+static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
struct device *dev)
{
struct perf_dom_info *dom;
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi = ph->get_priv(ph);
dom = pi->dom_info + scmi_dev_domain_id(dev);
return dom->fc_info && dom->fc_info->level_set_addr;
}
-static bool scmi_power_scale_mw_get(const struct scmi_handle *handle)
+static bool __scmi_fast_switch_possible(const struct scmi_handle *handle,
+ struct device *dev)
{
- struct scmi_perf_info *pi = handle->perf_priv;
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_fast_switch_possible(ph, dev);
+}
+
+static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
+{
+ struct scmi_perf_info *pi = ph->get_priv(ph);
return pi->power_scale_mw;
}
+static bool __scmi_power_scale_mw_get(const struct scmi_handle *handle)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
+
+ return scmi_power_scale_mw_get(ph);
+}
+
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,
+ .level_get = __scmi_perf_level_get,
+ .device_domain_id = scmi_dev_domain_id,
+ .transition_latency_get = __scmi_dvfs_transition_latency_get,
+ .device_opps_add = __scmi_dvfs_device_opps_add,
+ .freq_set = __scmi_dvfs_freq_set,
+ .freq_get = __scmi_dvfs_freq_get,
+ .est_power_get = __scmi_dvfs_est_power_get,
+ .fast_switch_possible = __scmi_fast_switch_possible,
+ .power_scale_mw_get = __scmi_power_scale_mw_get,
+};
+
+static const struct scmi_perf_proto_ops perf_proto_ops = {
.limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get,
.level_set = scmi_perf_level_set,
@@ -772,7 +884,7 @@ static const struct scmi_perf_ops perf_ops = {
.power_scale_mw_get = scmi_power_scale_mw_get,
};
-static int scmi_perf_set_notify_enabled(const void *handle,
+static int scmi_perf_set_notify_enabled(const void *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret, cmd_id;
@@ -781,7 +893,7 @@ static int scmi_perf_set_notify_enabled(const void *handle,
return -EINVAL;
cmd_id = evt_2_cmd[evt_id];
- ret = scmi_perf_level_limits_notify(handle, src_id, cmd_id, enable);
+ ret = scmi_perf_level_limits_notify(ph, src_id, cmd_id, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
@@ -789,7 +901,7 @@ static int scmi_perf_set_notify_enabled(const void *handle,
return ret;
}
-static void *scmi_perf_fill_custom_report(const void *handle,
+static void *scmi_perf_fill_custom_report(const void *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -837,10 +949,10 @@ static void *scmi_perf_fill_custom_report(const void *handle,
return rep;
}
-static int scmi_perf_get_num_sources(const void *handle)
+static int scmi_perf_get_num_sources(const void *ph)
{
struct scmi_perf_info *pi =
- ((const struct scmi_handle *)(handle))->perf_priv;
+ ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
if (!pi)
return -EINVAL;
@@ -874,24 +986,25 @@ static const struct scmi_protocol_events perf_protocol_events = {
.num_events = ARRAY_SIZE(perf_events),
};
-static int scmi_perf_protocol_init(struct scmi_handle *handle)
+static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
{
int domain;
u32 version;
struct scmi_perf_info *pinfo;
+ struct scmi_handle *handle;
- scmi_version_get(handle, SCMI_PROTOCOL_PERF, &version);
+ ph->xops->version_get(ph, &version);
- dev_dbg(handle->dev, "Performance Version %d.%d\n",
+ dev_dbg(ph->dev, "Performance Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
- pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
+ pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
- scmi_perf_attributes_get(handle, pinfo);
+ scmi_perf_attributes_get(ph, pinfo);
- pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains,
+ pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains,
sizeof(*pinfo->dom_info), GFP_KERNEL);
if (!pinfo->dom_info)
return -ENOMEM;
@@ -899,24 +1012,26 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
for (domain = 0; domain < pinfo->num_domains; domain++) {
struct perf_dom_info *dom = pinfo->dom_info + domain;
- scmi_perf_domain_attributes_get(handle, domain, dom);
- scmi_perf_describe_levels_get(handle, domain, dom);
+ scmi_perf_domain_attributes_get(ph, domain, dom);
+ scmi_perf_describe_levels_get(ph, domain, dom);
if (dom->perf_fastchannels)
- scmi_perf_domain_init_fc(handle, domain, &dom->fc_info);
+ scmi_perf_domain_init_fc(ph, domain, &dom->fc_info);
}
pinfo->version = version;
+
+ /* Transient code for legacy ops interface */
+ handle = scmi_map_scmi_handle(ph);
handle->perf_ops = &perf_ops;
- handle->perf_priv = pinfo;
- return 0;
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_perf = {
.id = SCMI_PROTOCOL_PERF,
- .init = &scmi_perf_protocol_init,
- .ops = &perf_ops,
+ .init_instance = &scmi_perf_protocol_init,
+ .ops = &perf_proto_ops,
.events = &perf_protocol_events,
};
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 88757639f790..0d2138f1d9f3 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -85,7 +85,7 @@ struct scmi_clk_ops {
};
/**
- * struct scmi_perf_ops - represents the various operations provided
+ * struct scmi_perf_proto_ops - represents the various operations provided
* by SCMI Performance Protocol
*
* @limits_set: sets limits on the performance level of a domain
@@ -102,6 +102,31 @@ struct scmi_clk_ops {
* @est_power_get: gets the estimated power cost for a given performance domain
* at a given frequency
*/
+struct scmi_perf_proto_ops {
+ int (*limits_set)(const struct scmi_protocol_handle *ph, u32 domain,
+ u32 max_perf, u32 min_perf);
+ int (*limits_get)(const struct scmi_protocol_handle *ph, u32 domain,
+ u32 *max_perf, u32 *min_perf);
+ int (*level_set)(const struct scmi_protocol_handle *ph, u32 domain,
+ u32 level, bool poll);
+ int (*level_get)(const struct scmi_protocol_handle *ph, u32 domain,
+ u32 *level, bool poll);
+ int (*device_domain_id)(struct device *dev);
+ int (*transition_latency_get)(const struct scmi_protocol_handle *ph,
+ struct device *dev);
+ int (*device_opps_add)(const struct scmi_protocol_handle *ph,
+ struct device *dev);
+ int (*freq_set)(const struct scmi_protocol_handle *ph, u32 domain,
+ unsigned long rate, bool poll);
+ int (*freq_get)(const struct scmi_protocol_handle *ph, u32 domain,
+ unsigned long *rate, bool poll);
+ int (*est_power_get)(const struct scmi_protocol_handle *ph, u32 domain,
+ unsigned long *rate, unsigned long *power);
+ bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph,
+ struct device *dev);
+ bool (*power_scale_mw_get)(const struct scmi_protocol_handle *ph);
+};
+
struct scmi_perf_ops {
int (*limits_set)(const struct scmi_handle *handle, u32 domain,
u32 max_perf, u32 min_perf);
@@ -615,8 +640,6 @@ struct scmi_notify_ops {
* dedicated protocol handler
* @put_ops: method to release a protocol
* @notify_ops: pointer to set of notifications related operations
- * @perf_priv: pointer to private data structure specific to performance
- * protocol(for internal use only)
* @clk_priv: pointer to private data structure specific to clock
* protocol(for internal use only)
* @power_priv: pointer to private data structure specific to power
@@ -652,7 +675,6 @@ struct scmi_handle {
const struct scmi_notify_ops *notify_ops;
/* for protocol internal use */
- void *perf_priv;
void *clk_priv;
void *power_priv;
void *sensor_priv;
--
2.17.1
Port driver to the new SCMI Sensor interface based on protocol handles
and common devm_get_ops().
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/hwmon/scmi-hwmon.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c
index 17d064e58938..399011740b00 100644
--- a/drivers/hwmon/scmi-hwmon.c
+++ b/drivers/hwmon/scmi-hwmon.c
@@ -2,7 +2,7 @@
/*
* System Control and Management Interface(SCMI) based hwmon sensor driver
*
- * Copyright (C) 2018 ARM Ltd.
+ * Copyright (C) 2018-2020 ARM Ltd.
* Sudeep Holla <[email protected]>
*/
@@ -13,8 +13,10 @@
#include <linux/sysfs.h>
#include <linux/thermal.h>
+static const struct scmi_sensor_proto_ops *sensor_ops;
+
struct scmi_sensors {
- const struct scmi_handle *handle;
+ const struct scmi_protocol_handle *ph;
const struct scmi_sensor_info **info[hwmon_max];
};
@@ -69,10 +71,9 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u64 value;
const struct scmi_sensor_info *sensor;
struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev);
- const struct scmi_handle *h = scmi_sensors->handle;
sensor = *(scmi_sensors->info[type] + channel);
- ret = h->sensor_ops->reading_get(h, sensor->id, &value);
+ ret = sensor_ops->reading_get(scmi_sensors->ph, sensor->id, &value);
if (ret)
return ret;
@@ -169,11 +170,16 @@ static int scmi_hwmon_probe(struct scmi_device *sdev)
struct hwmon_channel_info *scmi_hwmon_chan;
const struct hwmon_channel_info **ptr_scmi_ci;
const struct scmi_handle *handle = sdev->handle;
+ struct scmi_protocol_handle *ph;
- if (!handle || !handle->sensor_ops)
+ if (!handle)
return -ENODEV;
- nr_sensors = handle->sensor_ops->count_get(handle);
+ sensor_ops = handle->devm_get_ops(sdev, SCMI_PROTOCOL_SENSOR, &ph);
+ if (IS_ERR(sensor_ops))
+ return PTR_ERR(sensor_ops);
+
+ nr_sensors = sensor_ops->count_get(ph);
if (!nr_sensors)
return -EIO;
@@ -181,10 +187,10 @@ static int scmi_hwmon_probe(struct scmi_device *sdev)
if (!scmi_sensors)
return -ENOMEM;
- scmi_sensors->handle = handle;
+ scmi_sensors->ph = ph;
for (i = 0; i < nr_sensors; i++) {
- sensor = handle->sensor_ops->info_get(handle, i);
+ sensor = sensor_ops->info_get(ph, i);
if (!sensor)
return -EINVAL;
@@ -236,7 +242,7 @@ static int scmi_hwmon_probe(struct scmi_device *sdev)
}
for (i = nr_sensors - 1; i >= 0 ; i--) {
- sensor = handle->sensor_ops->info_get(handle, i);
+ sensor = sensor_ops->info_get(ph, i);
if (!sensor)
continue;
--
2.17.1
Convert internals of protocol implementation to use protocol handles and
expose a new protocol operations interface for SCMI driver using the new
get/put common operations, while keeping the old handle->power_ops still
around to ease transition.
Remove handle->power_priv now unused.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/power.c | 141 +++++++++++++++++++-----------
include/linux/scmi_protocol.h | 20 +++--
2 files changed, 105 insertions(+), 56 deletions(-)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index e4c084ca92e4..b3d1c032218c 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -68,21 +68,21 @@ struct scmi_power_info {
struct power_dom_info *dom_info;
};
-static int scmi_power_attributes_get(const struct scmi_handle *handle,
+static int scmi_power_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_power_info *pi)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_power_attributes *attr;
- ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
- SCMI_PROTOCOL_POWER, 0, sizeof(*attr), &t);
+ ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
+ 0, sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
pi->num_domains = le16_to_cpu(attr->num_domains);
pi->stats_addr = le32_to_cpu(attr->stats_addr_low) |
@@ -90,28 +90,27 @@ static int scmi_power_attributes_get(const struct scmi_handle *handle,
pi->stats_size = le32_to_cpu(attr->stats_size);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
static int
-scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
- struct power_dom_info *dom_info)
+scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
+ u32 domain, struct power_dom_info *dom_info)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_power_domain_attributes *attr;
- ret = scmi_xfer_get_init(handle, POWER_DOMAIN_ATTRIBUTES,
- SCMI_PROTOCOL_POWER, sizeof(domain),
- sizeof(*attr), &t);
+ ret = ph->xops->xfer_get_init(ph, POWER_DOMAIN_ATTRIBUTES,
+ sizeof(domain), sizeof(*attr), &t);
if (ret)
return ret;
put_unaligned_le32(domain, t->tx.buf);
attr = t->rx.buf;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
u32 flags = le32_to_cpu(attr->flags);
@@ -121,19 +120,18 @@ scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int
-scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state)
+static int scmi_power_state_set(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 state)
{
int ret;
struct scmi_xfer *t;
struct scmi_power_set_state *st;
- ret = scmi_xfer_get_init(handle, POWER_STATE_SET, SCMI_PROTOCOL_POWER,
- sizeof(*st), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, POWER_STATE_SET, sizeof(*st), 0, &t);
if (ret)
return ret;
@@ -142,64 +140,106 @@ scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state)
st->domain = cpu_to_le32(domain);
st->state = cpu_to_le32(state);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int
-scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state)
+static int __scmi_power_state_set(const struct scmi_handle *handle,
+ u32 domain, u32 state)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_POWER);
+
+ return scmi_power_state_set(ph, domain, state);
+}
+
+static int scmi_power_state_get(const struct scmi_protocol_handle *ph,
+ u32 domain, u32 *state)
{
int ret;
struct scmi_xfer *t;
- ret = scmi_xfer_get_init(handle, POWER_STATE_GET, SCMI_PROTOCOL_POWER,
- sizeof(u32), sizeof(u32), &t);
+ ret = ph->xops->xfer_get_init(ph, POWER_STATE_GET, sizeof(u32), sizeof(u32), &t);
if (ret)
return ret;
put_unaligned_le32(domain, t->tx.buf);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
*state = get_unaligned_le32(t->rx.buf);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_power_num_domains_get(const struct scmi_handle *handle)
+static int __scmi_power_state_get(const struct scmi_handle *handle,
+ u32 domain, u32 *state)
{
- struct scmi_power_info *pi = handle->power_priv;
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_POWER);
+
+ return scmi_power_state_get(ph, domain, state);
+}
+
+static int scmi_power_num_domains_get(const struct scmi_protocol_handle *ph)
+{
+ struct scmi_power_info *pi = ph->get_priv(ph);
return pi->num_domains;
}
-static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain)
+static int __scmi_power_num_domains_get(const struct scmi_handle *handle)
{
- struct scmi_power_info *pi = handle->power_priv;
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_POWER);
+
+ return scmi_power_num_domains_get(ph);
+}
+
+static char *scmi_power_name_get(const struct scmi_protocol_handle *ph,
+ u32 domain)
+{
+ struct scmi_power_info *pi = ph->get_priv(ph);
struct power_dom_info *dom = pi->dom_info + domain;
return dom->name;
}
+static char *__scmi_power_name_get(const struct scmi_handle *handle,
+ u32 domain)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_POWER);
+
+ return scmi_power_name_get(ph, domain);
+}
+
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,
+ .state_get = __scmi_power_state_get,
+};
+
+static const struct scmi_power_proto_ops power_proto_ops = {
.num_domains_get = scmi_power_num_domains_get,
.name_get = scmi_power_name_get,
.state_set = scmi_power_state_set,
.state_get = scmi_power_state_get,
};
-static int scmi_power_request_notify(const struct scmi_handle *handle,
+static int scmi_power_request_notify(const struct scmi_protocol_handle *ph,
u32 domain, bool enable)
{
int ret;
struct scmi_xfer *t;
struct scmi_power_state_notify *notify;
- ret = scmi_xfer_get_init(handle, POWER_STATE_NOTIFY,
- SCMI_PROTOCOL_POWER, sizeof(*notify), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, POWER_STATE_NOTIFY,
+ sizeof(*notify), 0, &t);
if (ret)
return ret;
@@ -207,18 +247,18 @@ static int scmi_power_request_notify(const struct scmi_handle *handle,
notify->domain = cpu_to_le32(domain);
notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_power_set_notify_enabled(const void *handle,
+static int scmi_power_set_notify_enabled(const void *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
- ret = scmi_power_request_notify(handle, src_id, enable);
+ ret = scmi_power_request_notify(ph, src_id, enable);
if (ret)
pr_debug("FAIL_ENABLE - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
@@ -226,7 +266,7 @@ static int scmi_power_set_notify_enabled(const void *handle,
return ret;
}
-static void *scmi_power_fill_custom_report(const void *handle,
+static void *scmi_power_fill_custom_report(const void *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -246,10 +286,10 @@ static void *scmi_power_fill_custom_report(const void *handle,
return r;
}
-static int scmi_power_get_num_sources(const void *handle)
+static int scmi_power_get_num_sources(const void *ph)
{
struct scmi_power_info *pinfo =
- ((const struct scmi_handle *)(handle))->power_priv;
+ ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
if (!pinfo)
return -EINVAL;
@@ -279,24 +319,25 @@ static const struct scmi_protocol_events power_protocol_events = {
.num_events = ARRAY_SIZE(power_events),
};
-static int scmi_power_protocol_init(struct scmi_handle *handle)
+static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
{
int domain;
u32 version;
struct scmi_power_info *pinfo;
+ struct scmi_handle *handle;
- scmi_version_get(handle, SCMI_PROTOCOL_POWER, &version);
+ ph->xops->version_get(ph, &version);
- dev_dbg(handle->dev, "Power Version %d.%d\n",
+ dev_dbg(ph->dev, "Power Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
- pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
+ pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
- scmi_power_attributes_get(handle, pinfo);
+ scmi_power_attributes_get(ph, pinfo);
- pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains,
+ pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains,
sizeof(*pinfo->dom_info), GFP_KERNEL);
if (!pinfo->dom_info)
return -ENOMEM;
@@ -304,20 +345,22 @@ static int scmi_power_protocol_init(struct scmi_handle *handle)
for (domain = 0; domain < pinfo->num_domains; domain++) {
struct power_dom_info *dom = pinfo->dom_info + domain;
- scmi_power_domain_attributes_get(handle, domain, dom);
+ scmi_power_domain_attributes_get(ph, domain, dom);
}
pinfo->version = version;
+
+ /* Transient code for legacy ops interface */
+ handle = scmi_map_scmi_handle(ph);
handle->power_ops = &power_ops;
- handle->power_priv = pinfo;
- return 0;
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_power = {
.id = SCMI_PROTOCOL_POWER,
- .init = &scmi_power_protocol_init,
- .ops = &power_ops,
+ .init_instance = &scmi_power_protocol_init,
+ .ops = &power_proto_ops,
.events = &power_protocol_events,
};
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 642c55a108ad..c038994e8adc 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -128,7 +128,7 @@ struct scmi_perf_proto_ops {
};
/**
- * struct scmi_power_ops - represents the various operations provided
+ * struct scmi_power_proto_ops - represents the various operations provided
* by SCMI Power Protocol
*
* @num_domains_get: get the count of power domains provided by SCMI
@@ -136,9 +136,9 @@ struct scmi_perf_proto_ops {
* @state_set: sets the power state of a power domain
* @state_get: gets the power state of a power domain
*/
-struct scmi_power_ops {
- int (*num_domains_get)(const struct scmi_handle *handle);
- char *(*name_get)(const struct scmi_handle *handle, u32 domain);
+struct scmi_power_proto_ops {
+ int (*num_domains_get)(const struct scmi_protocol_handle *ph);
+ char *(*name_get)(const struct scmi_protocol_handle *ph, u32 domain);
#define SCMI_POWER_STATE_TYPE_SHIFT 30
#define SCMI_POWER_STATE_ID_MASK (BIT(28) - 1)
#define SCMI_POWER_STATE_PARAM(type, id) \
@@ -146,6 +146,15 @@ struct scmi_power_ops {
((id) & SCMI_POWER_STATE_ID_MASK))
#define SCMI_POWER_STATE_GENERIC_ON SCMI_POWER_STATE_PARAM(0, 0)
#define SCMI_POWER_STATE_GENERIC_OFF SCMI_POWER_STATE_PARAM(1, 0)
+ int (*state_set)(const struct scmi_protocol_handle *ph, u32 domain,
+ u32 state);
+ int (*state_get)(const struct scmi_protocol_handle *ph, u32 domain,
+ u32 *state);
+};
+
+struct scmi_power_ops {
+ int (*num_domains_get)(const struct scmi_handle *handle);
+ char *(*name_get)(const struct scmi_handle *handle, u32 domain);
int (*state_set)(const struct scmi_handle *handle, u32 domain,
u32 state);
int (*state_get)(const struct scmi_handle *handle, u32 domain,
@@ -616,8 +625,6 @@ struct scmi_notify_ops {
* @notify_ops: pointer to set of notifications related operations
* @clk_priv: pointer to private data structure specific to clock
* protocol(for internal use only)
- * @power_priv: pointer to private data structure specific to power
- * protocol(for internal use only)
* @sensor_priv: pointer to private data structure specific to sensors
* protocol(for internal use only)
* @reset_priv: pointer to private data structure specific to reset
@@ -649,7 +656,6 @@ struct scmi_handle {
const struct scmi_notify_ops *notify_ops;
/* for protocol internal use */
void *clk_priv;
- void *power_priv;
void *sensor_priv;
void *reset_priv;
void *voltage_priv;
--
2.17.1
Add new core SCMI xfer operations based on protocol handles to enable
protocols to builds and send their own protocol specific messages.
Keep old original scmi_xfer_ operations interface as wrappers around the
new interface in order to let coexist old and new interfaces to ease
protocol by protocol migration.
In order to support such migration the above wrappers and some additional
transient code is also introduced in this commit: it will be later removed
as a whole once the full migration of protocols and SCMI drivers will have
been completed.
Signed-off-by: Cristian Marussi <[email protected]>
---
An exmaple of transient code:
scmi_map_protocol_handle() / scmi_map_scmi_handle()
and their usage will removed later on together with all the scmi_xfer
wrappers.
---
drivers/firmware/arm_scmi/common.h | 12 +-
drivers/firmware/arm_scmi/driver.c | 182 +++++++++++++++++++++++------
2 files changed, 158 insertions(+), 36 deletions(-)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 218a389f87b5..10ac5a6daf10 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -19,6 +19,8 @@
#include <asm/unaligned.h>
+#include "notify.h"
+
#define PROTOCOL_REV_MINOR_MASK GENMASK(15, 0)
#define PROTOCOL_REV_MAJOR_MASK GENMASK(31, 16)
#define PROTOCOL_REV_MAJOR(x) (u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x)))
@@ -179,6 +181,11 @@ struct scmi_protocol_handle {
void *(*get_priv)(const struct scmi_protocol_handle *ph);
};
+const struct scmi_protocol_handle *
+scmi_map_protocol_handle(const struct scmi_handle *handle, u8 prot_id);
+
+struct scmi_handle *scmi_map_scmi_handle(const struct scmi_protocol_handle *ph);
+
/**
* struct scmi_xfer_ops - References to the core SCMI xfer operations.
* @version_get: Get this version protocol.
@@ -217,6 +224,7 @@ void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
int scmi_base_protocol_init(struct scmi_handle *h);
typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *);
+typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
/**
* struct scmi_protocol - Protocol descriptor
@@ -231,8 +239,8 @@ typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *);
struct scmi_protocol {
const u8 id;
const scmi_prot_init_fn_t init;
- const scmi_prot_init_fn_t init_instance;
- const scmi_prot_init_fn_t deinit_instance;
+ const scmi_prot_init_ph_fn_t init_instance;
+ const scmi_prot_init_ph_fn_t deinit_instance;
const void *ops;
const struct scmi_protocol_events *events;
};
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index da0620318cab..d1357640bf07 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -349,19 +349,54 @@ void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr)
}
}
+/* Transient code wrapper to ease API migration */
+const struct scmi_protocol_handle *
+scmi_map_protocol_handle(const struct scmi_handle *handle, u8 prot_id)
+{
+ struct scmi_info *info = handle_to_scmi_info(handle);
+ const struct scmi_protocol_instance *pi;
+
+ mutex_lock(&info->protocols_mtx);
+ pi = idr_find(&info->protocols, prot_id);
+ mutex_unlock(&info->protocols_mtx);
+
+ return pi ? &pi->ph : NULL;
+}
+
+/* Transient code wrapper to ease API migration */
+struct scmi_handle *scmi_map_scmi_handle(const struct scmi_protocol_handle *ph)
+{
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+
+ return (struct scmi_handle *)pi->handle;
+}
+
/**
- * scmi_xfer_put() - Release a transmit message
+ * xfer_put() - Release a transmit message
*
- * @handle: Pointer to SCMI entity handle
+ * @ph: Pointer to SCMI protocol handle
* @xfer: message that was reserved by scmi_xfer_get
*/
-void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer)
+static void xfer_put(const struct scmi_protocol_handle *ph,
+ struct scmi_xfer *xfer)
{
- struct scmi_info *info = handle_to_scmi_info(handle);
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+ struct scmi_info *info = handle_to_scmi_info(pi->handle);
__scmi_xfer_put(&info->tx_minfo, xfer);
}
+void scmi_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer)
+{
+ const struct scmi_protocol_handle *ph;
+
+ ph = scmi_map_protocol_handle(h, xfer->hdr.protocol_id);
+ if (!ph)
+ return;
+
+ return xfer_put(ph, xfer);
+}
+
#define SCMI_MAX_POLL_TO_NS (100 * NSEC_PER_USEC)
static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
@@ -374,23 +409,32 @@ static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
}
/**
- * scmi_do_xfer() - Do one transfer
+ * do_xfer() - Do one transfer
*
- * @handle: Pointer to SCMI entity handle
+ * @ph: Pointer to SCMI protocol handle
* @xfer: Transfer to initiate and wait for response
*
* Return: -ETIMEDOUT in case of no response, if transmit error,
* return corresponding error, else if all goes well,
* return 0.
*/
-int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
+static int do_xfer(const struct scmi_protocol_handle *ph,
+ struct scmi_xfer *xfer)
{
int ret;
int timeout;
- struct scmi_info *info = handle_to_scmi_info(handle);
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+ struct scmi_info *info = handle_to_scmi_info(pi->handle);
struct device *dev = info->dev;
struct scmi_chan_info *cinfo;
+ /*
+ * Re-instate protocol id here from protocol handle so that cannot be
+ * overridden by mistake (or malice) by the protocol code mangling with
+ * the scmi_xfer structure.
+ */
+ xfer->hdr.protocol_id = pi->proto->id;
+
cinfo = idr_find(&info->tx_idr, xfer->hdr.protocol_id);
if (unlikely(!cinfo))
return -EINVAL;
@@ -436,35 +480,62 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
return ret;
}
+int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer)
+{
+ const struct scmi_protocol_handle *ph;
+
+ ph = scmi_map_protocol_handle(h, xfer->hdr.protocol_id);
+ if (!ph)
+ return -EINVAL;
+
+ return do_xfer(ph, xfer);
+}
+
+static void reset_rx_to_maxsz(const struct scmi_protocol_handle *ph,
+ struct scmi_xfer *xfer)
+{
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+ struct scmi_info *info = handle_to_scmi_info(pi->handle);
+
+ xfer->rx.len = info->desc->max_msg_size;
+}
+
void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle,
struct scmi_xfer *xfer)
{
- struct scmi_info *info = handle_to_scmi_info(handle);
+ const struct scmi_protocol_handle *ph;
- xfer->rx.len = info->desc->max_msg_size;
+ ph = scmi_map_protocol_handle(handle, xfer->hdr.protocol_id);
+ if (!ph)
+ return;
+
+ return reset_rx_to_maxsz(ph, xfer);
}
#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC)
/**
- * scmi_do_xfer_with_response() - Do one transfer and wait until the delayed
+ * do_xfer_with_response() - Do one transfer and wait until the delayed
* response is received
*
- * @handle: Pointer to SCMI entity handle
+ * @ph: Pointer to SCMI protocol handle
* @xfer: Transfer to initiate and wait for response
*
* Return: -ETIMEDOUT in case of no delayed response, if transmit error,
* return corresponding error, else if all goes well, return 0.
*/
-int scmi_do_xfer_with_response(const struct scmi_handle *handle,
- struct scmi_xfer *xfer)
+static int do_xfer_with_response(const struct scmi_protocol_handle *ph,
+ struct scmi_xfer *xfer)
{
int ret, timeout = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT);
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
DECLARE_COMPLETION_ONSTACK(async_response);
+ xfer->hdr.protocol_id = pi->proto->id;
+
xfer->async_done = &async_response;
- ret = scmi_do_xfer(handle, xfer);
+ ret = do_xfer(ph, xfer);
if (!ret && !wait_for_completion_timeout(xfer->async_done, timeout))
ret = -ETIMEDOUT;
@@ -472,12 +543,23 @@ int scmi_do_xfer_with_response(const struct scmi_handle *handle,
return ret;
}
+int scmi_do_xfer_with_response(const struct scmi_handle *h,
+ struct scmi_xfer *xfer)
+{
+ const struct scmi_protocol_handle *ph;
+
+ ph = scmi_map_protocol_handle(h, xfer->hdr.protocol_id);
+ if (!ph)
+ return -EINVAL;
+
+ return do_xfer_with_response(ph, xfer);
+}
+
/**
- * scmi_xfer_get_init() - Allocate and initialise one message for transmit
+ * xfer_get_init() - Allocate and initialise one message for transmit
*
- * @handle: Pointer to SCMI entity handle
+ * @ph: Pointer to SCMI protocol handle
* @msg_id: Message identifier
- * @prot_id: Protocol identifier for the message
* @tx_size: transmit message size
* @rx_size: receive message size
* @p: pointer to the allocated and initialised message
@@ -488,12 +570,14 @@ int scmi_do_xfer_with_response(const struct scmi_handle *handle,
* Return: 0 if all went fine with @p pointing to message, else
* corresponding error.
*/
-int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
- size_t tx_size, size_t rx_size, struct scmi_xfer **p)
+static int xfer_get_init(const struct scmi_protocol_handle *ph,
+ u8 msg_id, size_t tx_size, size_t rx_size,
+ struct scmi_xfer **p)
{
int ret;
struct scmi_xfer *xfer;
- struct scmi_info *info = handle_to_scmi_info(handle);
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+ struct scmi_info *info = handle_to_scmi_info(pi->handle);
struct scmi_xfers_info *minfo = &info->tx_minfo;
struct device *dev = info->dev;
@@ -502,7 +586,7 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
tx_size > info->desc->max_msg_size)
return -ERANGE;
- xfer = scmi_xfer_get(handle, minfo);
+ xfer = scmi_xfer_get(pi->handle, minfo);
if (IS_ERR(xfer)) {
ret = PTR_ERR(xfer);
dev_err(dev, "failed to get free message slot(%d)\n", ret);
@@ -512,7 +596,7 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
xfer->tx.len = tx_size;
xfer->rx.len = rx_size ? : info->desc->max_msg_size;
xfer->hdr.id = msg_id;
- xfer->hdr.protocol_id = prot_id;
+ xfer->hdr.protocol_id = pi->proto->id;
xfer->hdr.poll_completion = false;
*p = xfer;
@@ -520,39 +604,59 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
return 0;
}
+int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id,
+ size_t tx_size, size_t rx_size, struct scmi_xfer **p)
+{
+ const struct scmi_protocol_handle *ph;
+
+ ph = scmi_map_protocol_handle(h, prot_id);
+ if (!ph)
+ return -EINVAL;
+
+ return xfer_get_init(ph, msg_id, tx_size, rx_size, p);
+}
+
/**
- * scmi_version_get() - command to get the revision of the SCMI entity
+ * version_get() - command to get the revision of the SCMI entity
*
- * @handle: Pointer to SCMI entity handle
- * @protocol: Protocol identifier for the message
+ * @ph: Pointer to SCMI protocol handle
* @version: Holds returned version of protocol.
*
* Updates the SCMI information in the internal data structure.
*
* Return: 0 if all went fine, else return appropriate error.
*/
-int scmi_version_get(const struct scmi_handle *handle, u8 protocol,
- u32 *version)
+static int version_get(const struct scmi_protocol_handle *ph, u32 *version)
{
int ret;
__le32 *rev_info;
struct scmi_xfer *t;
- ret = scmi_xfer_get_init(handle, PROTOCOL_VERSION, protocol, 0,
- sizeof(*version), &t);
+ ret = xfer_get_init(ph, PROTOCOL_VERSION, 0, sizeof(*version), &t);
if (ret)
return ret;
- ret = scmi_do_xfer(handle, t);
+ ret = do_xfer(ph, t);
if (!ret) {
rev_info = t->rx.buf;
*version = le32_to_cpu(*rev_info);
}
- scmi_xfer_put(handle, t);
+ xfer_put(ph, t);
return ret;
}
+int scmi_version_get(const struct scmi_handle *h, u8 protocol, u32 *version)
+{
+ const struct scmi_protocol_handle *ph;
+
+ ph = scmi_map_protocol_handle(h, protocol);
+ if (!ph)
+ return -EINVAL;
+
+ return version_get(ph, version);
+}
+
/**
* scmi_set_protocol_priv - Set protocol specific data at init time
*
@@ -585,6 +689,15 @@ static void *scmi_get_protocol_priv(const struct scmi_protocol_handle *ph)
return pi->priv;
}
+static const struct scmi_xfer_ops xfer_ops = {
+ .version_get = version_get,
+ .xfer_get_init = xfer_get_init,
+ .reset_rx_to_maxsz = reset_rx_to_maxsz,
+ .do_xfer = do_xfer,
+ .do_xfer_with_response = do_xfer_with_response,
+ .xfer_put = xfer_put,
+};
+
/**
* scmi_get_protocol_instance - Protocol initialization helper.
* @handle: A reference to the SCMI platform instance.
@@ -632,11 +745,12 @@ scmi_get_protocol_instance(struct scmi_handle *handle, u8 protocol_id)
pi->proto = proto;
pi->handle = handle;
pi->ph.dev = handle->dev;
+ pi->ph.xops = &xfer_ops;
pi->ph.set_priv = scmi_set_protocol_priv;
pi->ph.get_priv = scmi_get_protocol_priv;
refcount_set(&pi->users, 1);
/* proto->init is assured NON NULL by scmi_protocol_register */
- ret = pi->proto->init_instance(handle);
+ ret = pi->proto->init_instance(&pi->ph);
if (ret)
goto clean;
@@ -705,7 +819,7 @@ void scmi_release_protocol(struct scmi_handle *handle, u8 protocol_id)
scmi_deregister_protocol_events(handle, protocol_id);
if (pi->proto->deinit_instance)
- pi->proto->deinit_instance(handle);
+ pi->proto->deinit_instance(&pi->ph);
idr_remove(&info->protocols, protocol_id);
--
2.17.1
Port driver to the new SCMI Perf interface based on protocol handles
and common devm_get_ops().
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/cpufreq/scmi-cpufreq.c | 37 ++++++++++++++++++----------------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c
index 491a0a24fb1e..520ecd03bf3e 100644
--- a/drivers/cpufreq/scmi-cpufreq.c
+++ b/drivers/cpufreq/scmi-cpufreq.c
@@ -25,17 +25,17 @@ struct scmi_data {
struct device *cpu_dev;
};
-static const struct scmi_handle *handle;
+static struct scmi_protocol_handle *ph;
+static const struct scmi_perf_proto_ops *perf_ops;
static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
- const struct scmi_perf_ops *perf_ops = handle->perf_ops;
struct scmi_data *priv = policy->driver_data;
unsigned long rate;
int ret;
- ret = perf_ops->freq_get(handle, priv->domain_id, &rate, false);
+ ret = perf_ops->freq_get(ph, priv->domain_id, &rate, false);
if (ret)
return 0;
return rate / 1000;
@@ -50,19 +50,17 @@ static int
scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
{
struct scmi_data *priv = policy->driver_data;
- const struct scmi_perf_ops *perf_ops = handle->perf_ops;
u64 freq = policy->freq_table[index].frequency;
- return perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false);
+ return perf_ops->freq_set(ph, priv->domain_id, freq * 1000, false);
}
static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq)
{
struct scmi_data *priv = policy->driver_data;
- const struct scmi_perf_ops *perf_ops = handle->perf_ops;
- if (!perf_ops->freq_set(handle, priv->domain_id,
+ if (!perf_ops->freq_set(ph, priv->domain_id,
target_freq * 1000, true))
return target_freq;
@@ -75,7 +73,7 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
int cpu, domain, tdomain;
struct device *tcpu_dev;
- domain = handle->perf_ops->device_domain_id(cpu_dev);
+ domain = perf_ops->device_domain_id(cpu_dev);
if (domain < 0)
return domain;
@@ -87,7 +85,7 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
if (!tcpu_dev)
continue;
- tdomain = handle->perf_ops->device_domain_id(tcpu_dev);
+ tdomain = perf_ops->device_domain_id(tcpu_dev);
if (tdomain == domain)
cpumask_set_cpu(cpu, cpumask);
}
@@ -102,13 +100,13 @@ scmi_get_cpu_power(unsigned long *power, unsigned long *KHz,
unsigned long Hz;
int ret, domain;
- domain = handle->perf_ops->device_domain_id(cpu_dev);
+ domain = perf_ops->device_domain_id(cpu_dev);
if (domain < 0)
return domain;
/* Get the power cost of the performance domain. */
Hz = *KHz * 1000;
- ret = handle->perf_ops->est_power_get(handle, domain, &Hz, power);
+ ret = perf_ops->est_power_get(ph, domain, &Hz, power);
if (ret)
return ret;
@@ -134,7 +132,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
return -ENODEV;
}
- ret = handle->perf_ops->device_opps_add(handle, cpu_dev);
+ ret = perf_ops->device_opps_add(ph, cpu_dev);
if (ret) {
dev_warn(cpu_dev, "failed to add opps to the device\n");
return ret;
@@ -173,7 +171,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
}
priv->cpu_dev = cpu_dev;
- priv->domain_id = handle->perf_ops->device_domain_id(cpu_dev);
+ priv->domain_id = perf_ops->device_domain_id(cpu_dev);
policy->driver_data = priv;
policy->freq_table = freq_table;
@@ -181,16 +179,16 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
/* SCMI allows DVFS request for any domain from any CPU */
policy->dvfs_possible_from_any_cpu = true;
- latency = handle->perf_ops->transition_latency_get(handle, cpu_dev);
+ latency = perf_ops->transition_latency_get(ph, cpu_dev);
if (!latency)
latency = CPUFREQ_ETERNAL;
policy->cpuinfo.transition_latency = latency;
policy->fast_switch_possible =
- handle->perf_ops->fast_switch_possible(handle, cpu_dev);
+ perf_ops->fast_switch_possible(ph, cpu_dev);
- power_scale_mw = handle->perf_ops->power_scale_mw_get(handle);
+ power_scale_mw = perf_ops->power_scale_mw_get(ph);
em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, policy->cpus,
power_scale_mw);
@@ -233,12 +231,17 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev)
{
int ret;
struct device *dev = &sdev->dev;
+ const struct scmi_handle *handle;
handle = sdev->handle;
- if (!handle || !handle->perf_ops)
+ if (!handle)
return -ENODEV;
+ perf_ops = handle->devm_get_ops(sdev, SCMI_PROTOCOL_PERF, &ph);
+ if (IS_ERR(perf_ops))
+ return PTR_ERR(perf_ops);
+
#ifdef CONFIG_COMMON_CLK
/* dummy clock provider as needed by OPP if clocks property is used */
if (of_find_property(dev->of_node, "#clock-cells", NULL))
--
2.17.1
Port driver to the new SCMI Power interface based on protocol handles
and common devm_get_ops().
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/scmi_pm_domain.c | 26 +++++++++++++---------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c
index 9e44479f0284..564bb4d56d9a 100644
--- a/drivers/firmware/arm_scmi/scmi_pm_domain.c
+++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c
@@ -2,7 +2,7 @@
/*
* SCMI Generic power domain support.
*
- * Copyright (C) 2018 ARM Ltd.
+ * Copyright (C) 2018-2020 ARM Ltd.
*/
#include <linux/err.h>
@@ -11,9 +11,11 @@
#include <linux/pm_domain.h>
#include <linux/scmi_protocol.h>
+static const struct scmi_power_proto_ops *power_ops;
+
struct scmi_pm_domain {
struct generic_pm_domain genpd;
- const struct scmi_handle *handle;
+ const struct scmi_protocol_handle *ph;
const char *name;
u32 domain;
};
@@ -25,16 +27,15 @@ static int scmi_pd_power(struct generic_pm_domain *domain, bool power_on)
int ret;
u32 state, ret_state;
struct scmi_pm_domain *pd = to_scmi_pd(domain);
- const struct scmi_power_ops *ops = pd->handle->power_ops;
if (power_on)
state = SCMI_POWER_STATE_GENERIC_ON;
else
state = SCMI_POWER_STATE_GENERIC_OFF;
- ret = ops->state_set(pd->handle, pd->domain, state);
+ ret = power_ops->state_set(pd->ph, pd->domain, state);
if (!ret)
- ret = ops->state_get(pd->handle, pd->domain, &ret_state);
+ ret = power_ops->state_get(pd->ph, pd->domain, &ret_state);
if (!ret && state != ret_state)
return -EIO;
@@ -60,11 +61,16 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
struct genpd_onecell_data *scmi_pd_data;
struct generic_pm_domain **domains;
const struct scmi_handle *handle = sdev->handle;
+ struct scmi_protocol_handle *ph;
- if (!handle || !handle->power_ops)
+ if (!handle)
return -ENODEV;
- num_domains = handle->power_ops->num_domains_get(handle);
+ power_ops = handle->devm_get_ops(sdev, SCMI_PROTOCOL_POWER, &ph);
+ if (IS_ERR(power_ops))
+ return PTR_ERR(power_ops);
+
+ num_domains = power_ops->num_domains_get(ph);
if (num_domains < 0) {
dev_err(dev, "number of domains not found\n");
return num_domains;
@@ -85,14 +91,14 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
for (i = 0; i < num_domains; i++, scmi_pd++) {
u32 state;
- if (handle->power_ops->state_get(handle, i, &state)) {
+ if (power_ops->state_get(ph, i, &state)) {
dev_warn(dev, "failed to get state for domain %d\n", i);
continue;
}
scmi_pd->domain = i;
- scmi_pd->handle = handle;
- scmi_pd->name = handle->power_ops->name_get(handle, i);
+ scmi_pd->ph = ph;
+ scmi_pd->name = power_ops->name_get(ph, i);
scmi_pd->genpd.name = scmi_pd->name;
scmi_pd->genpd.power_off = scmi_pd_power_off;
scmi_pd->genpd.power_on = scmi_pd_power_on;
--
2.17.1
Remove unused core scmi_xfer wrappers now that we have migrated all
protocols to the new interface based on protocol handles.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/common.h | 15 -----
drivers/firmware/arm_scmi/driver.c | 91 ------------------------------
2 files changed, 106 deletions(-)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 86f4fb707145..65db0aefc489 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -143,15 +143,6 @@ struct scmi_xfer {
struct completion *async_done;
};
-void scmi_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer);
-int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer);
-int scmi_do_xfer_with_response(const struct scmi_handle *h,
- struct scmi_xfer *xfer);
-int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id,
- size_t tx_size, size_t rx_size, struct scmi_xfer **p);
-void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle,
- struct scmi_xfer *xfer);
-
struct scmi_xfer_ops;
/**
@@ -181,11 +172,6 @@ struct scmi_protocol_handle {
void *(*get_priv)(const struct scmi_protocol_handle *ph);
};
-const struct scmi_protocol_handle *
-scmi_map_protocol_handle(const struct scmi_handle *handle, u8 prot_id);
-
-struct scmi_handle *scmi_map_scmi_handle(const struct scmi_protocol_handle *ph);
-
/**
* struct scmi_xfer_ops - References to the core SCMI xfer operations.
* @version_get: Get this version protocol.
@@ -220,7 +206,6 @@ scmi_get_revision_area(const struct scmi_protocol_handle *ph);
int scmi_handle_put(const struct scmi_handle *handle);
struct scmi_handle *scmi_handle_get(struct device *dev);
void scmi_set_handle(struct scmi_device *scmi_dev);
-int scmi_version_get(const struct scmi_handle *h, u8 protocol, u32 *version);
void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
u8 *prot_imp);
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 68a40d83325c..77e108475aea 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -349,28 +349,6 @@ void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr)
}
}
-/* Transient code wrapper to ease API migration */
-const struct scmi_protocol_handle *
-scmi_map_protocol_handle(const struct scmi_handle *handle, u8 prot_id)
-{
- struct scmi_info *info = handle_to_scmi_info(handle);
- const struct scmi_protocol_instance *pi;
-
- mutex_lock(&info->protocols_mtx);
- pi = idr_find(&info->protocols, prot_id);
- mutex_unlock(&info->protocols_mtx);
-
- return pi ? &pi->ph : NULL;
-}
-
-/* Transient code wrapper to ease API migration */
-struct scmi_handle *scmi_map_scmi_handle(const struct scmi_protocol_handle *ph)
-{
- const struct scmi_protocol_instance *pi = ph_to_pi(ph);
-
- return (struct scmi_handle *)pi->handle;
-}
-
/**
* xfer_put() - Release a transmit message
*
@@ -386,17 +364,6 @@ static void xfer_put(const struct scmi_protocol_handle *ph,
__scmi_xfer_put(&info->tx_minfo, xfer);
}
-void scmi_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer)
-{
- const struct scmi_protocol_handle *ph;
-
- ph = scmi_map_protocol_handle(h, xfer->hdr.protocol_id);
- if (!ph)
- return;
-
- return xfer_put(ph, xfer);
-}
-
#define SCMI_MAX_POLL_TO_NS (100 * NSEC_PER_USEC)
static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
@@ -480,17 +447,6 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
return ret;
}
-int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer)
-{
- const struct scmi_protocol_handle *ph;
-
- ph = scmi_map_protocol_handle(h, xfer->hdr.protocol_id);
- if (!ph)
- return -EINVAL;
-
- return do_xfer(ph, xfer);
-}
-
static void reset_rx_to_maxsz(const struct scmi_protocol_handle *ph,
struct scmi_xfer *xfer)
{
@@ -500,18 +456,6 @@ static void reset_rx_to_maxsz(const struct scmi_protocol_handle *ph,
xfer->rx.len = info->desc->max_msg_size;
}
-void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle,
- struct scmi_xfer *xfer)
-{
- const struct scmi_protocol_handle *ph;
-
- ph = scmi_map_protocol_handle(handle, xfer->hdr.protocol_id);
- if (!ph)
- return;
-
- return reset_rx_to_maxsz(ph, xfer);
-}
-
#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC)
/**
@@ -543,18 +487,6 @@ static int do_xfer_with_response(const struct scmi_protocol_handle *ph,
return ret;
}
-int scmi_do_xfer_with_response(const struct scmi_handle *h,
- struct scmi_xfer *xfer)
-{
- const struct scmi_protocol_handle *ph;
-
- ph = scmi_map_protocol_handle(h, xfer->hdr.protocol_id);
- if (!ph)
- return -EINVAL;
-
- return do_xfer_with_response(ph, xfer);
-}
-
/**
* xfer_get_init() - Allocate and initialise one message for transmit
*
@@ -604,18 +536,6 @@ static int xfer_get_init(const struct scmi_protocol_handle *ph,
return 0;
}
-int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id,
- size_t tx_size, size_t rx_size, struct scmi_xfer **p)
-{
- const struct scmi_protocol_handle *ph;
-
- ph = scmi_map_protocol_handle(h, prot_id);
- if (!ph)
- return -EINVAL;
-
- return xfer_get_init(ph, msg_id, tx_size, rx_size, p);
-}
-
/**
* version_get() - command to get the revision of the SCMI entity
*
@@ -646,17 +566,6 @@ static int version_get(const struct scmi_protocol_handle *ph, u32 *version)
return ret;
}
-int scmi_version_get(const struct scmi_handle *h, u8 protocol, u32 *version)
-{
- const struct scmi_protocol_handle *ph;
-
- ph = scmi_map_protocol_handle(h, protocol);
- if (!ph)
- return -EINVAL;
-
- return version_get(ph, version);
-}
-
/**
* scmi_set_protocol_priv - Set protocol specific data at init time
*
--
2.17.1
Remove all the events registration code used to ease the transition to the
new interface based on protocol handles..
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/base.c | 4 ++--
drivers/firmware/arm_scmi/notify.h | 6 +++---
drivers/firmware/arm_scmi/perf.c | 9 ++++-----
drivers/firmware/arm_scmi/power.c | 16 ++++++++--------
drivers/firmware/arm_scmi/reset.c | 16 ++++++++--------
drivers/firmware/arm_scmi/sensors.c | 19 +++++++++----------
drivers/firmware/arm_scmi/system.c | 11 ++++++-----
7 files changed, 40 insertions(+), 41 deletions(-)
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index c9e5e451b377..f2d10c5a55ae 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -264,7 +264,7 @@ static int scmi_base_error_notify(const struct scmi_protocol_handle *ph,
return ret;
}
-static int scmi_base_set_notify_enabled(const void *ph,
+static int scmi_base_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -276,7 +276,7 @@ static int scmi_base_set_notify_enabled(const void *ph,
return ret;
}
-static void *scmi_base_fill_custom_report(const void *ph,
+static void *scmi_base_fill_custom_report(const struct scmi_protocol_handle *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
diff --git a/drivers/firmware/arm_scmi/notify.h b/drivers/firmware/arm_scmi/notify.h
index 2281a740ae96..3915bcd76242 100644
--- a/drivers/firmware/arm_scmi/notify.h
+++ b/drivers/firmware/arm_scmi/notify.h
@@ -50,10 +50,10 @@ struct scmi_protocol_handle;
* process context.
*/
struct scmi_event_ops {
- int (*get_num_sources)(const void *handle);
- int (*set_notify_enabled)(const void *handle,
+ int (*get_num_sources)(const struct scmi_protocol_handle *ph);
+ int (*set_notify_enabled)(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enabled);
- void *(*fill_custom_report)(const void *handle,
+ void *(*fill_custom_report)(const struct scmi_protocol_handle *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id);
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index b2e1bdad2b3a..c87a390463d9 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -769,7 +769,7 @@ static const struct scmi_perf_proto_ops perf_proto_ops = {
.power_scale_mw_get = scmi_power_scale_mw_get,
};
-static int scmi_perf_set_notify_enabled(const void *ph,
+static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret, cmd_id;
@@ -786,7 +786,7 @@ static int scmi_perf_set_notify_enabled(const void *ph,
return ret;
}
-static void *scmi_perf_fill_custom_report(const void *ph,
+static void *scmi_perf_fill_custom_report(const struct scmi_protocol_handle *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -834,10 +834,9 @@ static void *scmi_perf_fill_custom_report(const void *ph,
return rep;
}
-static int scmi_perf_get_num_sources(const void *ph)
+static int scmi_perf_get_num_sources(const struct scmi_protocol_handle *ph)
{
- struct scmi_perf_info *pi =
- ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
+ struct scmi_perf_info *pi = ph->get_priv(ph);
if (!pi)
return -EINVAL;
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index 06e3ab17a0eb..3e453d9bcbc8 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -211,7 +211,7 @@ static int scmi_power_request_notify(const struct scmi_protocol_handle *ph,
return ret;
}
-static int scmi_power_set_notify_enabled(const void *ph,
+static int scmi_power_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -224,10 +224,11 @@ static int scmi_power_set_notify_enabled(const void *ph,
return ret;
}
-static void *scmi_power_fill_custom_report(const void *ph,
- u8 evt_id, ktime_t timestamp,
- const void *payld, size_t payld_sz,
- void *report, u32 *src_id)
+static void *
+scmi_power_fill_custom_report(const struct scmi_protocol_handle *ph,
+ u8 evt_id, ktime_t timestamp,
+ const void *payld, size_t payld_sz,
+ void *report, u32 *src_id)
{
const struct scmi_power_state_notify_payld *p = payld;
struct scmi_power_state_changed_report *r = report;
@@ -244,10 +245,9 @@ static void *scmi_power_fill_custom_report(const void *ph,
return r;
}
-static int scmi_power_get_num_sources(const void *ph)
+static int scmi_power_get_num_sources(const struct scmi_protocol_handle *ph)
{
- struct scmi_power_info *pinfo =
- ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
+ struct scmi_power_info *pinfo = ph->get_priv(ph);
if (!pinfo)
return -EINVAL;
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index 3856ceed2bd7..bd28d4e9664d 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -225,7 +225,7 @@ static int scmi_reset_notify(const struct scmi_protocol_handle *ph,
return ret;
}
-static int scmi_reset_set_notify_enabled(const void *ph,
+static int scmi_reset_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -238,10 +238,11 @@ static int scmi_reset_set_notify_enabled(const void *ph,
return ret;
}
-static void *scmi_reset_fill_custom_report(const void *ph,
- u8 evt_id, ktime_t timestamp,
- const void *payld, size_t payld_sz,
- void *report, u32 *src_id)
+static void *
+scmi_reset_fill_custom_report(const struct scmi_protocol_handle *ph,
+ u8 evt_id, ktime_t timestamp,
+ const void *payld, size_t payld_sz,
+ void *report, u32 *src_id)
{
const struct scmi_reset_issued_notify_payld *p = payld;
struct scmi_reset_issued_report *r = report;
@@ -258,10 +259,9 @@ static void *scmi_reset_fill_custom_report(const void *ph,
return r;
}
-static int scmi_reset_get_num_sources(const void *ph)
+static int scmi_reset_get_num_sources(const struct scmi_protocol_handle *ph)
{
- struct scmi_reset_info *pinfo =
- ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
+ struct scmi_reset_info *pinfo = ph->get_priv(ph);
if (!pinfo)
return -EINVAL;
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 478585f644fa..edc08d9f8daa 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -834,7 +834,7 @@ static const struct scmi_sensor_proto_ops sensor_proto_ops = {
.config_set = scmi_sensor_config_set,
};
-static int scmi_sensor_set_notify_enabled(const void *ph,
+static int scmi_sensor_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -858,10 +858,11 @@ static int scmi_sensor_set_notify_enabled(const void *ph,
return ret;
}
-static void *scmi_sensor_fill_custom_report(const void *ph,
- u8 evt_id, ktime_t timestamp,
- const void *payld, size_t payld_sz,
- void *report, u32 *src_id)
+static void *
+scmi_sensor_fill_custom_report(const struct scmi_protocol_handle *ph,
+ u8 evt_id, ktime_t timestamp,
+ const void *payld, size_t payld_sz,
+ void *report, u32 *src_id)
{
void *rep = NULL;
@@ -888,8 +889,7 @@ static void *scmi_sensor_fill_custom_report(const void *ph,
struct scmi_sensor_info *s;
const struct scmi_sensor_update_notify_payld *p = payld;
struct scmi_sensor_update_report *r = report;
- struct sensors_info *sinfo =
- ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
+ struct sensors_info *sinfo = ph->get_priv(ph);
/* payld_sz is variable for this event */
r->sensor_id = le32_to_cpu(p->sensor_id);
@@ -919,10 +919,9 @@ static void *scmi_sensor_fill_custom_report(const void *ph,
return rep;
}
-static int scmi_sensor_get_num_sources(const void *ph)
+static int scmi_sensor_get_num_sources(const struct scmi_protocol_handle *ph)
{
- struct sensors_info *si =
- ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
+ struct sensors_info *si = ph->get_priv(ph);
return si->num_sensors;
}
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
index a23c1f505b56..97ad20a51d72 100644
--- a/drivers/firmware/arm_scmi/system.c
+++ b/drivers/firmware/arm_scmi/system.c
@@ -53,7 +53,7 @@ static int scmi_system_request_notify(const struct scmi_protocol_handle *ph,
return ret;
}
-static int scmi_system_set_notify_enabled(const void *ph,
+static int scmi_system_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -65,10 +65,11 @@ static int scmi_system_set_notify_enabled(const void *ph,
return ret;
}
-static void *scmi_system_fill_custom_report(const void *ph,
- u8 evt_id, ktime_t timestamp,
- const void *payld, size_t payld_sz,
- void *report, u32 *src_id)
+static void *
+scmi_system_fill_custom_report(const struct scmi_protocol_handle *ph,
+ 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;
--
2.17.1
Convert refactored events registration routines to use protocol handles.
In order to maintain bisectability and to allow protocols and drivers
to be later ported to the new protocol handle interface one by one,
introduce here also some transient code and typing that will be removed
later in order to ease such transition.
Signed-off-by: Cristian Marussi <[email protected]>
---
In particular void* argument typing will be reverted later on once all
the protocols have been ported.
---
drivers/firmware/arm_scmi/base.c | 4 ++--
drivers/firmware/arm_scmi/driver.c | 1 +
drivers/firmware/arm_scmi/notify.c | 13 +++++++++----
drivers/firmware/arm_scmi/notify.h | 7 ++++---
drivers/firmware/arm_scmi/perf.c | 9 +++++----
drivers/firmware/arm_scmi/power.c | 9 +++++----
drivers/firmware/arm_scmi/reset.c | 9 +++++----
drivers/firmware/arm_scmi/sensors.c | 12 +++++++-----
drivers/firmware/arm_scmi/system.c | 4 ++--
9 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index 2fe76827e627..e7c21e925ea2 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -262,7 +262,7 @@ static int scmi_base_error_notify(const struct scmi_handle *handle, bool enable)
return ret;
}
-static int scmi_base_set_notify_enabled(const struct scmi_handle *handle,
+static int scmi_base_set_notify_enabled(const void *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -274,7 +274,7 @@ static int scmi_base_set_notify_enabled(const struct scmi_handle *handle,
return ret;
}
-static void *scmi_base_fill_custom_report(const struct scmi_handle *handle,
+static void *scmi_base_fill_custom_report(const void *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 2740c28928c7..da0620318cab 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -647,6 +647,7 @@ scmi_get_protocol_instance(struct scmi_handle *handle, u8 protocol_id)
if (pi->proto->events)
scmi_register_protocol_events(handle, pi->proto->id,
+ &pi->ph,
pi->proto->events);
devres_close_group(handle->dev, pi->gid);
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 8b4af3847bfa..d88bc9960c7c 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -178,7 +178,7 @@
#define REVT_NOTIFY_SET_STATUS(revt, eid, sid, state) \
({ \
typeof(revt) r = revt; \
- r->proto->ops->set_notify_enabled(r->proto->ni->handle, \
+ r->proto->ops->set_notify_enabled(r->proto->ph, \
(eid), (sid), (state)); \
})
@@ -191,7 +191,7 @@
#define REVT_FILL_REPORT(revt, ...) \
({ \
typeof(revt) r = revt; \
- r->proto->ops->fill_custom_report(r->proto->ni->handle, \
+ r->proto->ops->fill_custom_report(r->proto->ph, \
__VA_ARGS__); \
})
@@ -279,6 +279,7 @@ struct scmi_registered_event;
* events' descriptors, whose fixed-size is determined at
* compile time.
* @registered_mtx: A mutex to protect @registered_events_handlers
+ * @ph: SCMI protocol handle reference
* @registered_events_handlers: An hashtable containing all events' handlers
* descriptors registered for this protocol
*
@@ -303,6 +304,7 @@ struct scmi_registered_events_desc {
struct scmi_registered_event **registered_events;
/* mutex to protect registered_events_handlers */
struct mutex registered_mtx;
+ const struct scmi_protocol_handle *ph;
DECLARE_HASHTABLE(registered_events_handlers, SCMI_REGISTERED_HASH_SZ);
};
@@ -735,6 +737,7 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni,
* @handle: The handle identifying the platform instance against which the
* protocol's events are registered
* @proto_id: Protocol ID
+ * @ph: SCMI protocol handle.
* @ee: A structure describing the events supported by this protocol.
*
* Used by SCMI Protocols initialization code to register with the notification
@@ -745,6 +748,7 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni,
* Return: 0 on Success
*/
int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
+ const struct scmi_protocol_handle *ph,
const struct scmi_protocol_events *ee)
{
int i;
@@ -754,7 +758,7 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
struct scmi_notify_instance *ni;
const struct scmi_event *evt;
- if (!ee || !ee->ops || !ee->evts ||
+ if (!ee || !ee->ops || !ee->evts || !ph ||
(!ee->num_sources && !ee->ops->get_num_sources))
return -EINVAL;
@@ -768,7 +772,7 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
if (ee->num_sources) {
num_sources = ee->num_sources;
} else {
- int nsrc = ee->ops->get_num_sources(handle);
+ int nsrc = ee->ops->get_num_sources(ph);
if (nsrc <= 0)
return -EINVAL;
@@ -786,6 +790,7 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
if (IS_ERR(pd))
goto err;
+ pd->ph = ph;
for (i = 0; i < ee->num_events; i++, evt++) {
struct scmi_registered_event *r_evt;
diff --git a/drivers/firmware/arm_scmi/notify.h b/drivers/firmware/arm_scmi/notify.h
index 97ddfe55d773..2281a740ae96 100644
--- a/drivers/firmware/arm_scmi/notify.h
+++ b/drivers/firmware/arm_scmi/notify.h
@@ -50,10 +50,10 @@ struct scmi_protocol_handle;
* process context.
*/
struct scmi_event_ops {
- int (*get_num_sources)(const struct scmi_handle *handle);
- int (*set_notify_enabled)(const struct scmi_handle *handle,
+ int (*get_num_sources)(const void *handle);
+ int (*set_notify_enabled)(const void *handle,
u8 evt_id, u32 src_id, bool enabled);
- void *(*fill_custom_report)(const struct scmi_handle *handle,
+ void *(*fill_custom_report)(const void *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id);
@@ -82,6 +82,7 @@ void scmi_notification_exit(struct scmi_handle *handle);
struct scmi_protocol_handle;
int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
+ const struct scmi_protocol_handle *ph,
const struct scmi_protocol_events *ee);
void scmi_deregister_protocol_events(const struct scmi_handle *handle,
u8 proto_id);
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index b3160bd5ad0b..f27a0afbe65a 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -772,7 +772,7 @@ static const struct scmi_perf_ops perf_ops = {
.power_scale_mw_get = scmi_power_scale_mw_get,
};
-static int scmi_perf_set_notify_enabled(const struct scmi_handle *handle,
+static int scmi_perf_set_notify_enabled(const void *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret, cmd_id;
@@ -789,7 +789,7 @@ static int scmi_perf_set_notify_enabled(const struct scmi_handle *handle,
return ret;
}
-static void *scmi_perf_fill_custom_report(const struct scmi_handle *handle,
+static void *scmi_perf_fill_custom_report(const void *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -837,9 +837,10 @@ static void *scmi_perf_fill_custom_report(const struct scmi_handle *handle,
return rep;
}
-static int scmi_perf_get_num_sources(const struct scmi_handle *handle)
+static int scmi_perf_get_num_sources(const void *handle)
{
- struct scmi_perf_info *pi = handle->perf_priv;
+ struct scmi_perf_info *pi =
+ ((const struct scmi_handle *)(handle))->perf_priv;
if (!pi)
return -EINVAL;
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index 6db02dc547a7..e4c084ca92e4 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -213,7 +213,7 @@ static int scmi_power_request_notify(const struct scmi_handle *handle,
return ret;
}
-static int scmi_power_set_notify_enabled(const struct scmi_handle *handle,
+static int scmi_power_set_notify_enabled(const void *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -226,7 +226,7 @@ static int scmi_power_set_notify_enabled(const struct scmi_handle *handle,
return ret;
}
-static void *scmi_power_fill_custom_report(const struct scmi_handle *handle,
+static void *scmi_power_fill_custom_report(const void *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -246,9 +246,10 @@ static void *scmi_power_fill_custom_report(const struct scmi_handle *handle,
return r;
}
-static int scmi_power_get_num_sources(const struct scmi_handle *handle)
+static int scmi_power_get_num_sources(const void *handle)
{
- struct scmi_power_info *pinfo = handle->power_priv;
+ struct scmi_power_info *pinfo =
+ ((const struct scmi_handle *)(handle))->power_priv;
if (!pinfo)
return -EINVAL;
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index 7102cfeb2397..7047e5baecc2 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -224,7 +224,7 @@ static int scmi_reset_notify(const struct scmi_handle *handle, u32 domain_id,
return ret;
}
-static int scmi_reset_set_notify_enabled(const struct scmi_handle *handle,
+static int scmi_reset_set_notify_enabled(const void *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -237,7 +237,7 @@ static int scmi_reset_set_notify_enabled(const struct scmi_handle *handle,
return ret;
}
-static void *scmi_reset_fill_custom_report(const struct scmi_handle *handle,
+static void *scmi_reset_fill_custom_report(const void *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -257,9 +257,10 @@ static void *scmi_reset_fill_custom_report(const struct scmi_handle *handle,
return r;
}
-static int scmi_reset_get_num_sources(const struct scmi_handle *handle)
+static int scmi_reset_get_num_sources(const void *handle)
{
- struct scmi_reset_info *pinfo = handle->reset_priv;
+ struct scmi_reset_info *pinfo =
+ ((const struct scmi_handle *)(handle))->reset_priv;
if (!pinfo)
return -EINVAL;
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 526e2236929c..e1e428d59d5f 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -835,7 +835,7 @@ static const struct scmi_sensor_ops sensor_ops = {
.config_set = scmi_sensor_config_set,
};
-static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle,
+static int scmi_sensor_set_notify_enabled(const void *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -860,7 +860,7 @@ static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle,
return ret;
}
-static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle,
+static void *scmi_sensor_fill_custom_report(const void *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -890,7 +890,8 @@ static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle,
struct scmi_sensor_info *s;
const struct scmi_sensor_update_notify_payld *p = payld;
struct scmi_sensor_update_report *r = report;
- struct sensors_info *sinfo = handle->sensor_priv;
+ struct sensors_info *sinfo =
+ ((const struct scmi_handle *)(handle))->sensor_priv;
/* payld_sz is variable for this event */
r->sensor_id = le32_to_cpu(p->sensor_id);
@@ -920,9 +921,10 @@ static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle,
return rep;
}
-static int scmi_sensor_get_num_sources(const struct scmi_handle *handle)
+static int scmi_sensor_get_num_sources(const void *handle)
{
- struct sensors_info *si = handle->sensor_priv;
+ struct sensors_info *si =
+ ((const struct scmi_handle *)(handle))->sensor_priv;
return si->num_sensors;
}
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
index 167f539f7d95..6690610c2c26 100644
--- a/drivers/firmware/arm_scmi/system.c
+++ b/drivers/firmware/arm_scmi/system.c
@@ -53,7 +53,7 @@ static int scmi_system_request_notify(const struct scmi_handle *handle,
return ret;
}
-static int scmi_system_set_notify_enabled(const struct scmi_handle *handle,
+static int scmi_system_set_notify_enabled(const void *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
@@ -65,7 +65,7 @@ static int scmi_system_set_notify_enabled(const struct scmi_handle *handle,
return ret;
}
-static void *scmi_system_fill_custom_report(const struct scmi_handle *handle,
+static void *scmi_system_fill_custom_report(const void *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
--
2.17.1
Convert internals of protocol implementation to use protocol handles and
expose a new protocol operations interface for SCMI driver using the new
get/put common operations, while keeping the old handle->clk_ops still
around to ease transition.
Remove handle->clock_priv now unused.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/clock.c | 182 ++++++++++++++++++++----------
include/linux/scmi_protocol.h | 20 +++-
2 files changed, 139 insertions(+), 63 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index e8c84cff9922..bf7dcd537fce 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -74,52 +74,53 @@ struct clock_info {
struct scmi_clock_info *clk;
};
-static int scmi_clock_protocol_attributes_get(const struct scmi_handle *handle,
- struct clock_info *ci)
+static int
+scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph,
+ struct clock_info *ci)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_clock_protocol_attributes *attr;
- ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
- SCMI_PROTOCOL_CLOCK, 0, sizeof(*attr), &t);
+ ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
+ 0, sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
ci->num_clocks = le16_to_cpu(attr->num_clocks);
ci->max_async_req = attr->max_async_req;
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_clock_attributes_get(const struct scmi_handle *handle,
+static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
u32 clk_id, struct scmi_clock_info *clk)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_clock_attributes *attr;
- ret = scmi_xfer_get_init(handle, CLOCK_ATTRIBUTES, SCMI_PROTOCOL_CLOCK,
- sizeof(clk_id), sizeof(*attr), &t);
+ ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES,
+ sizeof(clk_id), sizeof(*attr), &t);
if (ret)
return ret;
put_unaligned_le32(clk_id, t->tx.buf);
attr = t->rx.buf;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
strlcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE);
else
clk->name[0] = '\0';
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -136,7 +137,7 @@ static int rate_cmp_func(const void *_r1, const void *_r2)
}
static int
-scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
+scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
struct scmi_clock_info *clk)
{
u64 *rate = NULL;
@@ -148,8 +149,8 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
struct scmi_msg_clock_describe_rates *clk_desc;
struct scmi_msg_resp_clock_describe_rates *rlist;
- ret = scmi_xfer_get_init(handle, CLOCK_DESCRIBE_RATES,
- SCMI_PROTOCOL_CLOCK, sizeof(*clk_desc), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, CLOCK_DESCRIBE_RATES,
+ sizeof(*clk_desc), 0, &t);
if (ret)
return ret;
@@ -161,7 +162,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
/* Set the number of rates to be skipped/already read */
clk_desc->rate_index = cpu_to_le32(tot_rate_cnt);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (ret)
goto err;
@@ -171,7 +172,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
num_returned = NUM_RETURNED(rates_flag);
if (tot_rate_cnt + num_returned > SCMI_MAX_NUM_RATES) {
- dev_err(handle->dev, "No. of rates > MAX_NUM_RATES");
+ dev_err(ph->dev, "No. of rates > MAX_NUM_RATES");
break;
}
@@ -179,7 +180,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
clk->range.min_rate = RATE_TO_U64(rlist->rate[0]);
clk->range.max_rate = RATE_TO_U64(rlist->rate[1]);
clk->range.step_size = RATE_TO_U64(rlist->rate[2]);
- dev_dbg(handle->dev, "Min %llu Max %llu Step %llu Hz\n",
+ dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n",
clk->range.min_rate, clk->range.max_rate,
clk->range.step_size);
break;
@@ -188,12 +189,12 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
rate = &clk->list.rates[tot_rate_cnt];
for (cnt = 0; cnt < num_returned; cnt++, rate++) {
*rate = RATE_TO_U64(rlist->rate[cnt]);
- dev_dbg(handle->dev, "Rate %llu Hz\n", *rate);
+ dev_dbg(ph->dev, "Rate %llu Hz\n", *rate);
}
tot_rate_cnt += num_returned;
- scmi_reset_rx_to_maxsz(handle, t);
+ ph->xops->reset_rx_to_maxsz(ph, t);
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
@@ -208,42 +209,52 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
clk->rate_discrete = rate_discrete;
err:
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
static int
-scmi_clock_rate_get(const struct scmi_handle *handle, u32 clk_id, u64 *value)
+scmi_clock_rate_get(const struct scmi_protocol_handle *ph,
+ u32 clk_id, u64 *value)
{
int ret;
struct scmi_xfer *t;
- ret = scmi_xfer_get_init(handle, CLOCK_RATE_GET, SCMI_PROTOCOL_CLOCK,
- sizeof(__le32), sizeof(u64), &t);
+ ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_GET,
+ sizeof(__le32), sizeof(u64), &t);
if (ret)
return ret;
put_unaligned_le32(clk_id, t->tx.buf);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
*value = get_unaligned_le64(t->rx.buf);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id,
- u64 rate)
+static int
+__scmi_clock_rate_get(const struct scmi_handle *handle,
+ u32 clk_id, u64 *value)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
+
+ return scmi_clock_rate_get(ph, clk_id, value);
+}
+
+static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
+ u32 clk_id, u64 rate)
{
int ret;
u32 flags = 0;
struct scmi_xfer *t;
struct scmi_clock_set_rate *cfg;
- struct clock_info *ci = handle->clk_priv;
+ struct clock_info *ci = ph->get_priv(ph);
- ret = scmi_xfer_get_init(handle, CLOCK_RATE_SET, SCMI_PROTOCOL_CLOCK,
- sizeof(*cfg), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_SET, sizeof(*cfg), 0, &t);
if (ret)
return ret;
@@ -258,26 +269,36 @@ static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id,
cfg->value_high = cpu_to_le32(rate >> 32);
if (flags & CLOCK_SET_ASYNC)
- ret = scmi_do_xfer_with_response(handle, t);
+ ret = ph->xops->do_xfer_with_response(ph, t);
else
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (ci->max_async_req)
atomic_dec(&ci->cur_async_req);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
+static int __scmi_clock_rate_set(const struct scmi_handle *handle,
+ u32 clk_id, u64 rate)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
+
+ return scmi_clock_rate_set(ph, clk_id, rate);
+}
+
static int
-scmi_clock_config_set(const struct scmi_handle *handle, u32 clk_id, u32 config)
+scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
+ u32 config)
{
int ret;
struct scmi_xfer *t;
struct scmi_clock_set_config *cfg;
- ret = scmi_xfer_get_init(handle, CLOCK_CONFIG_SET, SCMI_PROTOCOL_CLOCK,
- sizeof(*cfg), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, CLOCK_CONFIG_SET,
+ sizeof(*cfg), 0, &t);
if (ret)
return ret;
@@ -285,33 +306,57 @@ scmi_clock_config_set(const struct scmi_handle *handle, u32 clk_id, u32 config)
cfg->id = cpu_to_le32(clk_id);
cfg->attributes = cpu_to_le32(config);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_clock_enable(const struct scmi_handle *handle, u32 clk_id)
+static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id)
+{
+ return scmi_clock_config_set(ph, clk_id, CLOCK_ENABLE);
+}
+
+static int __scmi_clock_enable(const struct scmi_handle *handle, u32 clk_id)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
+
+ return scmi_clock_enable(ph, clk_id);
+}
+
+static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id)
{
- return scmi_clock_config_set(handle, clk_id, CLOCK_ENABLE);
+ return scmi_clock_config_set(ph, clk_id, 0);
}
-static int scmi_clock_disable(const struct scmi_handle *handle, u32 clk_id)
+static int __scmi_clock_disable(const struct scmi_handle *handle, u32 clk_id)
{
- return scmi_clock_config_set(handle, clk_id, 0);
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
+
+ return scmi_clock_disable(ph, clk_id);
}
-static int scmi_clock_count_get(const struct scmi_handle *handle)
+static int scmi_clock_count_get(const struct scmi_protocol_handle *ph)
{
- struct clock_info *ci = handle->clk_priv;
+ struct clock_info *ci = ph->get_priv(ph);
return ci->num_clocks;
}
+static int __scmi_clock_count_get(const struct scmi_handle *handle)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
+
+ return scmi_clock_count_get(ph);
+}
+
static const struct scmi_clock_info *
-scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id)
+scmi_clock_info_get(const struct scmi_protocol_handle *ph, u32 clk_id)
{
- struct clock_info *ci = handle->clk_priv;
+ struct clock_info *ci = ph->get_priv(ph);
struct scmi_clock_info *clk = ci->clk + clk_id;
if (!clk->name[0])
@@ -320,7 +365,25 @@ scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id)
return clk;
}
+static const struct scmi_clock_info *
+__scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_CLOCK);
+
+ return scmi_clock_info_get(ph, clk_id);
+}
+
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,
+ .rate_set = __scmi_clock_rate_set,
+ .enable = __scmi_clock_enable,
+ .disable = __scmi_clock_disable,
+};
+
+static const struct scmi_clk_proto_ops clk_proto_ops = {
.count_get = scmi_clock_count_get,
.info_get = scmi_clock_info_get,
.rate_get = scmi_clock_rate_get,
@@ -329,24 +392,25 @@ static const struct scmi_clk_ops clk_ops = {
.disable = scmi_clock_disable,
};
-static int scmi_clock_protocol_init(struct scmi_handle *handle)
+static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
{
u32 version;
int clkid, ret;
struct clock_info *cinfo;
+ struct scmi_handle *handle;
- scmi_version_get(handle, SCMI_PROTOCOL_CLOCK, &version);
+ ph->xops->version_get(ph, &version);
- dev_dbg(handle->dev, "Clock Version %d.%d\n",
+ dev_dbg(ph->dev, "Clock Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
- cinfo = devm_kzalloc(handle->dev, sizeof(*cinfo), GFP_KERNEL);
+ cinfo = devm_kzalloc(ph->dev, sizeof(*cinfo), GFP_KERNEL);
if (!cinfo)
return -ENOMEM;
- scmi_clock_protocol_attributes_get(handle, cinfo);
+ scmi_clock_protocol_attributes_get(ph, cinfo);
- cinfo->clk = devm_kcalloc(handle->dev, cinfo->num_clocks,
+ cinfo->clk = devm_kcalloc(ph->dev, cinfo->num_clocks,
sizeof(*cinfo->clk), GFP_KERNEL);
if (!cinfo->clk)
return -ENOMEM;
@@ -354,22 +418,24 @@ static int scmi_clock_protocol_init(struct scmi_handle *handle)
for (clkid = 0; clkid < cinfo->num_clocks; clkid++) {
struct scmi_clock_info *clk = cinfo->clk + clkid;
- ret = scmi_clock_attributes_get(handle, clkid, clk);
+ ret = scmi_clock_attributes_get(ph, clkid, clk);
if (!ret)
- scmi_clock_describe_rates_get(handle, clkid, clk);
+ scmi_clock_describe_rates_get(ph, clkid, clk);
}
cinfo->version = version;
+
+ /* Transient code for legacy ops interface */
+ handle = scmi_map_scmi_handle(ph);
handle->clk_ops = &clk_ops;
- handle->clk_priv = cinfo;
- return 0;
+ return ph->set_priv(ph, cinfo);
}
static const struct scmi_protocol scmi_clock = {
.id = SCMI_PROTOCOL_CLOCK,
- .init = &scmi_clock_protocol_init,
- .ops = &clk_ops,
+ .init_instance = &scmi_clock_protocol_init,
+ .ops = &clk_proto_ops,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock)
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 73d734eda954..a403035df0ef 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -61,7 +61,7 @@ struct scmi_device;
struct scmi_protocol_handle;
/**
- * struct scmi_clk_ops - represents the various operations provided
+ * struct scmi_clk_proto_ops - represents the various operations provided
* by SCMI Clock Protocol
*
* @count_get: get the count of clocks provided by SCMI
@@ -71,8 +71,21 @@ struct scmi_protocol_handle;
* @enable: enables the specified clock
* @disable: disables the specified clock
*/
+struct scmi_clk_proto_ops {
+ int (*count_get)(const struct scmi_protocol_handle *ph);
+
+ const struct scmi_clock_info *(*info_get)
+ (const struct scmi_protocol_handle *ph, u32 clk_id);
+ int (*rate_get)(const struct scmi_protocol_handle *ph, u32 clk_id,
+ u64 *rate);
+ int (*rate_set)(const struct scmi_protocol_handle *ph, u32 clk_id,
+ u64 rate);
+ int (*enable)(const struct scmi_protocol_handle *ph, u32 clk_id);
+ int (*disable)(const struct scmi_protocol_handle *ph, u32 clk_id);
+};
+
struct scmi_clk_ops {
- int (*count_get)(const struct scmi_handle *handle);
+ int (*count_get)(const struct scmi_handle *hamdle);
const struct scmi_clock_info *(*info_get)
(const struct scmi_handle *handle, u32 clk_id);
@@ -613,8 +626,6 @@ struct scmi_notify_ops {
* dedicated protocol handler
* @put_ops: method to release a protocol
* @notify_ops: pointer to set of notifications related operations
- * @clk_priv: pointer to private data structure specific to clock
- * protocol(for internal use only)
* @sensor_priv: pointer to private data structure specific to sensors
* protocol(for internal use only)
* @reset_priv: pointer to private data structure specific to reset
@@ -644,7 +655,6 @@ struct scmi_handle {
const struct scmi_notify_ops *notify_ops;
/* for protocol internal use */
- void *clk_priv;
void *sensor_priv;
void *reset_priv;
void *voltage_priv;
--
2.17.1
Now that all the SCMI driver users have been migrated to the new interface
remove the legacy interface and all the transient code.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/sensors.c | 82 -----------------------------
include/linux/scmi_protocol.h | 19 -------
2 files changed, 101 deletions(-)
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 5d2da4f78108..478585f644fa 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -624,17 +624,6 @@ scmi_sensor_trip_point_config(const struct scmi_protocol_handle *ph,
return ret;
}
-static int
-__scmi_sensor_trip_point_config(const struct scmi_handle *handle,
- u32 sensor_id, u8 trip_id, u64 trip_value)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
-
- return scmi_sensor_trip_point_config(ph, sensor_id, trip_id,
- trip_value);
-}
-
static int scmi_sensor_config_get(const struct scmi_protocol_handle *ph,
u32 sensor_id, u32 *sensor_config)
{
@@ -660,15 +649,6 @@ static int scmi_sensor_config_get(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_sensor_config_get(const struct scmi_handle *handle,
- u32 sensor_id, u32 *sensor_config)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
-
- return scmi_sensor_config_get(ph, sensor_id, sensor_config);
-}
-
static int scmi_sensor_config_set(const struct scmi_protocol_handle *ph,
u32 sensor_id, u32 sensor_config)
{
@@ -697,15 +677,6 @@ static int scmi_sensor_config_set(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_sensor_config_set(const struct scmi_handle *handle,
- u32 sensor_id, u32 sensor_config)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
-
- return scmi_sensor_config_set(ph, sensor_id, sensor_config);
-}
-
/**
* scmi_sensor_reading_get - Read scalar sensor value
* @ph: Protocol handle
@@ -760,15 +731,6 @@ static int scmi_sensor_reading_get(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_sensor_reading_get(const struct scmi_handle *handle,
- u32 sensor_id, u64 *value)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
-
- return scmi_sensor_reading_get(ph, sensor_id, value);
-}
-
static inline void
scmi_parse_sensor_readings(struct scmi_sensor_reading *out,
const struct scmi_sensor_reading_resp *in)
@@ -847,18 +809,6 @@ scmi_sensor_reading_get_timestamped(const struct scmi_protocol_handle *ph,
return ret;
}
-static int
-__scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle,
- u32 sensor_id, u8 count,
- struct scmi_sensor_reading *readings)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
-
- return scmi_sensor_reading_get_timestamped(ph, sensor_id, count,
- readings);
-}
-
static const struct scmi_sensor_info *
scmi_sensor_info_get(const struct scmi_protocol_handle *ph, u32 sensor_id)
{
@@ -867,15 +817,6 @@ scmi_sensor_info_get(const struct scmi_protocol_handle *ph, u32 sensor_id)
return si->sensors + sensor_id;
}
-static const struct scmi_sensor_info *
-__scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
-
- return scmi_sensor_info_get(ph, sensor_id);
-}
-
static int scmi_sensor_count_get(const struct scmi_protocol_handle *ph)
{
struct sensors_info *si = ph->get_priv(ph);
@@ -883,24 +824,6 @@ static int scmi_sensor_count_get(const struct scmi_protocol_handle *ph)
return si->num_sensors;
}
-static int __scmi_sensor_count_get(const struct scmi_handle *handle)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
-
- return scmi_sensor_count_get(ph);
-}
-
-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,
- .reading_get = __scmi_sensor_reading_get,
- .reading_get_timestamped = __scmi_sensor_reading_get_timestamped,
- .config_get = __scmi_sensor_config_get,
- .config_set = __scmi_sensor_config_set,
-};
-
static const struct scmi_sensor_proto_ops sensor_proto_ops = {
.count_get = scmi_sensor_count_get,
.info_get = scmi_sensor_info_get,
@@ -1040,7 +963,6 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
u32 version;
int ret;
struct sensors_info *sinfo;
- struct scmi_handle *handle;
ph->xops->version_get(ph, &version);
@@ -1064,10 +986,6 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
if (ret)
return ret;
- /* Transient code for legacy ops interface */
- handle = scmi_map_scmi_handle(ph);
- handle->sensor_ops = &sensor_ops;
-
return ph->set_priv(ph, sinfo);
}
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 402a2765f111..9da9c866e02c 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -463,23 +463,6 @@ struct scmi_sensor_proto_ops {
u32 sensor_id, u32 sensor_config);
};
-struct scmi_sensor_ops {
- int (*count_get)(const struct scmi_handle *handle);
- const struct scmi_sensor_info *(*info_get)
- (const struct scmi_handle *handle, u32 sensor_id);
- int (*trip_point_config)(const struct scmi_handle *handle,
- u32 sensor_id, u8 trip_id, u64 trip_value);
- int (*reading_get)(const struct scmi_handle *handle, u32 sensor_id,
- u64 *value);
- int (*reading_get_timestamped)(const struct scmi_handle *handle,
- u32 sensor_id, u8 count,
- struct scmi_sensor_reading *readings);
- int (*config_get)(const struct scmi_handle *handle,
- u32 sensor_id, u32 *sensor_config);
- int (*config_set)(const struct scmi_handle *handle,
- u32 sensor_id, u32 sensor_config);
-};
-
/**
* struct scmi_reset_proto_ops - represents the various operations provided
* by SCMI Reset Protocol
@@ -619,7 +602,6 @@ struct scmi_notify_ops {
*
* @dev: pointer to the SCMI device
* @version: pointer to the structure containing SCMI version information
- * @sensor_ops: pointer to set of sensor protocol operations
* @voltage_ops: pointer to set of voltage protocol operations
* @devm_get_ops: devres managed method to acquire a protocol and get specific
* operations and a dedicated protocol handler
@@ -636,7 +618,6 @@ struct scmi_notify_ops {
struct scmi_handle {
struct device *dev;
struct scmi_revision_info *version;
- const struct scmi_sensor_ops *sensor_ops;
const struct scmi_voltage_ops *voltage_ops;
const void __must_check *
--
2.17.1
Convert internals of protocol implementation to use protocol handles and
expose a new protocol operations interface for SCMI driver using the new
get/put common operations, while keeping the old handle->reset_ops still
around to ease transition.
Remove handle->reset_priv now unused.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/reset.c | 172 +++++++++++++++++++++---------
include/linux/scmi_protocol.h | 14 ++-
2 files changed, 129 insertions(+), 57 deletions(-)
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index 7047e5baecc2..9c808f5add7e 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -64,46 +64,45 @@ struct scmi_reset_info {
struct reset_dom_info *dom_info;
};
-static int scmi_reset_attributes_get(const struct scmi_handle *handle,
+static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_reset_info *pi)
{
int ret;
struct scmi_xfer *t;
u32 attr;
- ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
- SCMI_PROTOCOL_RESET, 0, sizeof(attr), &t);
+ ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
+ 0, sizeof(attr), &t);
if (ret)
return ret;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
attr = get_unaligned_le32(t->rx.buf);
pi->num_domains = attr & NUM_RESET_DOMAIN_MASK;
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
static int
-scmi_reset_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
- struct reset_dom_info *dom_info)
+scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
+ u32 domain, struct reset_dom_info *dom_info)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_reset_domain_attributes *attr;
- ret = scmi_xfer_get_init(handle, RESET_DOMAIN_ATTRIBUTES,
- SCMI_PROTOCOL_RESET, sizeof(domain),
- sizeof(*attr), &t);
+ ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES,
+ sizeof(domain), sizeof(*attr), &t);
if (ret)
return ret;
put_unaligned_le32(domain, t->tx.buf);
attr = t->rx.buf;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
u32 attributes = le32_to_cpu(attr->attributes);
@@ -115,47 +114,75 @@ scmi_reset_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_reset_num_domains_get(const struct scmi_handle *handle)
+static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph)
{
- struct scmi_reset_info *pi = handle->reset_priv;
+ struct scmi_reset_info *pi = ph->get_priv(ph);
return pi->num_domains;
}
-static char *scmi_reset_name_get(const struct scmi_handle *handle, u32 domain)
+static int __scmi_reset_num_domains_get(const struct scmi_handle *handle)
{
- struct scmi_reset_info *pi = handle->reset_priv;
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
+
+ return scmi_reset_num_domains_get(ph);
+}
+
+static char *scmi_reset_name_get(const struct scmi_protocol_handle *ph,
+ u32 domain)
+{
+ struct scmi_reset_info *pi = ph->get_priv(ph);
+
struct reset_dom_info *dom = pi->dom_info + domain;
return dom->name;
}
-static int scmi_reset_latency_get(const struct scmi_handle *handle, u32 domain)
+static char *__scmi_reset_name_get(const struct scmi_handle *handle,
+ u32 domain)
{
- struct scmi_reset_info *pi = handle->reset_priv;
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
+
+ return scmi_reset_name_get(ph, domain);
+}
+
+static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph,
+ u32 domain)
+{
+ struct scmi_reset_info *pi = ph->get_priv(ph);
struct reset_dom_info *dom = pi->dom_info + domain;
return dom->latency_us;
}
-static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain,
+static int __scmi_reset_latency_get(const struct scmi_handle *handle,
+ u32 domain)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
+
+ return scmi_reset_latency_get(ph, domain);
+}
+
+static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain,
u32 flags, u32 state)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_reset_domain_reset *dom;
- struct scmi_reset_info *pi = handle->reset_priv;
+ struct scmi_reset_info *pi = ph->get_priv(ph);
struct reset_dom_info *rdom = pi->dom_info + domain;
if (rdom->async_reset)
flags |= ASYNCHRONOUS_RESET;
- ret = scmi_xfer_get_init(handle, RESET, SCMI_PROTOCOL_RESET,
- sizeof(*dom), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t);
if (ret)
return ret;
@@ -165,34 +192,71 @@ static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain,
dom->reset_state = cpu_to_le32(state);
if (rdom->async_reset)
- ret = scmi_do_xfer_with_response(handle, t);
+ ret = ph->xops->do_xfer_with_response(ph, t);
else
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_reset_domain_reset(const struct scmi_handle *handle, u32 domain)
+static int scmi_reset_domain_reset(const struct scmi_protocol_handle *ph,
+ u32 domain)
{
- return scmi_domain_reset(handle, domain, AUTONOMOUS_RESET,
+ return scmi_domain_reset(ph, domain, AUTONOMOUS_RESET,
ARCH_COLD_RESET);
}
+static int __scmi_reset_domain_reset(const struct scmi_handle *handle,
+ u32 domain)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
+
+ return scmi_reset_domain_reset(ph, domain);
+}
+
static int
-scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain)
+scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain)
{
- return scmi_domain_reset(handle, domain, EXPLICIT_RESET_ASSERT,
+ return scmi_domain_reset(ph, domain, EXPLICIT_RESET_ASSERT,
ARCH_COLD_RESET);
}
static int
-scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
+__scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
+
+ return scmi_reset_domain_assert(ph, domain);
+}
+
+static int
+scmi_reset_domain_deassert(const struct scmi_protocol_handle *ph, u32 domain)
{
- return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET);
+ return scmi_domain_reset(ph, domain, 0, ARCH_COLD_RESET);
+}
+
+static int
+__scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_RESET);
+
+ return scmi_reset_domain_deassert(ph, domain);
}
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,
+ .reset = __scmi_reset_domain_reset,
+ .assert = __scmi_reset_domain_assert,
+ .deassert = __scmi_reset_domain_deassert,
+};
+
+static const struct scmi_reset_proto_ops reset_proto_ops = {
.num_domains_get = scmi_reset_num_domains_get,
.name_get = scmi_reset_name_get,
.latency_get = scmi_reset_latency_get,
@@ -201,16 +265,15 @@ static const struct scmi_reset_ops reset_ops = {
.deassert = scmi_reset_domain_deassert,
};
-static int scmi_reset_notify(const struct scmi_handle *handle, u32 domain_id,
- bool enable)
+static int scmi_reset_notify(const struct scmi_protocol_handle *ph,
+ u32 domain_id, bool enable)
{
int ret;
u32 evt_cntl = enable ? RESET_TP_NOTIFY_ALL : 0;
struct scmi_xfer *t;
struct scmi_msg_reset_notify *cfg;
- ret = scmi_xfer_get_init(handle, RESET_NOTIFY,
- SCMI_PROTOCOL_RESET, sizeof(*cfg), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, RESET_NOTIFY, sizeof(*cfg), 0, &t);
if (ret)
return ret;
@@ -218,18 +281,18 @@ static int scmi_reset_notify(const struct scmi_handle *handle, u32 domain_id,
cfg->id = cpu_to_le32(domain_id);
cfg->event_control = cpu_to_le32(evt_cntl);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_reset_set_notify_enabled(const void *handle,
+static int scmi_reset_set_notify_enabled(const void *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
- ret = scmi_reset_notify(handle, src_id, enable);
+ ret = scmi_reset_notify(ph, src_id, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
@@ -237,7 +300,7 @@ static int scmi_reset_set_notify_enabled(const void *handle,
return ret;
}
-static void *scmi_reset_fill_custom_report(const void *handle,
+static void *scmi_reset_fill_custom_report(const void *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -257,10 +320,10 @@ static void *scmi_reset_fill_custom_report(const void *handle,
return r;
}
-static int scmi_reset_get_num_sources(const void *handle)
+static int scmi_reset_get_num_sources(const void *ph)
{
struct scmi_reset_info *pinfo =
- ((const struct scmi_handle *)(handle))->reset_priv;
+ ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
if (!pinfo)
return -EINVAL;
@@ -289,24 +352,25 @@ static const struct scmi_protocol_events reset_protocol_events = {
.num_events = ARRAY_SIZE(reset_events),
};
-static int scmi_reset_protocol_init(struct scmi_handle *handle)
+static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
{
int domain;
u32 version;
struct scmi_reset_info *pinfo;
+ struct scmi_handle *handle;
- scmi_version_get(handle, SCMI_PROTOCOL_RESET, &version);
+ ph->xops->version_get(ph, &version);
- dev_dbg(handle->dev, "Reset Version %d.%d\n",
+ dev_dbg(ph->dev, "Reset Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
- pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
+ pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
- scmi_reset_attributes_get(handle, pinfo);
+ scmi_reset_attributes_get(ph, pinfo);
- pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains,
+ pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains,
sizeof(*pinfo->dom_info), GFP_KERNEL);
if (!pinfo->dom_info)
return -ENOMEM;
@@ -314,20 +378,22 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle)
for (domain = 0; domain < pinfo->num_domains; domain++) {
struct reset_dom_info *dom = pinfo->dom_info + domain;
- scmi_reset_domain_attributes_get(handle, domain, dom);
+ scmi_reset_domain_attributes_get(ph, domain, dom);
}
pinfo->version = version;
+
+ /* Transient code for legacy ops interface */
+ handle = scmi_map_scmi_handle(ph);
handle->reset_ops = &reset_ops;
- handle->reset_priv = pinfo;
- return 0;
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_reset = {
.id = SCMI_PROTOCOL_RESET,
- .init = &scmi_reset_protocol_init,
- .ops = &reset_ops,
+ .init_instance = &scmi_reset_protocol_init,
+ .ops = &reset_proto_ops,
.events = &reset_protocol_events,
};
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 6605b75f4577..58a33d0b6f90 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -464,7 +464,7 @@ struct scmi_sensor_ops {
};
/**
- * struct scmi_reset_ops - represents the various operations provided
+ * struct scmi_reset_proto_ops - represents the various operations provided
* by SCMI Reset Protocol
*
* @num_domains_get: get the count of reset domains provided by SCMI
@@ -474,6 +474,15 @@ struct scmi_sensor_ops {
* @assert: explicitly assert reset signal of the specified reset domain
* @deassert: explicitly deassert reset signal of the specified reset domain
*/
+struct scmi_reset_proto_ops {
+ int (*num_domains_get)(const struct scmi_protocol_handle *ph);
+ char *(*name_get)(const struct scmi_protocol_handle *ph, u32 domain);
+ int (*latency_get)(const struct scmi_protocol_handle *ph, u32 domain);
+ int (*reset)(const struct scmi_protocol_handle *ph, u32 domain);
+ int (*assert)(const struct scmi_protocol_handle *ph, u32 domain);
+ int (*deassert)(const struct scmi_protocol_handle *ph, u32 domain);
+};
+
struct scmi_reset_ops {
int (*num_domains_get)(const struct scmi_handle *handle);
char *(*name_get)(const struct scmi_handle *handle, u32 domain);
@@ -614,8 +623,6 @@ struct scmi_notify_ops {
* @notify_ops: pointer to set of notifications related operations
* @sensor_priv: pointer to private data structure specific to sensors
* protocol(for internal use only)
- * @reset_priv: pointer to private data structure specific to reset
- * protocol(for internal use only)
* @voltage_priv: pointer to private data structure specific to voltage
* protocol(for internal use only)
* @notify_priv: pointer to private data structure specific to notifications
@@ -641,7 +648,6 @@ struct scmi_handle {
const struct scmi_notify_ops *notify_ops;
/* for protocol internal use */
void *sensor_priv;
- void *reset_priv;
void *voltage_priv;
void *notify_priv;
void *system_priv;
--
2.17.1
Now that all the protocol private variable data have been moved out of
struct scmi_handle, mark all of its references as const.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/common.h | 4 ++--
drivers/firmware/arm_scmi/driver.c | 12 ++++++------
include/linux/scmi_protocol.h | 4 ++--
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index c7b48f1e5fe0..45387a32d79e 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -274,8 +274,8 @@ void __exit scmi_##name##_unregister(void) \
const struct scmi_protocol *scmi_get_protocol(int protocol_id);
-int scmi_acquire_protocol(struct scmi_handle *handle, u8 protocol_id);
-void scmi_release_protocol(struct scmi_handle *handle, u8 protocol_id);
+int scmi_acquire_protocol(const struct scmi_handle *handle, u8 protocol_id);
+void scmi_release_protocol(const struct scmi_handle *handle, u8 protocol_id);
/* SCMI Transport */
/**
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index b76c06b8bbc3..68a40d83325c 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -729,7 +729,7 @@ scmi_get_revision_area(const struct scmi_protocol_handle *ph)
* Return: A reference to an initialized protocol instance or error on failure.
*/
static struct scmi_protocol_instance * __must_check
-scmi_get_protocol_instance(struct scmi_handle *handle, u8 protocol_id)
+scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id)
{
int ret = -ENOMEM;
void *gid;
@@ -808,7 +808,7 @@ scmi_get_protocol_instance(struct scmi_handle *handle, u8 protocol_id)
*
* Return: 0 if protocol was acquired successfully.
*/
-int scmi_acquire_protocol(struct scmi_handle *handle, u8 protocol_id)
+int scmi_acquire_protocol(const struct scmi_handle *handle, u8 protocol_id)
{
return PTR_ERR_OR_ZERO(scmi_get_protocol_instance(handle, protocol_id));
}
@@ -821,7 +821,7 @@ int scmi_acquire_protocol(struct scmi_handle *handle, u8 protocol_id)
* Remove one user for the specified protocol and triggers de-initialization
* and resources de-allocation once the last user has gone.
*/
-void scmi_release_protocol(struct scmi_handle *handle, u8 protocol_id)
+void scmi_release_protocol(const struct scmi_handle *handle, u8 protocol_id)
{
struct scmi_info *info = handle_to_scmi_info(handle);
struct scmi_protocol_instance *pi;
@@ -866,7 +866,7 @@ void scmi_release_protocol(struct scmi_handle *handle, u8 protocol_id)
* Must be checked for errors by caller.
*/
static const void __must_check *
-scmi_get_protocol_operations(struct scmi_handle *handle, u8 protocol_id,
+scmi_get_protocol_operations(const struct scmi_handle *handle, u8 protocol_id,
struct scmi_protocol_handle **ph)
{
struct scmi_protocol_instance *pi;
@@ -908,7 +908,7 @@ scmi_is_protocol_implemented(const struct scmi_handle *handle, u8 prot_id)
}
struct scmi_protocol_devres {
- struct scmi_handle *handle;
+ const struct scmi_handle *handle;
u8 protocol_id;
};
@@ -943,7 +943,7 @@ scmi_devm_get_protocol_ops(struct scmi_device *sdev, u8 protocol_id,
{
struct scmi_protocol_instance *pi;
struct scmi_protocol_devres *dres;
- struct scmi_handle *handle = sdev->handle;
+ const struct scmi_handle *handle = sdev->handle;
if (!ph)
return ERR_PTR(-EINVAL);
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index c16455cff6a9..6c05e8acafac 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -622,9 +622,9 @@ struct scmi_handle {
void (*devm_put_ops)(struct scmi_device *sdev, u8 proto);
const void __must_check *
- (*get_ops)(struct scmi_handle *handle, u8 proto,
+ (*get_ops)(const struct scmi_handle *handle, u8 proto,
struct scmi_protocol_handle **ph);
- void (*put_ops)(struct scmi_handle *handle, u8 proto);
+ void (*put_ops)(const struct scmi_handle *handle, u8 proto);
const struct scmi_notify_ops *notify_ops;
void *notify_priv;
--
2.17.1
Extend SCMI protocols accounting mechanism to address possible module
usage and add the support to possibly define new protocols as loadable
modules.
Keep Standard protocols built into the SCMI core.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/base.c | 2 ++
drivers/firmware/arm_scmi/bus.c | 11 ++++++++++-
drivers/firmware/arm_scmi/clock.c | 2 ++
drivers/firmware/arm_scmi/common.h | 4 ++++
drivers/firmware/arm_scmi/driver.c | 5 ++++-
drivers/firmware/arm_scmi/perf.c | 2 ++
drivers/firmware/arm_scmi/power.c | 2 ++
drivers/firmware/arm_scmi/reset.c | 2 ++
drivers/firmware/arm_scmi/sensors.c | 2 ++
drivers/firmware/arm_scmi/system.c | 2 ++
include/linux/scmi_protocol.h | 12 ++++++++++++
11 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index f2d10c5a55ae..b70d741f8465 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -7,6 +7,7 @@
#define pr_fmt(fmt) "SCMI Notifications BASE - " fmt
+#include <linux/module.h>
#include <linux/scmi_protocol.h>
#include "common.h"
@@ -373,6 +374,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
static const struct scmi_protocol scmi_base = {
.id = SCMI_PROTOCOL_BASE,
+ .owner = NULL,
.init_instance = &scmi_base_protocol_init,
.ops = NULL,
.events = &base_protocol_events,
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 9fbf618b9c4b..88e5057f4e85 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -56,7 +56,7 @@ const struct scmi_protocol *scmi_get_protocol(int protocol_id)
const struct scmi_protocol *proto;
proto = idr_find(&scmi_available_protocols, protocol_id);
- if (!proto) {
+ if (!proto || !try_module_get(proto->owner)) {
pr_warn("SCMI Protocol 0x%x not found!\n", protocol_id);
return NULL;
}
@@ -66,6 +66,15 @@ const struct scmi_protocol *scmi_get_protocol(int protocol_id)
return proto;
}
+void scmi_put_protocol(int protocol_id)
+{
+ const struct scmi_protocol *proto;
+
+ proto = idr_find(&scmi_available_protocols, protocol_id);
+ if (proto)
+ module_put(proto->owner);
+}
+
static int scmi_dev_probe(struct device *dev)
{
struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index a0a6593f464f..bd364d3a56d2 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -5,6 +5,7 @@
* Copyright (C) 2018-2020 ARM Ltd.
*/
+#include <linux/module.h>
#include <linux/sort.h>
#include "common.h"
@@ -367,6 +368,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
static const struct scmi_protocol scmi_clock = {
.id = SCMI_PROTOCOL_CLOCK,
+ .owner = THIS_MODULE,
.init_instance = &scmi_clock_protocol_init,
.ops = &clk_proto_ops,
};
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 5fb64182610a..1e2046c61d43 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/scmi_protocol.h>
#include <linux/types.h>
@@ -214,6 +215,7 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
/**
* struct scmi_protocol - Protocol descriptor
* @id: Protocol ID.
+ * @owner: Module reference if any.
* @init_instance: Mandatory protocol initialization function.
* @deinit_instance: Optional protocol de-initialization function.
* @ops: Optional reference to the operations provided by the protocol and
@@ -222,6 +224,7 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
*/
struct scmi_protocol {
const u8 id;
+ struct module *owner;
const scmi_prot_init_ph_fn_t init_instance;
const scmi_prot_init_ph_fn_t deinit_instance;
const void *ops;
@@ -255,6 +258,7 @@ void __exit scmi_##name##_unregister(void) \
}
const struct scmi_protocol *scmi_get_protocol(int protocol_id);
+void scmi_put_protocol(int protocol_id);
int scmi_acquire_protocol(const struct scmi_handle *handle, u8 protocol_id);
void scmi_release_protocol(const struct scmi_handle *handle, u8 protocol_id);
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index a0a6a3d1d239..4b68952e49db 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -677,7 +677,7 @@ scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id)
/* Fail if protocol not registered on bus */
proto = scmi_get_protocol(protocol_id);
if (!proto) {
- ret = -ENODEV;
+ ret = -EPROBE_DEFER;
goto out;
}
@@ -722,6 +722,7 @@ scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id)
return pi;
clean:
+ scmi_put_protocol(protocol_id);
devres_release_group(handle->dev, gid);
out:
mutex_unlock(&info->protocols_mtx);
@@ -772,6 +773,8 @@ void scmi_release_protocol(const struct scmi_handle *handle, u8 protocol_id)
idr_remove(&info->protocols, protocol_id);
+ scmi_put_protocol(protocol_id);
+
devres_release_group(handle->dev, gid);
dev_dbg(handle->dev, "De-Initialized protocol: 0x%X\n",
protocol_id);
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index c87a390463d9..f9146429789e 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -11,6 +11,7 @@
#include <linux/of.h>
#include <linux/io.h>
#include <linux/io-64-nonatomic-hi-lo.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/scmi_protocol.h>
@@ -909,6 +910,7 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
static const struct scmi_protocol scmi_perf = {
.id = SCMI_PROTOCOL_PERF,
+ .owner = THIS_MODULE,
.init_instance = &scmi_perf_protocol_init,
.ops = &perf_proto_ops,
.events = &perf_protocol_events,
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index 3e453d9bcbc8..70d366ed37e6 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -7,6 +7,7 @@
#define pr_fmt(fmt) "SCMI Notifications POWER - " fmt
+#include <linux/module.h>
#include <linux/scmi_protocol.h>
#include "common.h"
@@ -312,6 +313,7 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
static const struct scmi_protocol scmi_power = {
.id = SCMI_PROTOCOL_POWER,
+ .owner = THIS_MODULE,
.init_instance = &scmi_power_protocol_init,
.ops = &power_proto_ops,
.events = &power_protocol_events,
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index bd28d4e9664d..b26686dd8526 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -7,6 +7,7 @@
#define pr_fmt(fmt) "SCMI Notifications RESET - " fmt
+#include <linux/module.h>
#include <linux/scmi_protocol.h>
#include "common.h"
@@ -324,6 +325,7 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
static const struct scmi_protocol scmi_reset = {
.id = SCMI_PROTOCOL_RESET,
+ .owner = THIS_MODULE,
.init_instance = &scmi_reset_protocol_init,
.ops = &reset_proto_ops,
.events = &reset_protocol_events,
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index edc08d9f8daa..903fcdb57d4a 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -8,6 +8,7 @@
#define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt
#include <linux/bitfield.h>
+#include <linux/module.h>
#include <linux/scmi_protocol.h>
#include "common.h"
@@ -990,6 +991,7 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
static const struct scmi_protocol scmi_sensors = {
.id = SCMI_PROTOCOL_SENSOR,
+ .owner = THIS_MODULE,
.init_instance = &scmi_sensors_protocol_init,
.ops = &sensor_proto_ops,
.events = &sensor_protocol_events,
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
index 97ad20a51d72..a68bad27688f 100644
--- a/drivers/firmware/arm_scmi/system.c
+++ b/drivers/firmware/arm_scmi/system.c
@@ -7,6 +7,7 @@
#define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt
+#include <linux/module.h>
#include <linux/scmi_protocol.h>
#include "common.h"
@@ -130,6 +131,7 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
static const struct scmi_protocol scmi_system = {
.id = SCMI_PROTOCOL_SYSTEM,
+ .owner = THIS_MODULE,
.init_instance = &scmi_system_protocol_init,
.ops = NULL,
.events = &system_protocol_events,
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index c5d3f9b7de7c..13e81547c3d1 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -709,6 +709,18 @@ static inline void scmi_driver_unregister(struct scmi_driver *driver) {}
#define module_scmi_driver(__scmi_driver) \
module_driver(__scmi_driver, scmi_register, scmi_unregister)
+/**
+ * module_scmi_protocol() - Helper macro for registering a scmi protocol
+ * @__scmi_protocol: scmi_protocol structure
+ *
+ * Helper macro for scmi drivers to set up proper module init / exit
+ * functions. Replaces module_init() and module_exit() and keeps people from
+ * printing pointless things to the kernel log when their driver is loaded.
+ */
+#define module_scmi_protocol(__scmi_protocol) \
+ module_driver(__scmi_protocol, \
+ scmi_protocol_register, scmi_protocol_unregister)
+
struct scmi_protocol;
int scmi_protocol_register(const struct scmi_protocol *proto);
void scmi_protocol_unregister(const struct scmi_protocol *proto);
--
2.17.1
Convert internals of protocol implementation to use protocol handles and
expose a new protocol operations interface for SCMI driver using the new
get/put common operations.
Remove handle->system_priv now unused.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/system.c | 30 ++++++++++++++----------------
include/linux/scmi_protocol.h | 1 -
2 files changed, 14 insertions(+), 17 deletions(-)
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
index 6690610c2c26..a23c1f505b56 100644
--- a/drivers/firmware/arm_scmi/system.c
+++ b/drivers/firmware/arm_scmi/system.c
@@ -32,40 +32,40 @@ struct scmi_system_info {
u32 version;
};
-static int scmi_system_request_notify(const struct scmi_handle *handle,
+static int scmi_system_request_notify(const struct scmi_protocol_handle *ph,
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);
+ ret = ph->xops->xfer_get_init(ph, SYSTEM_POWER_STATE_NOTIFY,
+ 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);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_system_set_notify_enabled(const void *handle,
+static int scmi_system_set_notify_enabled(const void *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
- ret = scmi_system_request_notify(handle, enable);
+ ret = scmi_system_request_notify(ph, 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 void *handle,
+static void *scmi_system_fill_custom_report(const void *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -109,29 +109,27 @@ static const struct scmi_protocol_events system_protocol_events = {
.num_sources = SCMI_SYSTEM_NUM_SOURCES,
};
-static int scmi_system_protocol_init(struct scmi_handle *handle)
+static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
{
u32 version;
struct scmi_system_info *pinfo;
- scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version);
+ ph->xops->version_get(ph, &version);
- dev_dbg(handle->dev, "System Power Version %d.%d\n",
+ dev_dbg(ph->dev, "System Power Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
- pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
+ pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
pinfo->version = version;
- handle->system_priv = pinfo;
-
- return 0;
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_system = {
.id = SCMI_PROTOCOL_SYSTEM,
- .init = &scmi_system_protocol_init,
+ .init_instance = &scmi_system_protocol_init,
.ops = NULL,
.events = &system_protocol_events,
};
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 9da9c866e02c..24972b798f79 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -634,7 +634,6 @@ struct scmi_handle {
/* for protocol internal use */
void *voltage_priv;
void *notify_priv;
- void *system_priv;
};
enum scmi_std_protocol {
--
2.17.1
Having added the support for SCMI protocols as modules in order to let
vendors extend the SCMI core with their own additions it seems odd to
then force SCMI drivers built on top to use a static device table to
declare their devices since this way any new SCMI drivers addition
would need the core SCMI device table to be updated too.
Remove the static core device table and let SCMI drivers to simply declare
which device/protocol pair they need at initialization time: the core will
then take care to generate such devices dynamically during platform
initialization or at module loading time, as long as the requested
underlying protocol is defined in the DT.
Signed-off-by: Cristian Marussi <[email protected]>
---
v3 --> v4
- add a few comments
---
drivers/firmware/arm_scmi/bus.c | 30 +++
drivers/firmware/arm_scmi/common.h | 5 +
drivers/firmware/arm_scmi/driver.c | 296 +++++++++++++++++++++++++----
3 files changed, 297 insertions(+), 34 deletions(-)
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 88e5057f4e85..88149a46e6d9 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -51,6 +51,31 @@ static int scmi_dev_match(struct device *dev, struct device_driver *drv)
return 0;
}
+static int scmi_match_by_id_table(struct device *dev, void *data)
+{
+ struct scmi_device *sdev = to_scmi_dev(dev);
+ struct scmi_device_id *id_table = data;
+
+ return sdev->protocol_id == id_table->protocol_id &&
+ !strcmp(sdev->name, id_table->name);
+}
+
+struct scmi_device *scmi_find_child_dev(struct device *parent,
+ int prot_id, const char *name)
+{
+ struct scmi_device_id id_table;
+ struct device *dev;
+
+ id_table.protocol_id = prot_id;
+ id_table.name = name;
+
+ dev = device_find_child(parent, &id_table, scmi_match_by_id_table);
+ if (!dev)
+ return NULL;
+
+ return to_scmi_dev(dev);
+}
+
const struct scmi_protocol *scmi_get_protocol(int protocol_id)
{
const struct scmi_protocol *proto;
@@ -114,6 +139,10 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
{
int retval;
+ retval = scmi_request_protocol_device(driver->id_table);
+ if (retval)
+ return retval;
+
driver->driver.bus = &scmi_bus_type;
driver->driver.name = driver->name;
driver->driver.owner = owner;
@@ -130,6 +159,7 @@ EXPORT_SYMBOL_GPL(scmi_driver_register);
void scmi_driver_unregister(struct scmi_driver *driver)
{
driver_unregister(&driver->driver);
+ scmi_unrequest_protocol_device(driver->id_table);
}
EXPORT_SYMBOL_GPL(scmi_driver_unregister);
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 1e2046c61d43..9a0519db4865 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -307,6 +307,11 @@ struct scmi_transport_ops {
bool (*poll_done)(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer);
};
+int scmi_request_protocol_device(const struct scmi_device_id *id_table);
+void scmi_unrequest_protocol_device(const struct scmi_device_id *id_table);
+struct scmi_device *scmi_find_child_dev(struct device *parent,
+ int prot_id, const char *name);
+
/**
* struct scmi_desc - Description of SoC integration
*
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 4b68952e49db..94d30fa652d9 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -56,6 +56,14 @@ static DEFINE_MUTEX(scmi_list_mutex);
/* Track the unique id for the transfers for debug & profiling purpose */
static atomic_t transfer_last_id;
+static DEFINE_IDR(scmi_requested_devices);
+static DEFINE_MUTEX(scmi_requested_devices_mutex);
+
+struct scmi_requested_dev {
+ const struct scmi_device_id *id_table;
+ struct scmi_requested_dev *next;
+};
+
/**
* struct scmi_xfers_info - Structure to manage transfer information
*
@@ -113,6 +121,8 @@ struct scmi_protocol_instance {
* @protocols_mtx: A mutex to protect protocols instances initialization.
* @protocols_imp: List of protocols implemented, currently maximum of
* MAX_PROTOCOLS_IMP elements allocated by the base protocol
+ * @active_protocols: IDR storing device_nodes for protocols actually defined
+ * in the DT and confirmed as implemented by fw.
* @notify_priv: Pointer to private data structure specific to notifications.
* @node: List head
* @users: Number of users of this instance
@@ -130,6 +140,7 @@ struct scmi_info {
/* Ensure mutual exclusive access to protocols instance array */
struct mutex protocols_mtx;
u8 *protocols_imp;
+ struct idr active_protocols;
void *notify_priv;
struct list_head node;
int users;
@@ -929,6 +940,13 @@ static void scmi_devm_put_protocol_ops(struct scmi_device *sdev, u8 protocol_id)
WARN_ON(ret);
}
+static inline
+struct scmi_handle *scmi_handle_get_from_info(struct scmi_info *info)
+{
+ info->users++;
+ return &info->handle;
+}
+
/**
* scmi_handle_get() - Get the SCMI handle for a device
*
@@ -950,8 +968,7 @@ struct scmi_handle *scmi_handle_get(struct device *dev)
list_for_each(p, &scmi_list) {
info = list_entry(p, struct scmi_info, node);
if (dev->parent == info->dev) {
- handle = &info->handle;
- info->users++;
+ handle = scmi_handle_get_from_info(info);
break;
}
}
@@ -1094,62 +1111,254 @@ scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id)
return ret;
}
-static inline void
-scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
- int prot_id, const char *name)
+/**
+ * scmi_get_protocol_device - Helper to get/create an SCMI device.
+ *
+ * @np: A device node representing a valid active protocols for the referred
+ * SCMI instance.
+ * @info: The referred SCMI instance for which we are getting/creating this
+ * device.
+ * @prot_id: The protocol ID.
+ * @name: The device name.
+ *
+ * Referring to the specific SCMI instance identified by @info, this helper
+ * takes care to return a properly initialized device matching the requested
+ * @proto_id and @name: if device was still not existent it is created as a
+ * child of the specified SCMI instance @info and its transport properly
+ * initialized as usual.
+ */
+static inline struct scmi_device *
+scmi_get_protocol_device(struct device_node *np, struct scmi_info *info,
+ int prot_id, const char *name)
{
struct scmi_device *sdev;
+ /* Already created for this parent SCMI instance ? */
+ sdev = scmi_find_child_dev(info->dev, prot_id, name);
+ if (sdev)
+ return sdev;
+
+ pr_debug("Creating SCMI device (%s) for protocol %x\n", name, prot_id);
+
sdev = scmi_device_create(np, info->dev, prot_id, name);
if (!sdev) {
dev_err(info->dev, "failed to create %d protocol device\n",
prot_id);
- return;
+ return NULL;
}
if (scmi_txrx_setup(info, &sdev->dev, prot_id)) {
dev_err(&sdev->dev, "failed to setup transport\n");
scmi_device_destroy(sdev);
- return;
+ return NULL;
}
+ return sdev;
+}
+
+static inline void
+scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
+ int prot_id, const char *name)
+{
+ struct scmi_device *sdev;
+
+ sdev = scmi_get_protocol_device(np, info, prot_id, name);
+ if (!sdev)
+ return;
+
/* setup handle now as the transport is ready */
scmi_set_handle(sdev);
}
-#define MAX_SCMI_DEV_PER_PROTOCOL 2
-struct scmi_prot_devnames {
- int protocol_id;
- char *names[MAX_SCMI_DEV_PER_PROTOCOL];
-};
+/**
+ * scmi_create_protocol_devices - Create devices for all pending requests for
+ * this SCMI instance.
+ *
+ * @np: The device node describing the protocol
+ * @info: The SCMI instance descriptor
+ * @prot_id: The protocol ID
+ *
+ * All devices previously requested for this instance (if any) are found and
+ * created by scanning the proper @&scmi_requested_devices entry.
+ */
+static void scmi_create_protocol_devices(struct device_node *np,
+ struct scmi_info *info, int prot_id)
+{
+ struct scmi_requested_dev *rdev;
-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" },},
- { SCMI_PROTOCOL_RESET, { "reset" },},
- { SCMI_PROTOCOL_VOLTAGE, { "regulator" },},
-};
+ rdev = idr_find(&scmi_requested_devices, prot_id);
+ if (!rdev)
+ return;
-static inline void
-scmi_create_protocol_devices(struct device_node *np, struct scmi_info *info,
- int prot_id)
+ for (; rdev; rdev = rdev->next)
+ scmi_create_protocol_device(np, info, prot_id,
+ rdev->id_table->name);
+}
+
+/**
+ * scmi_request_protocol_device - Helper to request a device
+ *
+ * @id_table: A protocol/name pair descriptor for the device to be created.
+ *
+ * This helper let an SCMI driver request specific devices identified by the
+ * @id_table to be created for each active SCMI instance.
+ *
+ * The requested device name MUST NOT be already existent for any protocol;
+ * at first the freshly requested @id_table is annotated in the IDR table
+ * @scmi_requested_devices, then a matching device is created for each already
+ * active SCMI instance. (if any)
+ *
+ * This way the requested device is created straight-away for all the already
+ * initialized(probed) SCMI instances (handles) but it remains instead pending
+ * for creation if the requesting SCMI driver is loaded before some instance
+ * and related transports was available: when such late SCMI instance is probed
+ * it will take care to scan the list of pending requested devices and create
+ * those on its own (see @scmi_create_protocol_devices and its enclosing loop)
+ *
+ * Return: 0 on Success
+ */
+int scmi_request_protocol_device(const struct scmi_device_id *id_table)
{
- int loop, cnt;
+ int ret = 0;
+ unsigned int id = 0;
+ struct scmi_requested_dev *rdev, *proto_rdev = NULL;
+ struct scmi_info *info;
- for (loop = 0; loop < ARRAY_SIZE(devnames); loop++) {
- if (devnames[loop].protocol_id != prot_id)
- continue;
+ pr_debug("Requesting SCMI device (%s) for protocol %x\n",
+ id_table->name, id_table->protocol_id);
- for (cnt = 0; cnt < ARRAY_SIZE(devnames[loop].names); cnt++) {
- const char *name = devnames[loop].names[cnt];
+ /*
+ * Search for the matching protocol rdev list and then search
+ * of any existent equally named device...fails if any duplicate found.
+ */
+ mutex_lock(&scmi_requested_devices_mutex);
+ idr_for_each_entry(&scmi_requested_devices, rdev, id) {
+ if (rdev->id_table->protocol_id == id_table->protocol_id)
+ proto_rdev = rdev;
+ for (; rdev; rdev = rdev->next) {
+ if (!strcmp(rdev->id_table->name, id_table->name)) {
+ pr_err("Ignoring duplicate request [%d] %s\n",
+ rdev->id_table->protocol_id,
+ rdev->id_table->name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ }
+
+ /*
+ * No duplicate found for requested id_table, so let's create a new
+ * requested device entry for this new valid request.
+ */
+ rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
+ if (!rdev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ rdev->id_table = id_table;
+
+ /*
+ * Append the new requested device table descriptor to the head of the
+ * related protocol chain, eventually creating such chain if not already
+ * there.
+ */
+ if (!proto_rdev) {
+ ret = idr_alloc(&scmi_requested_devices, (void *)rdev,
+ rdev->id_table->protocol_id,
+ rdev->id_table->protocol_id + 1, GFP_KERNEL);
+ if (ret != rdev->id_table->protocol_id) {
+ pr_err("Failed to save SCMI device - ret:%d\n", ret);
+ kfree(rdev);
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = 0;
+ } else {
+ proto_rdev->next = rdev;
+ }
+
+ /*
+ * Now effectively create and initialize the requested device for every
+ * already initialized SCMI instance which has registered the requested
+ * protocol as a valid active one: i.e. defined in DT and supported by
+ * current platform FW.
+ */
+ mutex_lock(&scmi_list_mutex);
+ list_for_each_entry(info, &scmi_list, node) {
+ struct device_node *child;
+
+ child = idr_find(&info->active_protocols,
+ id_table->protocol_id);
+ if (child) {
+ struct scmi_device *sdev;
+
+ sdev = scmi_get_protocol_device(child, info,
+ id_table->protocol_id,
+ id_table->name);
+ /* Set handle if not already set (device existed) */
+ if (sdev && !sdev->handle)
+ sdev->handle = scmi_handle_get_from_info(info);
+ } else {
+ dev_err(info->dev,
+ "Failed. SCMI protocol %d not active.\n",
+ id_table->protocol_id);
+ }
+ }
+ mutex_unlock(&scmi_list_mutex);
+
+out:
+ mutex_unlock(&scmi_requested_devices_mutex);
+
+ return ret;
+}
+
+/**
+ * scmi_unrequest_protocol_device - Helper to unrequest a device
+ *
+ * @id_table: A protocol/name pair descriptor for the device to be unrequested.
+ *
+ * An helper to let an SCMI driver release its request about devices; note that
+ * devices are created and initialized once the first SCMI driver request them
+ * but they destroyed only on SCMI core unloading/unbinding.
+ *
+ * The current SCMI transport layer uses such devices as internal references and
+ * as such they could be shared as same transport between multiple drivers so
+ * that cannot be safely destroyed till the whole SCMI stack is removed.
+ * (unless adding further burden of refcounting.)
+ */
+void scmi_unrequest_protocol_device(const struct scmi_device_id *id_table)
+{
+ struct scmi_requested_dev *victim, *prev, *head;
+
+ pr_debug("Unrequesting SCMI device (%s) for protocol %x\n",
+ id_table->name, id_table->protocol_id);
- if (name)
- scmi_create_protocol_device(np, info, prot_id,
- name);
+ head = idr_find(&scmi_requested_devices, id_table->protocol_id);
+ if (!head)
+ return;
+
+ /*
+ * Scan the protocol list of requested device name searching
+ * for the victim.
+ */
+ victim = head;
+ for (prev = victim; victim; prev = victim, victim = victim->next)
+ if (!strcmp(victim->id_table->name, id_table->name))
+ break;
+
+ if (victim) {
+ if (victim == head) {
+ head = victim->next;
+ if (head)
+ idr_replace(&scmi_requested_devices, head,
+ victim->id_table->protocol_id);
+ else
+ idr_remove(&scmi_requested_devices,
+ victim->id_table->protocol_id);
+ } else {
+ prev->next = victim->next;
}
+ kfree(victim);
}
}
@@ -1175,6 +1384,7 @@ static int scmi_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&info->node);
idr_init(&info->protocols);
mutex_init(&info->protocols_mtx);
+ idr_init(&info->active_protocols);
platform_set_drvdata(pdev, info);
idr_init(&info->tx_idr);
@@ -1229,6 +1439,19 @@ static int scmi_probe(struct platform_device *pdev)
continue;
}
+ /*
+ * Save this valid DT protocol descriptor amongst
+ * @active_protocols for this SCMI instance/
+ */
+ ret = idr_alloc(&info->active_protocols, child,
+ prot_id, prot_id + 1, GFP_KERNEL);
+ if (ret != prot_id) {
+ dev_err(dev, "SCMI protocol %d already activated. Skip\n",
+ prot_id);
+ continue;
+ }
+
+ of_node_get(child);
scmi_create_protocol_devices(child, info, prot_id);
}
@@ -1242,9 +1465,10 @@ void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id)
static int scmi_remove(struct platform_device *pdev)
{
- int ret = 0;
+ int ret = 0, id;
struct scmi_info *info = platform_get_drvdata(pdev);
struct idr *idr = &info->tx_idr;
+ struct device_node *child;
scmi_notification_exit(&info->handle);
@@ -1262,6 +1486,10 @@ static int scmi_remove(struct platform_device *pdev)
idr_destroy(&info->protocols);
mutex_unlock(&info->protocols_mtx);
+ idr_for_each_entry(&info->active_protocols, child, id)
+ of_node_put(child);
+ idr_destroy(&info->active_protocols);
+
/* Safe to free channels since no more users */
ret = idr_for_each(idr, info->desc->ops->chan_free, idr);
idr_destroy(&info->tx_idr);
--
2.17.1
Notification private data is currently accessible via handle->notify_priv;
this data was indeed meant to be private to the notification core support
and not to be accessible by SCMI drivers: make it private hiding it inside
instance descriptor struct scmi_info and accessible only via dedicated
helpers.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/common.h | 4 +++
drivers/firmware/arm_scmi/driver.c | 21 ++++++++++++++
drivers/firmware/arm_scmi/notify.c | 45 ++++++++++--------------------
include/linux/scmi_protocol.h | 3 --
4 files changed, 40 insertions(+), 33 deletions(-)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 65db0aefc489..5fb64182610a 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -341,4 +341,8 @@ void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
struct scmi_xfer *xfer);
+void scmi_set_notification_instance_data(const struct scmi_handle *handle,
+ void *priv);
+void *scmi_get_notification_instance_data(const struct scmi_handle *handle);
+
#endif /* _SCMI_COMMON_H */
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 77e108475aea..a0a6a3d1d239 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -113,6 +113,7 @@ struct scmi_protocol_instance {
* @protocols_mtx: A mutex to protect protocols instances initialization.
* @protocols_imp: List of protocols implemented, currently maximum of
* MAX_PROTOCOLS_IMP elements allocated by the base protocol
+ * @notify_priv: Pointer to private data structure specific to notifications.
* @node: List head
* @users: Number of users of this instance
*/
@@ -129,6 +130,7 @@ struct scmi_info {
/* Ensure mutual exclusive access to protocols instance array */
struct mutex protocols_mtx;
u8 *protocols_imp;
+ void *notify_priv;
struct list_head node;
int users;
};
@@ -170,6 +172,25 @@ static inline void scmi_dump_header_dbg(struct device *dev,
hdr->id, hdr->seq, hdr->protocol_id);
}
+void scmi_set_notification_instance_data(const struct scmi_handle *handle,
+ void *priv)
+{
+ struct scmi_info *info = handle_to_scmi_info(handle);
+
+ info->notify_priv = priv;
+ /* Ensure updated protocol private date are visible */
+ smp_wmb();
+}
+
+void *scmi_get_notification_instance_data(const struct scmi_handle *handle)
+{
+ struct scmi_info *info = handle_to_scmi_info(handle);
+
+ /* Ensure protocols_private_data has been updated */
+ smp_rmb();
+ return info->notify_priv;
+}
+
/**
* scmi_xfer_get() - Allocate one message
*
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index d88bc9960c7c..39374255b3a7 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -582,11 +582,9 @@ int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id,
struct scmi_event_header eh;
struct scmi_notify_instance *ni;
- /* Ensure notify_priv is updated */
- smp_rmb();
- if (!handle->notify_priv)
+ ni = scmi_get_notification_instance_data(handle);
+ if (!ni)
return 0;
- ni = handle->notify_priv;
r_evt = SCMI_GET_REVT(ni, proto_id, evt_id);
if (!r_evt)
@@ -762,11 +760,9 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
(!ee->num_sources && !ee->ops->get_num_sources))
return -EINVAL;
- /* Ensure notify_priv is updated */
- smp_rmb();
- if (!handle->notify_priv)
+ ni = scmi_get_notification_instance_data(handle);
+ if (!ni)
return -ENOMEM;
- ni = handle->notify_priv;
/* num_sources cannot be <= 0 */
if (ee->num_sources) {
@@ -851,12 +847,10 @@ void scmi_deregister_protocol_events(const struct scmi_handle *handle,
struct scmi_notify_instance *ni;
struct scmi_registered_events_desc *pd;
- /* Ensure notify_priv is updated */
- smp_rmb();
- if (!handle->notify_priv)
+ ni = scmi_get_notification_instance_data(handle);
+ if (!ni)
return;
- ni = handle->notify_priv;
pd = ni->registered_protocols[proto_id];
if (!pd)
return;
@@ -1359,11 +1353,9 @@ static int scmi_register_notifier(const struct scmi_handle *handle,
struct scmi_event_handler *hndl;
struct scmi_notify_instance *ni;
- /* Ensure notify_priv is updated */
- smp_rmb();
- if (!handle->notify_priv)
+ ni = scmi_get_notification_instance_data(handle);
+ if (!ni)
return -ENODEV;
- ni = handle->notify_priv;
evt_key = MAKE_HASH_KEY(proto_id, evt_id,
src_id ? *src_id : SRC_ID_MASK);
@@ -1407,11 +1399,9 @@ static int scmi_unregister_notifier(const struct scmi_handle *handle,
struct scmi_event_handler *hndl;
struct scmi_notify_instance *ni;
- /* Ensure notify_priv is updated */
- smp_rmb();
- if (!handle->notify_priv)
+ ni = scmi_get_notification_instance_data(handle);
+ if (!ni)
return -ENODEV;
- ni = handle->notify_priv;
evt_key = MAKE_HASH_KEY(proto_id, evt_id,
src_id ? *src_id : SRC_ID_MASK);
@@ -1684,8 +1674,8 @@ int scmi_notification_init(struct scmi_handle *handle)
INIT_WORK(&ni->init_work, scmi_protocols_late_init);
+ scmi_set_notification_instance_data(handle, ni);
handle->notify_ops = ¬ify_ops;
- handle->notify_priv = ni;
/* Ensure handle is up to date */
smp_wmb();
@@ -1697,7 +1687,7 @@ int scmi_notification_init(struct scmi_handle *handle)
err:
dev_warn(handle->dev, "Initialization Failed.\n");
- devres_release_group(handle->dev, NULL);
+ devres_release_group(handle->dev, gid);
return -ENOMEM;
}
@@ -1709,15 +1699,10 @@ void scmi_notification_exit(struct scmi_handle *handle)
{
struct scmi_notify_instance *ni;
- /* Ensure notify_priv is updated */
- smp_rmb();
- if (!handle->notify_priv)
+ ni = scmi_get_notification_instance_data(handle);
+ if (!ni)
return;
- ni = handle->notify_priv;
-
- handle->notify_priv = NULL;
- /* Ensure handle is up to date */
- smp_wmb();
+ scmi_set_notification_instance_data(handle, NULL);
/* Destroy while letting pending work complete */
destroy_workqueue(ni->notify_wq);
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 6c05e8acafac..c5d3f9b7de7c 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -609,8 +609,6 @@ struct scmi_notify_ops {
* dedicated protocol handler
* @put_ops: method to release a protocol
* @notify_ops: pointer to set of notifications related operations
- * @notify_priv: pointer to private data structure specific to notifications
- * (for internal use only)
*/
struct scmi_handle {
struct device *dev;
@@ -627,7 +625,6 @@ struct scmi_handle {
void (*put_ops)(const struct scmi_handle *handle, u8 proto);
const struct scmi_notify_ops *notify_ops;
- void *notify_priv;
};
enum scmi_std_protocol {
--
2.17.1
Now that all protocols and drivers have been ported to the new interface
based on protocol handles and get/put operations, remove all the legacy
transient initialization code.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/bus.c | 26 +-------------------------
drivers/firmware/arm_scmi/common.h | 5 +----
2 files changed, 2 insertions(+), 29 deletions(-)
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 044aa9e3ebb0..9fbf618b9c4b 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -66,27 +66,11 @@ const struct scmi_protocol *scmi_get_protocol(int protocol_id)
return proto;
}
-static int scmi_protocol_init(int protocol_id, struct scmi_handle *handle)
-{
- const struct scmi_protocol *proto;
-
- proto = scmi_get_protocol(protocol_id);
- if (!proto)
- return -EINVAL;
- return proto->init(handle);
-}
-
-static int scmi_protocol_dummy_init(struct scmi_handle *handle)
-{
- return 0;
-}
-
static int scmi_dev_probe(struct device *dev)
{
struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
struct scmi_device *scmi_dev = to_scmi_dev(dev);
const struct scmi_device_id *id;
- int ret;
id = scmi_dev_match_id(scmi_dev, scmi_drv);
if (!id)
@@ -95,14 +79,6 @@ static int scmi_dev_probe(struct device *dev)
if (!scmi_dev->handle)
return -EPROBE_DEFER;
- ret = scmi_protocol_init(scmi_dev->protocol_id, scmi_dev->handle);
- if (ret)
- return ret;
-
- /* Skip protocol initialisation for additional devices */
- idr_replace(&scmi_available_protocols, &scmi_protocol_dummy_init,
- scmi_dev->protocol_id);
-
return scmi_drv->probe(scmi_dev);
}
@@ -219,7 +195,7 @@ int scmi_protocol_register(const struct scmi_protocol *proto)
return -EINVAL;
}
- if (!proto->init && !proto->init_instance) {
+ if (!proto->init_instance) {
pr_err("missing .init() for protocol 0x%x\n", proto->id);
return -EINVAL;
}
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 45387a32d79e..86f4fb707145 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -224,14 +224,12 @@ int scmi_version_get(const struct scmi_handle *h, u8 protocol, u32 *version);
void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
u8 *prot_imp);
-typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *);
typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
/**
* struct scmi_protocol - Protocol descriptor
* @id: Protocol ID.
- * @init: Mandatory protocol initialization function.
- * @init_instance: Optional protocol instance initialization function.
+ * @init_instance: Mandatory protocol initialization function.
* @deinit_instance: Optional protocol de-initialization function.
* @ops: Optional reference to the operations provided by the protocol and
* exposed in scmi_protocol.h.
@@ -239,7 +237,6 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
*/
struct scmi_protocol {
const u8 id;
- const scmi_prot_init_fn_t init;
const scmi_prot_init_ph_fn_t init_instance;
const scmi_prot_init_ph_fn_t deinit_instance;
const void *ops;
--
2.17.1
Now that all the SCMI driver users have been migrated to the new interface
remove the legacy interface and all the transient code.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/perf.c | 120 -------------------------------
include/linux/scmi_protocol.h | 27 -------
2 files changed, 147 deletions(-)
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 99144a70ded6..b2e1bdad2b3a 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -391,15 +391,6 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
return scmi_perf_mb_limits_set(ph, domain, max_perf, min_perf);
}
-static int __scmi_perf_limits_set(const struct scmi_handle *handle,
- u32 domain, u32 max_perf, u32 min_perf)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_perf_limits_set(ph, domain, max_perf, min_perf);
-}
-
static int scmi_perf_mb_limits_get(const struct scmi_protocol_handle *ph,
u32 domain, u32 *max_perf, u32 *min_perf)
{
@@ -441,15 +432,6 @@ static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph,
return scmi_perf_mb_limits_get(ph, domain, max_perf, min_perf);
}
-static int __scmi_perf_limits_get(const struct scmi_handle *handle,
- u32 domain, u32 *max_perf, u32 *min_perf)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_perf_limits_get(ph, domain, max_perf, min_perf);
-}
-
static int scmi_perf_mb_level_set(const struct scmi_protocol_handle *ph,
u32 domain, u32 level, bool poll)
{
@@ -487,15 +469,6 @@ static int scmi_perf_level_set(const struct scmi_protocol_handle *ph,
return scmi_perf_mb_level_set(ph, domain, level, poll);
}
-static int __scmi_perf_level_set(const struct scmi_handle *handle,
- u32 domain, u32 level, bool poll)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_perf_level_set(ph, domain, level, poll);
-}
-
static int scmi_perf_mb_level_get(const struct scmi_protocol_handle *ph,
u32 domain, u32 *level, bool poll)
{
@@ -532,15 +505,6 @@ static int scmi_perf_level_get(const struct scmi_protocol_handle *ph,
return scmi_perf_mb_level_get(ph, domain, level, poll);
}
-static int __scmi_perf_level_get(const struct scmi_handle *handle,
- u32 domain, u32 *level, bool poll)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_perf_level_get(ph, domain, level, poll);
-}
-
static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph,
u32 domain, int message_id,
bool enable)
@@ -704,15 +668,6 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
return 0;
}
-static int __scmi_dvfs_device_opps_add(const struct scmi_handle *handle,
- struct device *dev)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_dvfs_device_opps_add(ph, dev);
-}
-
static int
scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph,
struct device *dev)
@@ -729,16 +684,6 @@ scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph,
return dom->opp[dom->opp_count - 1].trans_latency_us * 1000;
}
-static int
-__scmi_dvfs_transition_latency_get(const struct scmi_handle *handle,
- struct device *dev)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_dvfs_transition_latency_get(ph, dev);
-}
-
static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain,
unsigned long freq, bool poll)
{
@@ -748,15 +693,6 @@ static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain,
return scmi_perf_level_set(ph, domain, freq / dom->mult_factor, poll);
}
-static int __scmi_dvfs_freq_set(const struct scmi_handle *handle,
- u32 domain, unsigned long freq, bool poll)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_dvfs_freq_set(ph, domain, freq, poll);
-}
-
static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain,
unsigned long *freq, bool poll)
{
@@ -772,15 +708,6 @@ static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain,
return ret;
}
-static int __scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain,
- unsigned long *freq, bool poll)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_dvfs_freq_get(ph, domain, freq, poll);
-}
-
static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph,
u32 domain, unsigned long *freq,
unsigned long *power)
@@ -809,16 +736,6 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_dvfs_est_power_get(const struct scmi_handle *handle,
- u32 domain, unsigned long *freq,
- unsigned long *power)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_dvfs_est_power_get(ph, domain, freq, power);
-}
-
static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
struct device *dev)
{
@@ -830,15 +747,6 @@ static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
return dom->fc_info && dom->fc_info->level_set_addr;
}
-static bool __scmi_fast_switch_possible(const struct scmi_handle *handle,
- struct device *dev)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_fast_switch_possible(ph, dev);
-}
-
static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
{
struct scmi_perf_info *pi = ph->get_priv(ph);
@@ -846,29 +754,6 @@ static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
return pi->power_scale_mw;
}
-static bool __scmi_power_scale_mw_get(const struct scmi_handle *handle)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_PERF);
-
- return scmi_power_scale_mw_get(ph);
-}
-
-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,
- .level_get = __scmi_perf_level_get,
- .device_domain_id = scmi_dev_domain_id,
- .transition_latency_get = __scmi_dvfs_transition_latency_get,
- .device_opps_add = __scmi_dvfs_device_opps_add,
- .freq_set = __scmi_dvfs_freq_set,
- .freq_get = __scmi_dvfs_freq_get,
- .est_power_get = __scmi_dvfs_est_power_get,
- .fast_switch_possible = __scmi_fast_switch_possible,
- .power_scale_mw_get = __scmi_power_scale_mw_get,
-};
-
static const struct scmi_perf_proto_ops perf_proto_ops = {
.limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get,
@@ -991,7 +876,6 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
int domain;
u32 version;
struct scmi_perf_info *pinfo;
- struct scmi_handle *handle;
ph->xops->version_get(ph, &version);
@@ -1021,10 +905,6 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
pinfo->version = version;
- /* Transient code for legacy ops interface */
- handle = scmi_map_scmi_handle(ph);
- handle->perf_ops = &perf_ops;
-
return ph->set_priv(ph, pinfo);
}
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 0d2138f1d9f3..642c55a108ad 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -127,31 +127,6 @@ struct scmi_perf_proto_ops {
bool (*power_scale_mw_get)(const struct scmi_protocol_handle *ph);
};
-struct scmi_perf_ops {
- int (*limits_set)(const struct scmi_handle *handle, u32 domain,
- u32 max_perf, u32 min_perf);
- int (*limits_get)(const struct scmi_handle *handle, u32 domain,
- u32 *max_perf, u32 *min_perf);
- int (*level_set)(const struct scmi_handle *handle, u32 domain,
- u32 level, bool poll);
- int (*level_get)(const struct scmi_handle *handle, u32 domain,
- u32 *level, bool poll);
- int (*device_domain_id)(struct device *dev);
- int (*transition_latency_get)(const struct scmi_handle *handle,
- struct device *dev);
- int (*device_opps_add)(const struct scmi_handle *handle,
- struct device *dev);
- int (*freq_set)(const struct scmi_handle *handle, u32 domain,
- unsigned long rate, bool poll);
- int (*freq_get)(const struct scmi_handle *handle, u32 domain,
- unsigned long *rate, bool poll);
- int (*est_power_get)(const struct scmi_handle *handle, u32 domain,
- unsigned long *rate, unsigned long *power);
- bool (*fast_switch_possible)(const struct scmi_handle *handle,
- struct device *dev);
- bool (*power_scale_mw_get)(const struct scmi_handle *handle);
-};
-
/**
* struct scmi_power_ops - represents the various operations provided
* by SCMI Power Protocol
@@ -628,7 +603,6 @@ struct scmi_notify_ops {
* @dev: pointer to the SCMI device
* @version: pointer to the structure containing SCMI version information
* @power_ops: pointer to set of power protocol operations
- * @perf_ops: pointer to set of performance protocol operations
* @clk_ops: pointer to set of clock protocol operations
* @sensor_ops: pointer to set of sensor protocol operations
* @reset_ops: pointer to set of reset protocol operations
@@ -656,7 +630,6 @@ struct scmi_notify_ops {
struct scmi_handle {
struct device *dev;
struct scmi_revision_info *version;
- 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;
--
2.17.1
Port driver to the new SCMI Reset interface based on protocol handles
and common devm_get_ops().
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/reset/reset-scmi.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
index 8d3a858e3b19..ec77d40e64ad 100644
--- a/drivers/reset/reset-scmi.c
+++ b/drivers/reset/reset-scmi.c
@@ -2,7 +2,7 @@
/*
* ARM System Control and Management Interface (ARM SCMI) reset driver
*
- * Copyright (C) 2019 ARM Ltd.
+ * Copyright (C) 2019-2020 ARM Ltd.
*/
#include <linux/module.h>
@@ -11,18 +11,20 @@
#include <linux/reset-controller.h>
#include <linux/scmi_protocol.h>
+static const struct scmi_reset_proto_ops *reset_ops;
+
/**
* struct scmi_reset_data - reset controller information structure
* @rcdev: reset controller entity
- * @handle: ARM SCMI handle used for communication with system controller
+ * @ph: ARM SCMI protocol handle used for communication with system controller
*/
struct scmi_reset_data {
struct reset_controller_dev rcdev;
- const struct scmi_handle *handle;
+ const struct scmi_protocol_handle *ph;
};
#define to_scmi_reset_data(p) container_of((p), struct scmi_reset_data, rcdev)
-#define to_scmi_handle(p) (to_scmi_reset_data(p)->handle)
+#define to_scmi_handle(p) (to_scmi_reset_data(p)->ph)
/**
* scmi_reset_assert() - assert device reset
@@ -37,9 +39,9 @@ struct scmi_reset_data {
static int
scmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
{
- const struct scmi_handle *handle = to_scmi_handle(rcdev);
+ const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
- return handle->reset_ops->assert(handle, id);
+ return reset_ops->assert(ph, id);
}
/**
@@ -55,9 +57,9 @@ scmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
static int
scmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
{
- const struct scmi_handle *handle = to_scmi_handle(rcdev);
+ const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
- return handle->reset_ops->deassert(handle, id);
+ return reset_ops->deassert(ph, id);
}
/**
@@ -73,9 +75,9 @@ scmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
static int
scmi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
{
- const struct scmi_handle *handle = to_scmi_handle(rcdev);
+ const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
- return handle->reset_ops->reset(handle, id);
+ return reset_ops->reset(ph, id);
}
static const struct reset_control_ops scmi_reset_ops = {
@@ -90,10 +92,15 @@ static int scmi_reset_probe(struct scmi_device *sdev)
struct device *dev = &sdev->dev;
struct device_node *np = dev->of_node;
const struct scmi_handle *handle = sdev->handle;
+ struct scmi_protocol_handle *ph;
- if (!handle || !handle->reset_ops)
+ if (!handle)
return -ENODEV;
+ reset_ops = handle->devm_get_ops(sdev, SCMI_PROTOCOL_RESET, &ph);
+ if (IS_ERR(reset_ops))
+ return PTR_ERR(reset_ops);
+
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -101,8 +108,8 @@ static int scmi_reset_probe(struct scmi_device *sdev)
data->rcdev.ops = &scmi_reset_ops;
data->rcdev.owner = THIS_MODULE;
data->rcdev.of_node = np;
- data->rcdev.nr_resets = handle->reset_ops->num_domains_get(handle);
- data->handle = handle;
+ data->rcdev.nr_resets = reset_ops->num_domains_get(ph);
+ data->ph = ph;
return devm_reset_controller_register(dev, &data->rcdev);
}
--
2.17.1
Port driver to the new SCMI Clock interface based on protocol handles
and common devm_get_ops().
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/clk/clk-scmi.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index c754dfbb73fd..9d5e1262673b 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -2,7 +2,7 @@
/*
* System Control and Power Interface (SCMI) Protocol based clock driver
*
- * Copyright (C) 2018 ARM Ltd.
+ * Copyright (C) 2018-2020 ARM Ltd.
*/
#include <linux/clk-provider.h>
@@ -13,11 +13,13 @@
#include <linux/scmi_protocol.h>
#include <asm/div64.h>
+static const struct scmi_clk_proto_ops *clk_ops;
+
struct scmi_clk {
u32 id;
struct clk_hw hw;
const struct scmi_clock_info *info;
- const struct scmi_handle *handle;
+ const struct scmi_protocol_handle *ph;
};
#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
@@ -29,7 +31,7 @@ static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
u64 rate;
struct scmi_clk *clk = to_scmi_clk(hw);
- ret = clk->handle->clk_ops->rate_get(clk->handle, clk->id, &rate);
+ ret = clk_ops->rate_get(clk->ph, clk->id, &rate);
if (ret)
return 0;
return rate;
@@ -69,21 +71,21 @@ static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct scmi_clk *clk = to_scmi_clk(hw);
- return clk->handle->clk_ops->rate_set(clk->handle, clk->id, rate);
+ return clk_ops->rate_set(clk->ph, clk->id, rate);
}
static int scmi_clk_enable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
- return clk->handle->clk_ops->enable(clk->handle, clk->id);
+ return clk_ops->enable(clk->ph, clk->id);
}
static void scmi_clk_disable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
- clk->handle->clk_ops->disable(clk->handle, clk->id);
+ clk_ops->disable(clk->ph, clk->id);
}
static const struct clk_ops scmi_clk_ops = {
@@ -142,11 +144,16 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
struct device *dev = &sdev->dev;
struct device_node *np = dev->of_node;
const struct scmi_handle *handle = sdev->handle;
+ struct scmi_protocol_handle *ph;
- if (!handle || !handle->clk_ops)
+ if (!handle)
return -ENODEV;
- count = handle->clk_ops->count_get(handle);
+ clk_ops = handle->devm_get_ops(sdev, SCMI_PROTOCOL_CLOCK, &ph);
+ if (IS_ERR(clk_ops))
+ return PTR_ERR(clk_ops);
+
+ count = clk_ops->count_get(ph);
if (count < 0) {
dev_err(dev, "%pOFn: invalid clock output count\n", np);
return -EINVAL;
@@ -167,14 +174,14 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
if (!sclk)
return -ENOMEM;
- sclk->info = handle->clk_ops->info_get(handle, idx);
+ sclk->info = clk_ops->info_get(ph, idx);
if (!sclk->info) {
dev_dbg(dev, "invalid clock info for idx %d\n", idx);
continue;
}
sclk->id = idx;
- sclk->handle = handle;
+ sclk->ph = ph;
err = scmi_clk_ops_init(dev, sclk);
if (err) {
--
2.17.1
Port Base protocol to new protocol handles based interface.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/base.c | 117 +++++++++++++++--------------
drivers/firmware/arm_scmi/common.h | 3 +-
drivers/firmware/arm_scmi/driver.c | 14 +++-
3 files changed, 71 insertions(+), 63 deletions(-)
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index e7c21e925ea2..c9e5e451b377 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -50,30 +50,30 @@ struct scmi_base_error_notify_payld {
* scmi_base_attributes_get() - gets the implementation details
* that are associated with the base protocol.
*
- * @handle: SCMI entity handle
+ * @ph: SCMI protocol handle
*
* Return: 0 on success, else appropriate SCMI error.
*/
-static int scmi_base_attributes_get(const struct scmi_handle *handle)
+static int scmi_base_attributes_get(const struct scmi_protocol_handle *ph)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_base_attributes *attr_info;
- struct scmi_revision_info *rev = handle->version;
+ struct scmi_revision_info *rev = ph->get_priv(ph);
- ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
- SCMI_PROTOCOL_BASE, 0, sizeof(*attr_info), &t);
+ ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
+ 0, sizeof(*attr_info), &t);
if (ret)
return ret;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
attr_info = t->rx.buf;
rev->num_protocols = attr_info->num_protocols;
rev->num_agents = attr_info->num_agents;
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -81,19 +81,20 @@ static int scmi_base_attributes_get(const struct scmi_handle *handle)
/**
* scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string.
*
- * @handle: SCMI entity handle
+ * @ph: SCMI protocol handle
* @sub_vendor: specify true if sub-vendor ID is needed
*
* Return: 0 on success, else appropriate SCMI error.
*/
static int
-scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor)
+scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor)
{
u8 cmd;
int ret, size;
char *vendor_id;
struct scmi_xfer *t;
- struct scmi_revision_info *rev = handle->version;
+ struct scmi_revision_info *rev = ph->get_priv(ph);
+
if (sub_vendor) {
cmd = BASE_DISCOVER_SUB_VENDOR;
@@ -105,15 +106,15 @@ scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor)
size = ARRAY_SIZE(rev->vendor_id);
}
- ret = scmi_xfer_get_init(handle, cmd, SCMI_PROTOCOL_BASE, 0, size, &t);
+ ret = ph->xops->xfer_get_init(ph, cmd, 0, size, &t);
if (ret)
return ret;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
memcpy(vendor_id, t->rx.buf, size);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -123,30 +124,30 @@ scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor)
* implementation 32-bit version. The format of the version number is
* vendor-specific
*
- * @handle: SCMI entity handle
+ * @ph: SCMI protocol handle
*
* Return: 0 on success, else appropriate SCMI error.
*/
static int
-scmi_base_implementation_version_get(const struct scmi_handle *handle)
+scmi_base_implementation_version_get(const struct scmi_protocol_handle *ph)
{
int ret;
__le32 *impl_ver;
struct scmi_xfer *t;
- struct scmi_revision_info *rev = handle->version;
+ struct scmi_revision_info *rev = ph->get_priv(ph);
- ret = scmi_xfer_get_init(handle, BASE_DISCOVER_IMPLEMENT_VERSION,
- SCMI_PROTOCOL_BASE, 0, sizeof(*impl_ver), &t);
+ ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_IMPLEMENT_VERSION,
+ 0, sizeof(*impl_ver), &t);
if (ret)
return ret;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
impl_ver = t->rx.buf;
rev->impl_ver = le32_to_cpu(*impl_ver);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -155,23 +156,24 @@ scmi_base_implementation_version_get(const struct scmi_handle *handle)
* scmi_base_implementation_list_get() - gets the list of protocols it is
* OSPM is allowed to access
*
- * @handle: SCMI entity handle
+ * @ph: SCMI protocol handle
* @protocols_imp: pointer to hold the list of protocol identifiers
*
* Return: 0 on success, else appropriate SCMI error.
*/
-static int scmi_base_implementation_list_get(const struct scmi_handle *handle,
- u8 *protocols_imp)
+static int
+scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph,
+ u8 *protocols_imp)
{
u8 *list;
int ret, loop;
struct scmi_xfer *t;
__le32 *num_skip, *num_ret;
u32 tot_num_ret = 0, loop_num_ret;
- struct device *dev = handle->dev;
+ struct device *dev = ph->dev;
- ret = scmi_xfer_get_init(handle, BASE_DISCOVER_LIST_PROTOCOLS,
- SCMI_PROTOCOL_BASE, sizeof(*num_skip), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_LIST_PROTOCOLS,
+ sizeof(*num_skip), 0, &t);
if (ret)
return ret;
@@ -183,7 +185,7 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle,
/* Set the number of protocols to be skipped/already read */
*num_skip = cpu_to_le32(tot_num_ret);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (ret)
break;
@@ -198,10 +200,10 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle,
tot_num_ret += loop_num_ret;
- scmi_reset_rx_to_maxsz(handle, t);
+ ph->xops->reset_rx_to_maxsz(ph, t);
} while (loop_num_ret);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -209,7 +211,7 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle,
/**
* scmi_base_discover_agent_get() - discover the name of an agent
*
- * @handle: SCMI entity handle
+ * @ph: SCMI protocol handle
* @id: Agent identifier
* @name: Agent identifier ASCII string
*
@@ -218,63 +220,63 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle,
*
* Return: 0 on success, else appropriate SCMI error.
*/
-static int scmi_base_discover_agent_get(const struct scmi_handle *handle,
+static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph,
int id, char *name)
{
int ret;
struct scmi_xfer *t;
- ret = scmi_xfer_get_init(handle, BASE_DISCOVER_AGENT,
- SCMI_PROTOCOL_BASE, sizeof(__le32),
- SCMI_MAX_STR_SIZE, &t);
+ ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_AGENT,
+ sizeof(__le32), SCMI_MAX_STR_SIZE, &t);
if (ret)
return ret;
put_unaligned_le32(id, t->tx.buf);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
strlcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_base_error_notify(const struct scmi_handle *handle, bool enable)
+static int scmi_base_error_notify(const struct scmi_protocol_handle *ph,
+ bool enable)
{
int ret;
u32 evt_cntl = enable ? BASE_TP_NOTIFY_ALL : 0;
struct scmi_xfer *t;
struct scmi_msg_base_error_notify *cfg;
- ret = scmi_xfer_get_init(handle, BASE_NOTIFY_ERRORS,
- SCMI_PROTOCOL_BASE, sizeof(*cfg), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, BASE_NOTIFY_ERRORS,
+ sizeof(*cfg), 0, &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->event_control = cpu_to_le32(evt_cntl);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_base_set_notify_enabled(const void *handle,
+static int scmi_base_set_notify_enabled(const void *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
- ret = scmi_base_error_notify(handle, enable);
+ ret = scmi_base_error_notify(ph, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] ret:%d\n", evt_id, ret);
return ret;
}
-static void *scmi_base_fill_custom_report(const void *handle,
+static void *scmi_base_fill_custom_report(const void *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -326,17 +328,16 @@ static const struct scmi_protocol_events base_protocol_events = {
.num_sources = SCMI_BASE_NUM_SOURCES,
};
-int scmi_base_protocol_init(struct scmi_handle *h)
+static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
{
int id, ret;
u8 *prot_imp;
u32 version;
char name[SCMI_MAX_STR_SIZE];
- const struct scmi_handle *handle = h;
- struct device *dev = handle->dev;
- struct scmi_revision_info *rev = handle->version;
+ struct device *dev = ph->dev;
+ struct scmi_revision_info *rev = scmi_get_revision_area(ph);
- ret = scmi_version_get(handle, SCMI_PROTOCOL_BASE, &version);
+ ret = ph->xops->version_get(ph, &version);
if (ret)
return ret;
@@ -346,13 +347,15 @@ int scmi_base_protocol_init(struct scmi_handle *h)
rev->major_ver = PROTOCOL_REV_MAJOR(version),
rev->minor_ver = PROTOCOL_REV_MINOR(version);
+ ph->set_priv(ph, rev);
+
+ scmi_base_attributes_get(ph);
+ scmi_base_vendor_id_get(ph, false);
+ scmi_base_vendor_id_get(ph, true);
+ scmi_base_implementation_version_get(ph);
+ scmi_base_implementation_list_get(ph, prot_imp);
- scmi_base_attributes_get(handle);
- scmi_base_vendor_id_get(handle, false);
- scmi_base_vendor_id_get(handle, true);
- scmi_base_implementation_version_get(handle);
- scmi_base_implementation_list_get(handle, prot_imp);
- scmi_setup_protocol_implemented(handle, prot_imp);
+ scmi_setup_protocol_implemented(ph, prot_imp);
dev_info(dev, "SCMI Protocol v%d.%d '%s:%s' Firmware version 0x%x\n",
rev->major_ver, rev->minor_ver, rev->vendor_id,
@@ -361,7 +364,7 @@ int scmi_base_protocol_init(struct scmi_handle *h)
rev->num_agents);
for (id = 0; id < rev->num_agents; id++) {
- scmi_base_discover_agent_get(handle, id, name);
+ scmi_base_discover_agent_get(ph, id, name);
dev_dbg(dev, "Agent %d: %s\n", id, name);
}
@@ -370,7 +373,7 @@ int scmi_base_protocol_init(struct scmi_handle *h)
static const struct scmi_protocol scmi_base = {
.id = SCMI_PROTOCOL_BASE,
- .init = &scmi_base_protocol_init,
+ .init_instance = &scmi_base_protocol_init,
.ops = NULL,
.events = &base_protocol_events,
};
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 428bfba40dfd..c7b48f1e5fe0 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -221,10 +221,9 @@ int scmi_handle_put(const struct scmi_handle *handle);
struct scmi_handle *scmi_handle_get(struct device *dev);
void scmi_set_handle(struct scmi_device *scmi_dev);
int scmi_version_get(const struct scmi_handle *h, u8 protocol, u32 *version);
-void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
+void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
u8 *prot_imp);
-int scmi_base_protocol_init(struct scmi_handle *h);
typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *);
typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index b936cf47cd7d..b76c06b8bbc3 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -883,10 +883,11 @@ scmi_get_protocol_operations(struct scmi_handle *handle, u8 protocol_id,
return pi->proto->ops;
}
-void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
+void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
u8 *prot_imp)
{
- struct scmi_info *info = handle_to_scmi_info(handle);
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+ struct scmi_info *info = handle_to_scmi_info(pi->handle);
info->protocols_imp = prot_imp;
}
@@ -1265,9 +1266,14 @@ static int scmi_probe(struct platform_device *pdev)
if (scmi_notification_init(handle))
dev_err(dev, "SCMI Notifications NOT available.\n");
- ret = scmi_base_protocol_init(handle);
+ /*
+ * Trigger SCMI Base protocol initialization.
+ * It's mandatory and won't be ever released/deinit until the
+ * SCMI stack is shutdown/unloaded as a whole.
+ */
+ ret = scmi_acquire_protocol(handle, SCMI_PROTOCOL_BASE);
if (ret) {
- dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);
+ dev_err(dev, "unable to communicate with SCMI\n");
return ret;
}
--
2.17.1
Convert internals of protocol implementation to use protocol handles and
expose a new protocol operations interface for SCMI driver using the new
get/put common operations, while keeping the old handle->sensor_ops still
around to ease transition.
Remove handle->sensor_priv now unused.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/sensors.c | 275 ++++++++++++++++++----------
include/linux/scmi_protocol.h | 22 ++-
2 files changed, 194 insertions(+), 103 deletions(-)
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index e1e428d59d5f..5d2da4f78108 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -201,21 +201,21 @@ struct sensors_info {
struct scmi_sensor_info *sensors;
};
-static int scmi_sensor_attributes_get(const struct scmi_handle *handle,
+static int scmi_sensor_attributes_get(const struct scmi_protocol_handle *ph,
struct sensors_info *si)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_resp_sensor_attributes *attr;
- ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
- SCMI_PROTOCOL_SENSOR, 0, sizeof(*attr), &t);
+ ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
+ 0, sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
si->num_sensors = le16_to_cpu(attr->num_sensors);
si->max_requests = attr->max_requests;
@@ -224,7 +224,7 @@ static int scmi_sensor_attributes_get(const struct scmi_handle *handle,
si->reg_size = le32_to_cpu(attr->reg_size);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
@@ -235,7 +235,7 @@ static inline void scmi_parse_range_attrs(struct scmi_range_attrs *out,
out->max_range = get_unaligned_le64((void *)&in->max_range_low);
}
-static int scmi_sensor_update_intervals(const struct scmi_handle *handle,
+static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph,
struct scmi_sensor_info *s)
{
int ret, cnt;
@@ -245,8 +245,8 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle,
struct scmi_msg_resp_sensor_list_update_intervals *buf;
struct scmi_msg_sensor_list_update_intervals *msg;
- ret = scmi_xfer_get_init(handle, SENSOR_LIST_UPDATE_INTERVALS,
- SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &ti);
+ ret = ph->xops->xfer_get_init(ph, SENSOR_LIST_UPDATE_INTERVALS,
+ sizeof(*msg), 0, &ti);
if (ret)
return ret;
@@ -259,7 +259,7 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle,
msg->id = cpu_to_le32(s->id);
msg->index = cpu_to_le32(desc_index);
- ret = scmi_do_xfer(handle, ti);
+ ret = ph->xops->do_xfer(ph, ti);
if (ret)
break;
@@ -277,7 +277,7 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle,
/* segmented intervals are reported in one triplet */
if (s->intervals.segmented &&
(num_remaining || num_returned != 3)) {
- dev_err(handle->dev,
+ dev_err(ph->dev,
"Sensor ID:%d advertises an invalid segmented interval (%d)\n",
s->id, s->intervals.count);
s->intervals.segmented = false;
@@ -288,7 +288,7 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle,
/* Direct allocation when exceeding pre-allocated */
if (s->intervals.count >= SCMI_MAX_PREALLOC_POOL) {
s->intervals.desc =
- devm_kcalloc(handle->dev,
+ devm_kcalloc(ph->dev,
s->intervals.count,
sizeof(*s->intervals.desc),
GFP_KERNEL);
@@ -300,7 +300,7 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle,
}
}
} else if (desc_index + num_returned > s->intervals.count) {
- dev_err(handle->dev,
+ dev_err(ph->dev,
"No. of update intervals can't exceed %d\n",
s->intervals.count);
ret = -EINVAL;
@@ -313,18 +313,18 @@ static int scmi_sensor_update_intervals(const struct scmi_handle *handle,
desc_index += num_returned;
- scmi_reset_rx_to_maxsz(handle, ti);
+ ph->xops->reset_rx_to_maxsz(ph, ti);
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
*/
} while (num_returned && num_remaining);
- scmi_xfer_put(handle, ti);
+ ph->xops->xfer_put(ph, ti);
return ret;
}
-static int scmi_sensor_axis_description(const struct scmi_handle *handle,
+static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
struct scmi_sensor_info *s)
{
int ret, cnt;
@@ -334,13 +334,13 @@ static int scmi_sensor_axis_description(const struct scmi_handle *handle,
struct scmi_msg_resp_sensor_axis_description *buf;
struct scmi_msg_sensor_axis_description_get *msg;
- s->axis = devm_kcalloc(handle->dev, s->num_axis,
+ s->axis = devm_kcalloc(ph->dev, s->num_axis,
sizeof(*s->axis), GFP_KERNEL);
if (!s->axis)
return -ENOMEM;
- ret = scmi_xfer_get_init(handle, SENSOR_AXIS_DESCRIPTION_GET,
- SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &te);
+ ret = ph->xops->xfer_get_init(ph, SENSOR_AXIS_DESCRIPTION_GET,
+ sizeof(*msg), 0, &te);
if (ret)
return ret;
@@ -354,7 +354,7 @@ static int scmi_sensor_axis_description(const struct scmi_handle *handle,
msg->id = cpu_to_le32(s->id);
msg->axis_desc_index = cpu_to_le32(desc_index);
- ret = scmi_do_xfer(handle, te);
+ ret = ph->xops->do_xfer(ph, te);
if (ret)
break;
@@ -363,7 +363,7 @@ static int scmi_sensor_axis_description(const struct scmi_handle *handle,
num_remaining = NUM_AXIS_REMAINING(flags);
if (desc_index + num_returned > s->num_axis) {
- dev_err(handle->dev, "No. of axis can't exceed %d\n",
+ dev_err(ph->dev, "No. of axis can't exceed %d\n",
s->num_axis);
break;
}
@@ -405,18 +405,18 @@ static int scmi_sensor_axis_description(const struct scmi_handle *handle,
desc_index += num_returned;
- scmi_reset_rx_to_maxsz(handle, te);
+ ph->xops->reset_rx_to_maxsz(ph, te);
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
*/
} while (num_returned && num_remaining);
- scmi_xfer_put(handle, te);
+ ph->xops->xfer_put(ph, te);
return ret;
}
-static int scmi_sensor_description_get(const struct scmi_handle *handle,
+static int scmi_sensor_description_get(const struct scmi_protocol_handle *ph,
struct sensors_info *si)
{
int ret, cnt;
@@ -425,8 +425,8 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
struct scmi_xfer *t;
struct scmi_msg_resp_sensor_description *buf;
- ret = scmi_xfer_get_init(handle, SENSOR_DESCRIPTION_GET,
- SCMI_PROTOCOL_SENSOR, sizeof(__le32), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, SENSOR_DESCRIPTION_GET,
+ sizeof(__le32), 0, &t);
if (ret)
return ret;
@@ -437,7 +437,8 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
/* Set the number of sensors to be skipped/already read */
put_unaligned_le32(desc_index, t->tx.buf);
- ret = scmi_do_xfer(handle, t);
+
+ ret = ph->xops->do_xfer(ph, t);
if (ret)
break;
@@ -445,7 +446,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
num_remaining = le16_to_cpu(buf->num_remaining);
if (desc_index + num_returned > si->num_sensors) {
- dev_err(handle->dev, "No. of sensors can't exceed %d",
+ dev_err(ph->dev, "No. of sensors can't exceed %d",
si->num_sensors);
break;
}
@@ -500,8 +501,8 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
* Since the command is optional, on error carry
* on without any update interval.
*/
- if (scmi_sensor_update_intervals(handle, s))
- dev_dbg(handle->dev,
+ if (scmi_sensor_update_intervals(ph, s))
+ dev_dbg(ph->dev,
"Update Intervals not available for sensor ID:%d\n",
s->id);
}
@@ -535,7 +536,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
}
}
if (s->num_axis > 0) {
- ret = scmi_sensor_axis_description(handle, s);
+ ret = scmi_sensor_axis_description(ph, s);
if (ret)
goto out;
}
@@ -545,7 +546,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
desc_index += num_returned;
- scmi_reset_rx_to_maxsz(handle, t);
+ ph->xops->reset_rx_to_maxsz(ph, t);
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
@@ -553,12 +554,12 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
} while (num_returned && num_remaining);
out:
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
static inline int
-scmi_sensor_request_notify(const struct scmi_handle *handle, u32 sensor_id,
+scmi_sensor_request_notify(const struct scmi_protocol_handle *ph, u32 sensor_id,
u8 message_id, bool enable)
{
int ret;
@@ -566,8 +567,7 @@ scmi_sensor_request_notify(const struct scmi_handle *handle, u32 sensor_id,
struct scmi_xfer *t;
struct scmi_msg_sensor_request_notify *cfg;
- ret = scmi_xfer_get_init(handle, message_id,
- SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*cfg), 0, &t);
if (ret)
return ret;
@@ -575,40 +575,40 @@ scmi_sensor_request_notify(const struct scmi_handle *handle, u32 sensor_id,
cfg->id = cpu_to_le32(sensor_id);
cfg->event_control = cpu_to_le32(evt_cntl);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle,
+static int scmi_sensor_trip_point_notify(const struct scmi_protocol_handle *ph,
u32 sensor_id, bool enable)
{
- return scmi_sensor_request_notify(handle, sensor_id,
+ return scmi_sensor_request_notify(ph, sensor_id,
SENSOR_TRIP_POINT_NOTIFY,
enable);
}
static int
-scmi_sensor_continuous_update_notify(const struct scmi_handle *handle,
+scmi_sensor_continuous_update_notify(const struct scmi_protocol_handle *ph,
u32 sensor_id, bool enable)
{
- return scmi_sensor_request_notify(handle, sensor_id,
+ return scmi_sensor_request_notify(ph, sensor_id,
SENSOR_CONTINUOUS_UPDATE_NOTIFY,
enable);
}
static int
-scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
- u8 trip_id, u64 trip_value)
+scmi_sensor_trip_point_config(const struct scmi_protocol_handle *ph,
+ u32 sensor_id, u8 trip_id, u64 trip_value)
{
int ret;
u32 evt_cntl = SENSOR_TP_BOTH;
struct scmi_xfer *t;
struct scmi_msg_set_sensor_trip_point *trip;
- ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_CONFIG,
- SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, SENSOR_TRIP_POINT_CONFIG,
+ sizeof(*trip), 0, &t);
if (ret)
return ret;
@@ -618,47 +618,66 @@ scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
trip->value_low = cpu_to_le32(trip_value & 0xffffffff);
trip->value_high = cpu_to_le32(trip_value >> 32);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_sensor_config_get(const struct scmi_handle *handle,
+static int
+__scmi_sensor_trip_point_config(const struct scmi_handle *handle,
+ u32 sensor_id, u8 trip_id, u64 trip_value)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
+
+ return scmi_sensor_trip_point_config(ph, sensor_id, trip_id,
+ trip_value);
+}
+
+static int scmi_sensor_config_get(const struct scmi_protocol_handle *ph,
u32 sensor_id, u32 *sensor_config)
{
int ret;
struct scmi_xfer *t;
- ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_GET,
- SCMI_PROTOCOL_SENSOR, sizeof(__le32),
- sizeof(__le32), &t);
+ ret = ph->xops->xfer_get_init(ph, SENSOR_CONFIG_GET,
+ sizeof(__le32), sizeof(__le32), &t);
if (ret)
return ret;
put_unaligned_le32(cpu_to_le32(sensor_id), t->tx.buf);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
- struct sensors_info *si = handle->sensor_priv;
+ struct sensors_info *si = ph->get_priv(ph);
struct scmi_sensor_info *s = si->sensors + sensor_id;
*sensor_config = get_unaligned_le64(t->rx.buf);
s->sensor_config = *sensor_config;
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
-static int scmi_sensor_config_set(const struct scmi_handle *handle,
+static int __scmi_sensor_config_get(const struct scmi_handle *handle,
+ u32 sensor_id, u32 *sensor_config)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
+
+ return scmi_sensor_config_get(ph, sensor_id, sensor_config);
+}
+
+static int scmi_sensor_config_set(const struct scmi_protocol_handle *ph,
u32 sensor_id, u32 sensor_config)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_sensor_config_set *msg;
- ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_SET,
- SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, SENSOR_CONFIG_SET,
+ sizeof(*msg), 0, &t);
if (ret)
return ret;
@@ -666,21 +685,30 @@ static int scmi_sensor_config_set(const struct scmi_handle *handle,
msg->id = cpu_to_le32(sensor_id);
msg->sensor_config = cpu_to_le32(sensor_config);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
- struct sensors_info *si = handle->sensor_priv;
+ struct sensors_info *si = ph->get_priv(ph);
struct scmi_sensor_info *s = si->sensors + sensor_id;
s->sensor_config = sensor_config;
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
+static int __scmi_sensor_config_set(const struct scmi_handle *handle,
+ u32 sensor_id, u32 sensor_config)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
+
+ return scmi_sensor_config_set(ph, sensor_id, sensor_config);
+}
+
/**
* scmi_sensor_reading_get - Read scalar sensor value
- * @handle: Platform handle
+ * @ph: Protocol handle
* @sensor_id: Sensor ID
* @value: The 64bit value sensor reading
*
@@ -693,17 +721,17 @@ static int scmi_sensor_config_set(const struct scmi_handle *handle,
*
* Return: 0 on Success
*/
-static int scmi_sensor_reading_get(const struct scmi_handle *handle,
+static int scmi_sensor_reading_get(const struct scmi_protocol_handle *ph,
u32 sensor_id, u64 *value)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_sensor_reading_get *sensor;
- struct sensors_info *si = handle->sensor_priv;
+ struct sensors_info *si = ph->get_priv(ph);
struct scmi_sensor_info *s = si->sensors + sensor_id;
- ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
- SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, SENSOR_READING_GET,
+ sizeof(*sensor), 0, &t);
if (ret)
return ret;
@@ -711,7 +739,7 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle,
sensor->id = cpu_to_le32(sensor_id);
if (s->async) {
sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
- ret = scmi_do_xfer_with_response(handle, t);
+ ret = ph->xops->do_xfer_with_response(ph, t);
if (!ret) {
struct scmi_resp_sensor_reading_complete *resp;
@@ -723,15 +751,24 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle,
}
} else {
sensor->flags = cpu_to_le32(0);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret)
*value = get_unaligned_le64(t->rx.buf);
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
+static int __scmi_sensor_reading_get(const struct scmi_handle *handle,
+ u32 sensor_id, u64 *value)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
+
+ return scmi_sensor_reading_get(ph, sensor_id, value);
+}
+
static inline void
scmi_parse_sensor_readings(struct scmi_sensor_reading *out,
const struct scmi_sensor_reading_resp *in)
@@ -742,7 +779,7 @@ scmi_parse_sensor_readings(struct scmi_sensor_reading *out,
/**
* scmi_sensor_reading_get_timestamped - Read multiple-axis timestamped values
- * @handle: Platform handle
+ * @ph: Protocol handle
* @sensor_id: Sensor ID
* @count: The length of the provided @readings array
* @readings: An array of elements each representing a timestamped per-axis
@@ -755,22 +792,22 @@ scmi_parse_sensor_readings(struct scmi_sensor_reading *out,
* Return: 0 on Success
*/
static int
-scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle,
+scmi_sensor_reading_get_timestamped(const struct scmi_protocol_handle *ph,
u32 sensor_id, u8 count,
struct scmi_sensor_reading *readings)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_sensor_reading_get *sensor;
- struct sensors_info *si = handle->sensor_priv;
+ struct sensors_info *si = ph->get_priv(ph);
struct scmi_sensor_info *s = si->sensors + sensor_id;
if (!count || !readings ||
(!s->num_axis && count > 1) || (s->num_axis && count > s->num_axis))
return -EINVAL;
- ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
- SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t);
+ ret = ph->xops->xfer_get_init(ph, SENSOR_READING_GET,
+ sizeof(*sensor), 0, &t);
if (ret)
return ret;
@@ -778,7 +815,7 @@ scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle,
sensor->id = cpu_to_le32(sensor_id);
if (s->async) {
sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
- ret = scmi_do_xfer_with_response(handle, t);
+ ret = ph->xops->do_xfer_with_response(ph, t);
if (!ret) {
int i;
struct scmi_resp_sensor_reading_complete_v3 *resp;
@@ -794,7 +831,7 @@ scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle,
}
} else {
sensor->flags = cpu_to_le32(0);
- ret = scmi_do_xfer(handle, t);
+ ret = ph->xops->do_xfer(ph, t);
if (!ret) {
int i;
struct scmi_sensor_reading_resp *resp_readings;
@@ -806,26 +843,65 @@ scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle,
}
}
- scmi_xfer_put(handle, t);
+ ph->xops->xfer_put(ph, t);
return ret;
}
+static int
+__scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle,
+ u32 sensor_id, u8 count,
+ struct scmi_sensor_reading *readings)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
+
+ return scmi_sensor_reading_get_timestamped(ph, sensor_id, count,
+ readings);
+}
+
static const struct scmi_sensor_info *
-scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id)
+scmi_sensor_info_get(const struct scmi_protocol_handle *ph, u32 sensor_id)
{
- struct sensors_info *si = handle->sensor_priv;
+ struct sensors_info *si = ph->get_priv(ph);
return si->sensors + sensor_id;
}
-static int scmi_sensor_count_get(const struct scmi_handle *handle)
+static const struct scmi_sensor_info *
+__scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id)
{
- struct sensors_info *si = handle->sensor_priv;
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
+
+ return scmi_sensor_info_get(ph, sensor_id);
+}
+
+static int scmi_sensor_count_get(const struct scmi_protocol_handle *ph)
+{
+ struct sensors_info *si = ph->get_priv(ph);
return si->num_sensors;
}
+static int __scmi_sensor_count_get(const struct scmi_handle *handle)
+{
+ const struct scmi_protocol_handle *ph =
+ scmi_map_protocol_handle(handle, SCMI_PROTOCOL_SENSOR);
+
+ return scmi_sensor_count_get(ph);
+}
+
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,
+ .reading_get = __scmi_sensor_reading_get,
+ .reading_get_timestamped = __scmi_sensor_reading_get_timestamped,
+ .config_get = __scmi_sensor_config_get,
+ .config_set = __scmi_sensor_config_set,
+};
+
+static const struct scmi_sensor_proto_ops sensor_proto_ops = {
.count_get = scmi_sensor_count_get,
.info_get = scmi_sensor_info_get,
.trip_point_config = scmi_sensor_trip_point_config,
@@ -835,18 +911,17 @@ static const struct scmi_sensor_ops sensor_ops = {
.config_set = scmi_sensor_config_set,
};
-static int scmi_sensor_set_notify_enabled(const void *handle,
+static int scmi_sensor_set_notify_enabled(const void *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
switch (evt_id) {
case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT:
- ret = scmi_sensor_trip_point_notify(handle, src_id, enable);
+ ret = scmi_sensor_trip_point_notify(ph, src_id, enable);
break;
case SCMI_EVENT_SENSOR_UPDATE:
- ret = scmi_sensor_continuous_update_notify(handle, src_id,
- enable);
+ ret = scmi_sensor_continuous_update_notify(ph, src_id, enable);
break;
default:
ret = -EINVAL;
@@ -860,7 +935,7 @@ static int scmi_sensor_set_notify_enabled(const void *handle,
return ret;
}
-static void *scmi_sensor_fill_custom_report(const void *handle,
+static void *scmi_sensor_fill_custom_report(const void *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
@@ -891,7 +966,7 @@ static void *scmi_sensor_fill_custom_report(const void *handle,
const struct scmi_sensor_update_notify_payld *p = payld;
struct scmi_sensor_update_report *r = report;
struct sensors_info *sinfo =
- ((const struct scmi_handle *)(handle))->sensor_priv;
+ ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
/* payld_sz is variable for this event */
r->sensor_id = le32_to_cpu(p->sensor_id);
@@ -921,10 +996,10 @@ static void *scmi_sensor_fill_custom_report(const void *handle,
return rep;
}
-static int scmi_sensor_get_num_sources(const void *handle)
+static int scmi_sensor_get_num_sources(const void *ph)
{
struct sensors_info *si =
- ((const struct scmi_handle *)(handle))->sensor_priv;
+ ((const struct scmi_protocol_handle *)ph)->get_priv(ph);
return si->num_sensors;
}
@@ -960,44 +1035,46 @@ static const struct scmi_protocol_events sensor_protocol_events = {
.num_events = ARRAY_SIZE(sensor_events),
};
-static int scmi_sensors_protocol_init(struct scmi_handle *handle)
+static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
{
u32 version;
int ret;
struct sensors_info *sinfo;
+ struct scmi_handle *handle;
- scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version);
+ ph->xops->version_get(ph, &version);
- dev_dbg(handle->dev, "Sensor Version %d.%d\n",
+ dev_dbg(ph->dev, "Sensor Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
- sinfo = devm_kzalloc(handle->dev, sizeof(*sinfo), GFP_KERNEL);
+ sinfo = devm_kzalloc(ph->dev, sizeof(*sinfo), GFP_KERNEL);
if (!sinfo)
return -ENOMEM;
sinfo->version = version;
- ret = scmi_sensor_attributes_get(handle, sinfo);
+ ret = scmi_sensor_attributes_get(ph, sinfo);
if (ret)
return ret;
- sinfo->sensors = devm_kcalloc(handle->dev, sinfo->num_sensors,
+ sinfo->sensors = devm_kcalloc(ph->dev, sinfo->num_sensors,
sizeof(*sinfo->sensors), GFP_KERNEL);
if (!sinfo->sensors)
return -ENOMEM;
- ret = scmi_sensor_description_get(handle, sinfo);
+ ret = scmi_sensor_description_get(ph, sinfo);
if (ret)
return ret;
- handle->sensor_priv = sinfo;
+ /* Transient code for legacy ops interface */
+ handle = scmi_map_scmi_handle(ph);
handle->sensor_ops = &sensor_ops;
- return 0;
+ return ph->set_priv(ph, sinfo);
}
static const struct scmi_protocol scmi_sensors = {
.id = SCMI_PROTOCOL_SENSOR,
- .init = &scmi_sensors_protocol_init,
- .ops = &sensor_ops,
+ .init_instance = &scmi_sensors_protocol_init,
+ .ops = &sensor_proto_ops,
.events = &sensor_protocol_events,
};
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index d1a052cc5162..402a2765f111 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -431,7 +431,7 @@ enum scmi_sensor_class {
};
/**
- * struct scmi_sensor_ops - represents the various operations provided
+ * struct scmi_sensor_proto_ops - represents the various operations provided
* by SCMI Sensor Protocol
*
* @count_get: get the count of sensors provided by SCMI
@@ -446,6 +446,23 @@ enum scmi_sensor_class {
* @config_get: Get sensor current configuration
* @config_set: Set sensor current configuration
*/
+struct scmi_sensor_proto_ops {
+ int (*count_get)(const struct scmi_protocol_handle *ph);
+ const struct scmi_sensor_info *(*info_get)
+ (const struct scmi_protocol_handle *ph, u32 sensor_id);
+ int (*trip_point_config)(const struct scmi_protocol_handle *ph,
+ u32 sensor_id, u8 trip_id, u64 trip_value);
+ int (*reading_get)(const struct scmi_protocol_handle *ph, u32 sensor_id,
+ u64 *value);
+ int (*reading_get_timestamped)(const struct scmi_protocol_handle *ph,
+ u32 sensor_id, u8 count,
+ struct scmi_sensor_reading *readings);
+ int (*config_get)(const struct scmi_protocol_handle *ph,
+ u32 sensor_id, u32 *sensor_config);
+ int (*config_set)(const struct scmi_protocol_handle *ph,
+ u32 sensor_id, u32 sensor_config);
+};
+
struct scmi_sensor_ops {
int (*count_get)(const struct scmi_handle *handle);
const struct scmi_sensor_info *(*info_get)
@@ -611,8 +628,6 @@ struct scmi_notify_ops {
* dedicated protocol handler
* @put_ops: method to release a protocol
* @notify_ops: pointer to set of notifications related operations
- * @sensor_priv: pointer to private data structure specific to sensors
- * protocol(for internal use only)
* @voltage_priv: pointer to private data structure specific to voltage
* protocol(for internal use only)
* @notify_priv: pointer to private data structure specific to notifications
@@ -636,7 +651,6 @@ struct scmi_handle {
const struct scmi_notify_ops *notify_ops;
/* for protocol internal use */
- void *sensor_priv;
void *voltage_priv;
void *notify_priv;
void *system_priv;
--
2.17.1
Port driver to the new SCMI Voltage interface based on protocol handles
and common devm_get_ops().
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/regulator/scmi-regulator.c | 39 ++++++++++++++++--------------
1 file changed, 21 insertions(+), 18 deletions(-)
diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
index 0e8b3caa8146..4689937ebbfa 100644
--- a/drivers/regulator/scmi-regulator.c
+++ b/drivers/regulator/scmi-regulator.c
@@ -33,9 +33,12 @@
#include <linux/slab.h>
#include <linux/types.h>
+static const struct scmi_voltage_proto_ops *voltage_ops;
+
struct scmi_regulator {
u32 id;
struct scmi_device *sdev;
+ struct scmi_protocol_handle *ph;
struct regulator_dev *rdev;
struct device_node *of_node;
struct regulator_desc desc;
@@ -50,19 +53,17 @@ struct scmi_regulator_info {
static int scmi_reg_enable(struct regulator_dev *rdev)
{
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
- return handle->voltage_ops->config_set(handle, sreg->id,
- SCMI_VOLTAGE_ARCH_STATE_ON);
+ return voltage_ops->config_set(sreg->ph, sreg->id,
+ SCMI_VOLTAGE_ARCH_STATE_ON);
}
static int scmi_reg_disable(struct regulator_dev *rdev)
{
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
- return handle->voltage_ops->config_set(handle, sreg->id,
- SCMI_VOLTAGE_ARCH_STATE_OFF);
+ return voltage_ops->config_set(sreg->ph, sreg->id,
+ SCMI_VOLTAGE_ARCH_STATE_OFF);
}
static int scmi_reg_is_enabled(struct regulator_dev *rdev)
@@ -70,10 +71,8 @@ static int scmi_reg_is_enabled(struct regulator_dev *rdev)
int ret;
u32 config;
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
- ret = handle->voltage_ops->config_get(handle, sreg->id,
- &config);
+ ret = voltage_ops->config_get(sreg->ph, sreg->id, &config);
if (ret) {
dev_err(&sreg->sdev->dev,
"Error %d reading regulator %s status.\n",
@@ -89,9 +88,8 @@ static int scmi_reg_get_voltage_sel(struct regulator_dev *rdev)
int ret;
s32 volt_uV;
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
- ret = handle->voltage_ops->level_get(handle, sreg->id, &volt_uV);
+ ret = voltage_ops->level_get(sreg->ph, sreg->id, &volt_uV);
if (ret)
return ret;
@@ -103,13 +101,12 @@ static int scmi_reg_set_voltage_sel(struct regulator_dev *rdev,
{
s32 volt_uV;
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
volt_uV = sreg->desc.ops->list_voltage(rdev, selector);
if (volt_uV <= 0)
return -EINVAL;
- return handle->voltage_ops->level_set(handle, sreg->id, 0x0, volt_uV);
+ return voltage_ops->level_set(sreg->ph, sreg->id, 0x0, volt_uV);
}
static const struct regulator_ops scmi_reg_fixed_ops = {
@@ -204,11 +201,10 @@ scmi_config_discrete_regulator_mappings(struct scmi_regulator *sreg,
static int scmi_regulator_common_init(struct scmi_regulator *sreg)
{
int ret;
- const struct scmi_handle *handle = sreg->sdev->handle;
struct device *dev = &sreg->sdev->dev;
const struct scmi_voltage_info *vinfo;
- vinfo = handle->voltage_ops->info_get(handle, sreg->id);
+ vinfo = voltage_ops->info_get(sreg->ph, sreg->id);
if (!vinfo) {
dev_warn(dev, "Failure to get voltage domain %d\n",
sreg->id);
@@ -257,6 +253,7 @@ static int scmi_regulator_common_init(struct scmi_regulator *sreg)
}
static int process_scmi_regulator_of_node(struct scmi_device *sdev,
+ struct scmi_protocol_handle *ph,
struct device_node *np,
struct scmi_regulator_info *rinfo)
{
@@ -284,6 +281,7 @@ static int process_scmi_regulator_of_node(struct scmi_device *sdev,
rinfo->sregv[dom]->id = dom;
rinfo->sregv[dom]->sdev = sdev;
+ rinfo->sregv[dom]->ph = ph;
/* get hold of good nodes */
of_node_get(np);
@@ -302,11 +300,16 @@ static int scmi_regulator_probe(struct scmi_device *sdev)
struct device_node *np, *child;
const struct scmi_handle *handle = sdev->handle;
struct scmi_regulator_info *rinfo;
+ struct scmi_protocol_handle *ph;
- if (!handle || !handle->voltage_ops)
+ if (!handle)
return -ENODEV;
- num_doms = handle->voltage_ops->num_domains_get(handle);
+ voltage_ops = handle->devm_get_ops(sdev, SCMI_PROTOCOL_VOLTAGE, &ph);
+ if (IS_ERR(voltage_ops))
+ return PTR_ERR(voltage_ops);
+
+ num_doms = voltage_ops->num_domains_get(ph);
if (num_doms <= 0) {
if (!num_doms) {
dev_err(&sdev->dev,
@@ -341,7 +344,7 @@ static int scmi_regulator_probe(struct scmi_device *sdev)
*/
np = of_find_node_by_name(handle->dev->of_node, "regulators");
for_each_child_of_node(np, child) {
- ret = process_scmi_regulator_of_node(sdev, child, rinfo);
+ ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
/* abort on any mem issue */
if (ret == -ENOMEM)
return ret;
--
2.17.1
Add a new refactored protocol events registration helper and invoke it
from the centralized initialization process triggered by get_ops() and
friends.
Add a .get_num_sources as a new optional callback amongst protocol events
operations; finally remove events registration call-sites from within the
legacy protocol init routines.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/base.c | 15 +++---
drivers/firmware/arm_scmi/common.h | 2 +
drivers/firmware/arm_scmi/driver.c | 7 +++
drivers/firmware/arm_scmi/notify.c | 77 ++++++++++++++++++++---------
drivers/firmware/arm_scmi/notify.h | 33 +++++++++++--
drivers/firmware/arm_scmi/perf.c | 25 +++++++---
drivers/firmware/arm_scmi/power.c | 25 +++++++---
drivers/firmware/arm_scmi/reset.c | 25 +++++++---
drivers/firmware/arm_scmi/sensors.c | 22 ++++++---
drivers/firmware/arm_scmi/system.c | 16 +++---
10 files changed, 181 insertions(+), 66 deletions(-)
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index 1469bad34bc1..2fe76827e627 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -318,6 +318,14 @@ static const struct scmi_event_ops base_event_ops = {
.fill_custom_report = scmi_base_fill_custom_report,
};
+static const struct scmi_protocol_events base_protocol_events = {
+ .queue_sz = 4 * SCMI_PROTO_QUEUE_SZ,
+ .ops = &base_event_ops,
+ .evts = base_events,
+ .num_events = ARRAY_SIZE(base_events),
+ .num_sources = SCMI_BASE_NUM_SOURCES,
+};
+
int scmi_base_protocol_init(struct scmi_handle *h)
{
int id, ret;
@@ -352,12 +360,6 @@ int scmi_base_protocol_init(struct scmi_handle *h)
dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols,
rev->num_agents);
- scmi_register_protocol_events(handle, SCMI_PROTOCOL_BASE,
- (4 * SCMI_PROTO_QUEUE_SZ),
- &base_event_ops, base_events,
- ARRAY_SIZE(base_events),
- SCMI_BASE_NUM_SOURCES);
-
for (id = 0; id < rev->num_agents; id++) {
scmi_base_discover_agent_get(handle, id, name);
dev_dbg(dev, "Agent %d: %s\n", id, name);
@@ -370,6 +372,7 @@ static const struct scmi_protocol scmi_base = {
.id = SCMI_PROTOCOL_BASE,
.init = &scmi_base_protocol_init,
.ops = NULL,
+ .events = &base_protocol_events,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 977e31224efe..218a389f87b5 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -226,6 +226,7 @@ typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *);
* @deinit_instance: Optional protocol de-initialization function.
* @ops: Optional reference to the operations provided by the protocol and
* exposed in scmi_protocol.h.
+ * @events: An optional reference to the events supported by this protocol.
*/
struct scmi_protocol {
const u8 id;
@@ -233,6 +234,7 @@ struct scmi_protocol {
const scmi_prot_init_fn_t init_instance;
const scmi_prot_init_fn_t deinit_instance;
const void *ops;
+ const struct scmi_protocol_events *events;
};
int __init scmi_bus_init(void);
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index e6e760501587..2740c28928c7 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -645,6 +645,10 @@ scmi_get_protocol_instance(struct scmi_handle *handle, u8 protocol_id)
if (ret != protocol_id)
goto clean;
+ if (pi->proto->events)
+ scmi_register_protocol_events(handle, pi->proto->id,
+ pi->proto->events);
+
devres_close_group(handle->dev, pi->gid);
dev_dbg(handle->dev, "Initialized protocol: 0x%X\n",
protocol_id);
@@ -696,6 +700,9 @@ void scmi_release_protocol(struct scmi_handle *handle, u8 protocol_id)
if (refcount_dec_and_test(&pi->users)) {
void *gid = pi->gid;
+ if (pi->proto->events)
+ scmi_deregister_protocol_events(handle, protocol_id);
+
if (pi->proto->deinit_instance)
pi->proto->deinit_instance(handle);
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 70e8eb4e33c6..8b4af3847bfa 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -733,14 +733,9 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni,
/**
* scmi_register_protocol_events() - Register Protocol Events with the core
* @handle: The handle identifying the platform instance against which the
- * the protocol's events are registered
+ * protocol's events are registered
* @proto_id: Protocol ID
- * @queue_sz: Size in bytes of the associated queue to be allocated
- * @ops: Protocol specific event-related operations
- * @evt: Event descriptor array
- * @num_events: Number of events in @evt array
- * @num_sources: Number of possible sources for this protocol on this
- * platform.
+ * @ee: A structure describing the events supported by this protocol.
*
* Used by SCMI Protocols initialization code to register with the notification
* core the list of supported events and their descriptors: takes care to
@@ -749,18 +744,18 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni,
*
* Return: 0 on Success
*/
-int scmi_register_protocol_events(const struct scmi_handle *handle,
- u8 proto_id, size_t queue_sz,
- const struct scmi_event_ops *ops,
- const struct scmi_event *evt, int num_events,
- int num_sources)
+int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
+ const struct scmi_protocol_events *ee)
{
int i;
+ unsigned int num_sources;
size_t payld_sz = 0;
struct scmi_registered_events_desc *pd;
struct scmi_notify_instance *ni;
+ const struct scmi_event *evt;
- if (!ops || !evt)
+ if (!ee || !ee->ops || !ee->evts ||
+ (!ee->num_sources && !ee->ops->get_num_sources))
return -EINVAL;
/* Ensure notify_priv is updated */
@@ -769,20 +764,29 @@ int scmi_register_protocol_events(const struct scmi_handle *handle,
return -ENOMEM;
ni = handle->notify_priv;
- /* Attach to the notification main devres group */
- if (!devres_open_group(ni->handle->dev, ni->gid, GFP_KERNEL))
- return -ENOMEM;
+ /* num_sources cannot be <= 0 */
+ if (ee->num_sources) {
+ num_sources = ee->num_sources;
+ } else {
+ int nsrc = ee->ops->get_num_sources(handle);
+
+ if (nsrc <= 0)
+ return -EINVAL;
+ num_sources = nsrc;
+ }
- for (i = 0; i < num_events; i++)
+ evt = ee->evts;
+ for (i = 0; i < ee->num_events; i++)
payld_sz = max_t(size_t, payld_sz, evt[i].max_payld_sz);
payld_sz += sizeof(struct scmi_event_header);
- pd = scmi_allocate_registered_events_desc(ni, proto_id, queue_sz,
- payld_sz, num_events, ops);
+ pd = scmi_allocate_registered_events_desc(ni, proto_id, ee->queue_sz,
+ payld_sz, ee->num_events,
+ ee->ops);
if (IS_ERR(pd))
goto err;
- for (i = 0; i < num_events; i++, evt++) {
+ for (i = 0; i < ee->num_events; i++, evt++) {
struct scmi_registered_event *r_evt;
r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt),
@@ -816,8 +820,6 @@ int scmi_register_protocol_events(const struct scmi_handle *handle,
/* Ensure protocols are updated */
smp_wmb();
- devres_close_group(ni->handle->dev, ni->gid);
-
/*
* Finalize any pending events' handler which could have been waiting
* for this protocol's events registration.
@@ -828,12 +830,39 @@ int scmi_register_protocol_events(const struct scmi_handle *handle,
err:
dev_warn(handle->dev, "Proto:%X - Registration Failed !\n", proto_id);
- /* A failing protocol registration does not trigger full failure */
- devres_close_group(ni->handle->dev, ni->gid);
return -ENOMEM;
}
+/**
+ * scmi_deregister_protocol_events - Deregister protocol events with the core
+ * @handle: The handle identifying the platform instance against which the
+ * protocol's events are registered
+ * @proto_id: Protocol ID
+ */
+void scmi_deregister_protocol_events(const struct scmi_handle *handle,
+ u8 proto_id)
+{
+ struct scmi_notify_instance *ni;
+ struct scmi_registered_events_desc *pd;
+
+ /* Ensure notify_priv is updated */
+ smp_rmb();
+ if (!handle->notify_priv)
+ return;
+
+ ni = handle->notify_priv;
+ pd = ni->registered_protocols[proto_id];
+ if (!pd)
+ return;
+
+ ni->registered_protocols[proto_id] = NULL;
+ /* Ensure protocols are updated */
+ smp_wmb();
+
+ cancel_work_sync(&pd->equeue.notify_work);
+}
+
/**
* scmi_allocate_event_handler() - Allocate Event handler
* @ni: A reference to the notification instance to use
diff --git a/drivers/firmware/arm_scmi/notify.h b/drivers/firmware/arm_scmi/notify.h
index 3485f20fa70e..97ddfe55d773 100644
--- a/drivers/firmware/arm_scmi/notify.h
+++ b/drivers/firmware/arm_scmi/notify.h
@@ -31,8 +31,12 @@ struct scmi_event {
size_t max_report_sz;
};
+struct scmi_protocol_handle;
+
/**
* struct scmi_event_ops - Protocol helpers called by the notification core.
+ * @get_num_sources: Returns the number of possible events' sources for this
+ * protocol
* @set_notify_enabled: Enable/disable the required evt_id/src_id notifications
* using the proper custom protocol commands.
* Return 0 on Success
@@ -46,6 +50,7 @@ struct scmi_event {
* process context.
*/
struct scmi_event_ops {
+ int (*get_num_sources)(const struct scmi_handle *handle);
int (*set_notify_enabled)(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enabled);
void *(*fill_custom_report)(const struct scmi_handle *handle,
@@ -54,14 +59,32 @@ struct scmi_event_ops {
void *report, u32 *src_id);
};
+/**
+ * struct scmi_protocol_events - Per-protocol description of available events
+ * @queue_sz: Size in bytes of the per-protocol queue to use.
+ * @ops: Array of protocol-specific events operations.
+ * @evts: Array of supported protocol's events.
+ * @num_events: Number of supported protocol's events described in @evts.
+ * @num_sources: Number of protocol's sources, should be greater than 0; if not
+ * available at compile time, it will be provided at run-time via
+ * @get_num_sources.
+ */
+struct scmi_protocol_events {
+ size_t queue_sz;
+ const struct scmi_event_ops *ops;
+ const struct scmi_event *evts;
+ unsigned int num_events;
+ unsigned int num_sources;
+};
+
int scmi_notification_init(struct scmi_handle *handle);
void scmi_notification_exit(struct scmi_handle *handle);
-int scmi_register_protocol_events(const struct scmi_handle *handle,
- u8 proto_id, size_t queue_sz,
- const struct scmi_event_ops *ops,
- const struct scmi_event *evt, int num_events,
- int num_sources);
+struct scmi_protocol_handle;
+int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
+ const struct scmi_protocol_events *ee);
+void scmi_deregister_protocol_events(const struct scmi_handle *handle,
+ u8 proto_id);
int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id,
const void *buf, size_t len, ktime_t ts);
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index f2317e4c10de..b3160bd5ad0b 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -837,6 +837,16 @@ static void *scmi_perf_fill_custom_report(const struct scmi_handle *handle,
return rep;
}
+static int scmi_perf_get_num_sources(const struct scmi_handle *handle)
+{
+ struct scmi_perf_info *pi = handle->perf_priv;
+
+ if (!pi)
+ return -EINVAL;
+
+ return pi->num_domains;
+}
+
static const struct scmi_event perf_events[] = {
{
.id = SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED,
@@ -851,10 +861,18 @@ static const struct scmi_event perf_events[] = {
};
static const struct scmi_event_ops perf_event_ops = {
+ .get_num_sources = scmi_perf_get_num_sources,
.set_notify_enabled = scmi_perf_set_notify_enabled,
.fill_custom_report = scmi_perf_fill_custom_report,
};
+static const struct scmi_protocol_events perf_protocol_events = {
+ .queue_sz = SCMI_PROTO_QUEUE_SZ,
+ .ops = &perf_event_ops,
+ .evts = perf_events,
+ .num_events = ARRAY_SIZE(perf_events),
+};
+
static int scmi_perf_protocol_init(struct scmi_handle *handle)
{
int domain;
@@ -887,12 +905,6 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
scmi_perf_domain_init_fc(handle, domain, &dom->fc_info);
}
- scmi_register_protocol_events(handle,
- SCMI_PROTOCOL_PERF, SCMI_PROTO_QUEUE_SZ,
- &perf_event_ops, perf_events,
- ARRAY_SIZE(perf_events),
- pinfo->num_domains);
-
pinfo->version = version;
handle->perf_ops = &perf_ops;
handle->perf_priv = pinfo;
@@ -904,6 +916,7 @@ static const struct scmi_protocol scmi_perf = {
.id = SCMI_PROTOCOL_PERF,
.init = &scmi_perf_protocol_init,
.ops = &perf_ops,
+ .events = &perf_protocol_events,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index b620c5fec855..6db02dc547a7 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -246,6 +246,16 @@ static void *scmi_power_fill_custom_report(const struct scmi_handle *handle,
return r;
}
+static int scmi_power_get_num_sources(const struct scmi_handle *handle)
+{
+ struct scmi_power_info *pinfo = handle->power_priv;
+
+ if (!pinfo)
+ return -EINVAL;
+
+ return pinfo->num_domains;
+}
+
static const struct scmi_event power_events[] = {
{
.id = SCMI_EVENT_POWER_STATE_CHANGED,
@@ -256,10 +266,18 @@ static const struct scmi_event power_events[] = {
};
static const struct scmi_event_ops power_event_ops = {
+ .get_num_sources = scmi_power_get_num_sources,
.set_notify_enabled = scmi_power_set_notify_enabled,
.fill_custom_report = scmi_power_fill_custom_report,
};
+static const struct scmi_protocol_events power_protocol_events = {
+ .queue_sz = SCMI_PROTO_QUEUE_SZ,
+ .ops = &power_event_ops,
+ .evts = power_events,
+ .num_events = ARRAY_SIZE(power_events),
+};
+
static int scmi_power_protocol_init(struct scmi_handle *handle)
{
int domain;
@@ -288,12 +306,6 @@ static int scmi_power_protocol_init(struct scmi_handle *handle)
scmi_power_domain_attributes_get(handle, domain, dom);
}
- scmi_register_protocol_events(handle,
- SCMI_PROTOCOL_POWER, SCMI_PROTO_QUEUE_SZ,
- &power_event_ops, power_events,
- ARRAY_SIZE(power_events),
- pinfo->num_domains);
-
pinfo->version = version;
handle->power_ops = &power_ops;
handle->power_priv = pinfo;
@@ -305,6 +317,7 @@ static const struct scmi_protocol scmi_power = {
.id = SCMI_PROTOCOL_POWER,
.init = &scmi_power_protocol_init,
.ops = &power_ops,
+ .events = &power_protocol_events,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(power, scmi_power)
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index 3283dde30641..7102cfeb2397 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -257,6 +257,16 @@ static void *scmi_reset_fill_custom_report(const struct scmi_handle *handle,
return r;
}
+static int scmi_reset_get_num_sources(const struct scmi_handle *handle)
+{
+ struct scmi_reset_info *pinfo = handle->reset_priv;
+
+ if (!pinfo)
+ return -EINVAL;
+
+ return pinfo->num_domains;
+}
+
static const struct scmi_event reset_events[] = {
{
.id = SCMI_EVENT_RESET_ISSUED,
@@ -266,10 +276,18 @@ static const struct scmi_event reset_events[] = {
};
static const struct scmi_event_ops reset_event_ops = {
+ .get_num_sources = scmi_reset_get_num_sources,
.set_notify_enabled = scmi_reset_set_notify_enabled,
.fill_custom_report = scmi_reset_fill_custom_report,
};
+static const struct scmi_protocol_events reset_protocol_events = {
+ .queue_sz = SCMI_PROTO_QUEUE_SZ,
+ .ops = &reset_event_ops,
+ .evts = reset_events,
+ .num_events = ARRAY_SIZE(reset_events),
+};
+
static int scmi_reset_protocol_init(struct scmi_handle *handle)
{
int domain;
@@ -298,12 +316,6 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle)
scmi_reset_domain_attributes_get(handle, domain, dom);
}
- scmi_register_protocol_events(handle,
- SCMI_PROTOCOL_RESET, SCMI_PROTO_QUEUE_SZ,
- &reset_event_ops, reset_events,
- ARRAY_SIZE(reset_events),
- pinfo->num_domains);
-
pinfo->version = version;
handle->reset_ops = &reset_ops;
handle->reset_priv = pinfo;
@@ -315,6 +327,7 @@ static const struct scmi_protocol scmi_reset = {
.id = SCMI_PROTOCOL_RESET,
.init = &scmi_reset_protocol_init,
.ops = &reset_ops,
+ .events = &reset_protocol_events,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset)
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index c80d492b068a..526e2236929c 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -920,6 +920,13 @@ static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle,
return rep;
}
+static int scmi_sensor_get_num_sources(const struct scmi_handle *handle)
+{
+ struct sensors_info *si = handle->sensor_priv;
+
+ return si->num_sensors;
+}
+
static const struct scmi_event sensor_events[] = {
{
.id = SCMI_EVENT_SENSOR_TRIP_POINT_EVENT,
@@ -939,10 +946,18 @@ static const struct scmi_event sensor_events[] = {
};
static const struct scmi_event_ops sensor_event_ops = {
+ .get_num_sources = scmi_sensor_get_num_sources,
.set_notify_enabled = scmi_sensor_set_notify_enabled,
.fill_custom_report = scmi_sensor_fill_custom_report,
};
+static const struct scmi_protocol_events sensor_protocol_events = {
+ .queue_sz = SCMI_PROTO_QUEUE_SZ,
+ .ops = &sensor_event_ops,
+ .evts = sensor_events,
+ .num_events = ARRAY_SIZE(sensor_events),
+};
+
static int scmi_sensors_protocol_init(struct scmi_handle *handle)
{
u32 version;
@@ -971,12 +986,6 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
if (ret)
return ret;
- scmi_register_protocol_events(handle,
- SCMI_PROTOCOL_SENSOR, SCMI_PROTO_QUEUE_SZ,
- &sensor_event_ops, sensor_events,
- ARRAY_SIZE(sensor_events),
- sinfo->num_sensors);
-
handle->sensor_priv = sinfo;
handle->sensor_ops = &sensor_ops;
@@ -987,6 +996,7 @@ static const struct scmi_protocol scmi_sensors = {
.id = SCMI_PROTOCOL_SENSOR,
.init = &scmi_sensors_protocol_init,
.ops = &sensor_ops,
+ .events = &sensor_protocol_events,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors)
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
index 94a68bfc79d6..167f539f7d95 100644
--- a/drivers/firmware/arm_scmi/system.c
+++ b/drivers/firmware/arm_scmi/system.c
@@ -101,6 +101,14 @@ static const struct scmi_event_ops system_event_ops = {
.fill_custom_report = scmi_system_fill_custom_report,
};
+static const struct scmi_protocol_events system_protocol_events = {
+ .queue_sz = SCMI_PROTO_QUEUE_SZ,
+ .ops = &system_event_ops,
+ .evts = system_events,
+ .num_events = ARRAY_SIZE(system_events),
+ .num_sources = SCMI_SYSTEM_NUM_SOURCES,
+};
+
static int scmi_system_protocol_init(struct scmi_handle *handle)
{
u32 version;
@@ -115,13 +123,6 @@ static int scmi_system_protocol_init(struct scmi_handle *handle)
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;
@@ -132,6 +133,7 @@ static const struct scmi_protocol scmi_system = {
.id = SCMI_PROTOCOL_SYSTEM,
.init = &scmi_system_protocol_init,
.ops = NULL,
+ .events = &system_protocol_events,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system)
--
2.17.1
Account for any active registered notifier against the proper related
protocol; do not consider pending event handlers, only active handlers
will concur to protocol usage accounting.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/notify.c | 51 ++++++++++++++++++++++++++----
1 file changed, 44 insertions(+), 7 deletions(-)
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 66196b293b6c..cdaf0f962d84 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -91,6 +91,7 @@
#include <linux/types.h>
#include <linux/workqueue.h>
+#include "common.h"
#include "notify.h"
#define SCMI_MAX_PROTO 256
@@ -368,7 +369,7 @@ static struct scmi_event_handler *
scmi_get_active_handler(struct scmi_notify_instance *ni, u32 evt_key);
static void scmi_put_active_handler(struct scmi_notify_instance *ni,
struct scmi_event_handler *hndl);
-static void scmi_put_handler_unlocked(struct scmi_notify_instance *ni,
+static bool scmi_put_handler_unlocked(struct scmi_notify_instance *ni,
struct scmi_event_handler *hndl);
/**
@@ -900,9 +901,21 @@ static inline int scmi_bind_event_handler(struct scmi_notify_instance *ni,
if (!r_evt)
return -EINVAL;
- /* Remove from pending and insert into registered */
+ /*
+ * Remove from pending and insert into registered while getting hold
+ * of protocol instance.
+ */
hash_del(&hndl->hash);
+ /*
+ * Acquire protocols only for NON pending handlers, so as NOT to trigger
+ * protocol initialization when a notifier is registered against a still
+ * not registered protocol, since it would make little sense to force init
+ * protocols for which still no SCMI driver user exists: they wouldn't
+ * emit any event anyway till some SCMI driver starts using it.
+ */
+ scmi_acquire_protocol(ni->handle, KEY_XTRACT_PROTO_ID(hndl->key));
hndl->r_evt = r_evt;
+
mutex_lock(&r_evt->proto->registered_mtx);
hash_add(r_evt->proto->registered_events_handlers,
&hndl->hash, hndl->key);
@@ -1193,41 +1206,65 @@ static int scmi_disable_events(struct scmi_event_handler *hndl)
* * unregister and free the handler itself
*
* Context: Assumes all the proper locking has been managed by the caller.
+ *
+ * Return: True if handler was freed (users dropped to zero)
*/
-static void scmi_put_handler_unlocked(struct scmi_notify_instance *ni,
+static bool scmi_put_handler_unlocked(struct scmi_notify_instance *ni,
struct scmi_event_handler *hndl)
{
+ bool freed = false;
+
if (refcount_dec_and_test(&hndl->users)) {
if (!IS_HNDL_PENDING(hndl))
scmi_disable_events(hndl);
scmi_free_event_handler(hndl);
+ freed = true;
}
+
+ return freed;
}
static void scmi_put_handler(struct scmi_notify_instance *ni,
struct scmi_event_handler *hndl)
{
+ bool freed;
+ u8 protocol_id;
struct scmi_registered_event *r_evt = hndl->r_evt;
mutex_lock(&ni->pending_mtx);
- if (r_evt)
+ if (r_evt) {
+ protocol_id = r_evt->proto->id;
mutex_lock(&r_evt->proto->registered_mtx);
+ }
- scmi_put_handler_unlocked(ni, hndl);
+ freed = scmi_put_handler_unlocked(ni, hndl);
- if (r_evt)
+ if (r_evt) {
mutex_unlock(&r_evt->proto->registered_mtx);
+ /*
+ * Only registered handler acquired protocol; must be here
+ * released only AFTER unlocking registered_mtx, since
+ * releasing a protocol can trigger its de-initialization
+ * (ie. including r_evt and registered_mtx)
+ */
+ if (freed)
+ scmi_release_protocol(ni->handle, protocol_id);
+ }
mutex_unlock(&ni->pending_mtx);
}
static void scmi_put_active_handler(struct scmi_notify_instance *ni,
struct scmi_event_handler *hndl)
{
+ bool freed;
struct scmi_registered_event *r_evt = hndl->r_evt;
+ u8 protocol_id = r_evt->proto->id;
mutex_lock(&r_evt->proto->registered_mtx);
- scmi_put_handler_unlocked(ni, hndl);
+ freed = scmi_put_handler_unlocked(ni, hndl);
mutex_unlock(&r_evt->proto->registered_mtx);
+ if (freed)
+ scmi_release_protocol(ni->handle, protocol_id);
}
/**
--
2.17.1
Now that all the SCMI driver users have been migrated to the new interface
remove the legacy interface and all the transient code.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/voltage.c | 67 -----------------------------
include/linux/scmi_protocol.h | 16 -------
2 files changed, 83 deletions(-)
diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c
index 7b390426028e..3a0cd5a531f1 100644
--- a/drivers/firmware/arm_scmi/voltage.c
+++ b/drivers/firmware/arm_scmi/voltage.c
@@ -262,15 +262,6 @@ static int scmi_voltage_config_set(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_voltage_config_set(const struct scmi_handle *handle,
- u32 domain_id, u32 config)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
-
- return scmi_voltage_config_set(ph, domain_id, config);
-}
-
static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph,
u32 domain_id, u32 *config)
{
@@ -278,15 +269,6 @@ static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph,
domain_id, config);
}
-static int __scmi_voltage_config_get(const struct scmi_handle *handle,
- u32 domain_id, u32 *config)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
-
- return scmi_voltage_config_get(ph, domain_id, config);
-}
-
static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
u32 domain_id, u32 flags, s32 volt_uV)
{
@@ -314,15 +296,6 @@ static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
return ret;
}
-static int __scmi_voltage_level_set(const struct scmi_handle *handle,
- u32 domain_id, u32 flags, s32 volt_uV)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
-
- return scmi_voltage_level_set(ph, domain_id, flags, volt_uV);
-}
-
static int scmi_voltage_level_get(const struct scmi_protocol_handle *ph,
u32 domain_id, s32 *volt_uV)
{
@@ -330,15 +303,6 @@ static int scmi_voltage_level_get(const struct scmi_protocol_handle *ph,
domain_id, (u32 *)volt_uV);
}
-static int __scmi_voltage_level_get(const struct scmi_handle *handle,
- u32 domain_id, s32 *volt_uV)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
-
- return scmi_voltage_level_get(ph, domain_id, volt_uV);
-}
-
static const struct scmi_voltage_info * __must_check
scmi_voltage_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
{
@@ -351,15 +315,6 @@ scmi_voltage_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
return vinfo->domains + domain_id;
}
-static const struct scmi_voltage_info * __must_check
-__scmi_voltage_info_get(const struct scmi_handle *handle, u32 domain_id)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
-
- return scmi_voltage_info_get(ph, domain_id);
-}
-
static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle *ph)
{
struct voltage_info *vinfo = ph->get_priv(ph);
@@ -367,23 +322,6 @@ static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle *ph)
return vinfo->num_domains;
}
-static int __scmi_voltage_domains_num_get(const struct scmi_handle *handle)
-{
- const struct scmi_protocol_handle *ph =
- scmi_map_protocol_handle(handle, SCMI_PROTOCOL_VOLTAGE);
-
- return scmi_voltage_domains_num_get(ph);
-}
-
-static struct scmi_voltage_ops voltage_ops = {
- .num_domains_get = __scmi_voltage_domains_num_get,
- .info_get = __scmi_voltage_info_get,
- .config_set = __scmi_voltage_config_set,
- .config_get = __scmi_voltage_config_get,
- .level_set = __scmi_voltage_level_set,
- .level_get = __scmi_voltage_level_get,
-};
-
static struct scmi_voltage_proto_ops voltage_proto_ops = {
.num_domains_get = scmi_voltage_domains_num_get,
.info_get = scmi_voltage_info_get,
@@ -398,7 +336,6 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
int ret;
u32 version;
struct voltage_info *vinfo;
- struct scmi_handle *handle;
ret = ph->xops->version_get(ph, &version);
if (ret)
@@ -429,10 +366,6 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
dev_warn(ph->dev, "No Voltage domains found.\n");
}
- /* Transient code for legacy ops interface */
- handle = scmi_map_scmi_handle(ph);
- handle->voltage_ops = &voltage_ops;
-
return ph->set_priv(ph, vinfo);
}
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index a36f3fa33a5f..c16455cff6a9 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -541,20 +541,6 @@ struct scmi_voltage_proto_ops {
s32 *volt_uV);
};
-struct scmi_voltage_ops {
- int (*num_domains_get)(const struct scmi_handle *handle);
- const struct scmi_voltage_info __must_check *(*info_get)
- (const struct scmi_handle *handle, u32 domain_id);
- int (*config_set)(const struct scmi_handle *handle, u32 domain_id,
- u32 config);
- int (*config_get)(const struct scmi_handle *handle, u32 domain_id,
- u32 *config);
- int (*level_set)(const struct scmi_handle *handle, u32 domain_id,
- u32 flags, s32 volt_uV);
- int (*level_get)(const struct scmi_handle *handle, u32 domain_id,
- s32 *volt_uV);
-};
-
/**
* struct scmi_notify_ops - represents notifications' operations provided by
* SCMI core
@@ -616,7 +602,6 @@ struct scmi_notify_ops {
*
* @dev: pointer to the SCMI device
* @version: pointer to the structure containing SCMI version information
- * @voltage_ops: pointer to set of voltage protocol operations
* @devm_get_ops: devres managed method to acquire a protocol and get specific
* operations and a dedicated protocol handler
* @devm_put_ops: devres managed method to release a protocol
@@ -630,7 +615,6 @@ struct scmi_notify_ops {
struct scmi_handle {
struct device *dev;
struct scmi_revision_info *version;
- const struct scmi_voltage_ops *voltage_ops;
const void __must_check *
(*devm_get_ops)(struct scmi_device *sdev, u8 proto,
--
2.17.1
Add an helper to grab, from a protocol handle, the handle common memory
area allocated to store SCMI version data which is exposed on sysfs.
Such helper will be needed by SCMI Base protocol initialization once it
will be moved to new protocol handles scheme.
Signed-off-by: Cristian Marussi <[email protected]>
---
drivers/firmware/arm_scmi/common.h | 2 ++
drivers/firmware/arm_scmi/driver.c | 19 +++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 10ac5a6daf10..428bfba40dfd 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -215,6 +215,8 @@ struct scmi_xfer_ops {
struct scmi_xfer *xfer);
};
+struct scmi_revision_info *
+scmi_get_revision_area(const struct scmi_protocol_handle *ph);
int scmi_handle_put(const struct scmi_handle *handle);
struct scmi_handle *scmi_handle_get(struct device *dev);
void scmi_set_handle(struct scmi_device *scmi_dev);
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index d1357640bf07..b936cf47cd7d 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -698,6 +698,25 @@ static const struct scmi_xfer_ops xfer_ops = {
.xfer_put = xfer_put,
};
+/**
+ * scmi_get_revision_area - Retrieve version memory area.
+ *
+ * @ph: A reference to the protocol handle.
+ *
+ * A helper to grab the version memory area reference during SCMI Base protocol
+ * initialization.
+ *
+ * Return: A reference to the version memory area associated to the SCMI
+ * instance underlying this protocol handle.
+ */
+struct scmi_revision_info *
+scmi_get_revision_area(const struct scmi_protocol_handle *ph)
+{
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+
+ return pi->handle->version;
+}
+
/**
* scmi_get_protocol_instance - Protocol initialization helper.
* @handle: A reference to the SCMI platform instance.
--
2.17.1
Hi Christian,
On 1/6/21 3:16 PM, Cristian Marussi wrote:
> Having added the support for SCMI protocols as modules in order to let
> vendors extend the SCMI core with their own additions it seems odd to
> then force SCMI drivers built on top to use a static device table to
> declare their devices since this way any new SCMI drivers addition
> would need the core SCMI device table to be updated too.
>
> Remove the static core device table and let SCMI drivers to simply declare
> which device/protocol pair they need at initialization time: the core will
> then take care to generate such devices dynamically during platform
> initialization or at module loading time, as long as the requested
> underlying protocol is defined in the DT.
>
> Signed-off-by: Cristian Marussi <[email protected]>
> ---
[snip]
>
> -static inline void
> -scmi_create_protocol_devices(struct device_node *np, struct scmi_info *info,
> - int prot_id)
> + for (; rdev; rdev = rdev->next)
> + scmi_create_protocol_device(np, info, prot_id,
> + rdev->id_table->name);
> +}
> +
> +/**
> + * scmi_request_protocol_device - Helper to request a device
> + *
> + * @id_table: A protocol/name pair descriptor for the device to be created.
> + *
> + * This helper let an SCMI driver request specific devices identified by the
> + * @id_table to be created for each active SCMI instance.
> + *
> + * The requested device name MUST NOT be already existent for any protocol;
> + * at first the freshly requested @id_table is annotated in the IDR table
> + * @scmi_requested_devices, then a matching device is created for each already
> + * active SCMI instance. (if any)
> + *
> + * This way the requested device is created straight-away for all the already
> + * initialized(probed) SCMI instances (handles) but it remains instead pending
> + * for creation if the requesting SCMI driver is loaded before some instance
> + * and related transports was available: when such late SCMI instance is probed
> + * it will take care to scan the list of pending requested devices and create
> + * those on its own (see @scmi_create_protocol_devices and its enclosing loop)
> + *
> + * Return: 0 on Success
> + */
> +int scmi_request_protocol_device(const struct scmi_device_id *id_table)
> {
> - int loop, cnt;
> + int ret = 0;
> + unsigned int id = 0;
> + struct scmi_requested_dev *rdev, *proto_rdev = NULL;
> + struct scmi_info *info;
>
> - for (loop = 0; loop < ARRAY_SIZE(devnames); loop++) {
> - if (devnames[loop].protocol_id != prot_id)
> - continue;
> + pr_debug("Requesting SCMI device (%s) for protocol %x\n",
> + id_table->name, id_table->protocol_id);
>
> - for (cnt = 0; cnt < ARRAY_SIZE(devnames[loop].names); cnt++) {
> - const char *name = devnames[loop].names[cnt];
> + /*
> + * Search for the matching protocol rdev list and then search
> + * of any existent equally named device...fails if any duplicate found.
> + */
> + mutex_lock(&scmi_requested_devices_mutex);
> + idr_for_each_entry(&scmi_requested_devices, rdev, id) {
> + if (rdev->id_table->protocol_id == id_table->protocol_id)
> + proto_rdev = rdev;
> + for (; rdev; rdev = rdev->next) {
> + if (!strcmp(rdev->id_table->name, id_table->name)) {
> + pr_err("Ignoring duplicate request [%d] %s\n",
> + rdev->id_table->protocol_id,
> + rdev->id_table->name);
> + ret = -EINVAL;
> + goto out;
> + }
Shouldn't there be proto_rdev = rdev here as well ?
> + }
> + }
> +
> + /*
> + * No duplicate found for requested id_table, so let's create a new
> + * requested device entry for this new valid request.
> + */
> + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
> + if (!rdev) {
> + ret = -ENOMEM;
> + goto out;
> + }
> + rdev->id_table = id_table;
> +
> + /*
> + * Append the new requested device table descriptor to the head of the
> + * related protocol chain, eventually creating such chain if not already
> + * there.
> + */
> + if (!proto_rdev) {
> + ret = idr_alloc(&scmi_requested_devices, (void *)rdev,
> + rdev->id_table->protocol_id,
> + rdev->id_table->protocol_id + 1, GFP_KERNEL);
> + if (ret != rdev->id_table->protocol_id) {
> + pr_err("Failed to save SCMI device - ret:%d\n", ret);
> + kfree(rdev);
> + ret = -EINVAL;
> + goto out;
> + }
> + ret = 0;
> + } else {
> + proto_rdev->next = rdev;
> + }
> +
> + /*
> + * Now effectively create and initialize the requested device for every
> + * already initialized SCMI instance which has registered the requested
> + * protocol as a valid active one: i.e. defined in DT and supported by
> + * current platform FW.
> + */
> + mutex_lock(&scmi_list_mutex);
> + list_for_each_entry(info, &scmi_list, node) {
> + struct device_node *child;
> +
> + child = idr_find(&info->active_protocols,
> + id_table->protocol_id);
> + if (child) {
> + struct scmi_device *sdev;
> +
> + sdev = scmi_get_protocol_device(child, info,
> + id_table->protocol_id,
> + id_table->name);
> + /* Set handle if not already set (device existed) */
> + if (sdev && !sdev->handle)
> + sdev->handle = scmi_handle_get_from_info(info);
> + } else {
> + dev_err(info->dev,
> + "Failed. SCMI protocol %d not active.\n",
> + id_table->protocol_id);
> + }
> + }
> + mutex_unlock(&scmi_list_mutex);
> +
> +out:
> + mutex_unlock(&scmi_requested_devices_mutex);
> +
> + return ret;
> +}
> +
> +/**
> + * scmi_unrequest_protocol_device - Helper to unrequest a device
> + *
> + * @id_table: A protocol/name pair descriptor for the device to be unrequested.
> + *
> + * An helper to let an SCMI driver release its request about devices; note that
> + * devices are created and initialized once the first SCMI driver request them
> + * but they destroyed only on SCMI core unloading/unbinding.
> + *
> + * The current SCMI transport layer uses such devices as internal references and
> + * as such they could be shared as same transport between multiple drivers so
> + * that cannot be safely destroyed till the whole SCMI stack is removed.
> + * (unless adding further burden of refcounting.)
> + */
> +void scmi_unrequest_protocol_device(const struct scmi_device_id *id_table)
> +{
> + struct scmi_requested_dev *victim, *prev, *head;
> +
> + pr_debug("Unrequesting SCMI device (%s) for protocol %x\n",
> + id_table->name, id_table->protocol_id);
>
> - if (name)
> - scmi_create_protocol_device(np, info, prot_id,
> - name);
> + head = idr_find(&scmi_requested_devices, id_table->protocol_id);
> + if (!head)
> + return;
> +
> + /*
> + * Scan the protocol list of requested device name searching
> + * for the victim.
> + */
> + victim = head;
> + for (prev = victim; victim; prev = victim, victim = victim->next)
The initial assignment for the for loop is wrong. With this when you
break prev will be equal to victim. You want prev to be the one pointing
to the victim. Or am I missing something?
--
Warm Regards
Thara
On 1/6/21 3:15 PM, Cristian Marussi wrote:
> Expose to the SCMI drivers a non managed version of a common protocols API
> based on generic get/put methods and protocol handles.
>
> All drivers still keep using the old API, no functional change.
>
> Signed-off-by: Cristian Marussi <[email protected]>
> ---
> These non devres methods are probably not needed, given the devm_ ones are
> already provided and any SCMI driver (user of the API) has surely available
> an scmi_device reference to use in the devm_ flavour...so the RFC
I agree. The protocol devices can use the devm_ flavor.
--
Warm Regards
Thara
On Thu, Jan 07, 2021 at 09:28:07AM -0500, Thara Gopinath wrote:
> Hi Christian,
>
> On 1/6/21 3:16 PM, Cristian Marussi wrote:
> > Having added the support for SCMI protocols as modules in order to let
> > vendors extend the SCMI core with their own additions it seems odd to
> > then force SCMI drivers built on top to use a static device table to
> > declare their devices since this way any new SCMI drivers addition
> > would need the core SCMI device table to be updated too.
> >
> > Remove the static core device table and let SCMI drivers to simply declare
> > which device/protocol pair they need at initialization time: the core will
> > then take care to generate such devices dynamically during platform
> > initialization or at module loading time, as long as the requested
> > underlying protocol is defined in the DT.
> >
> > Signed-off-by: Cristian Marussi <[email protected]>
> > ---
>
> [snip]
>
> > -static inline void
> > -scmi_create_protocol_devices(struct device_node *np, struct scmi_info *info,
> > - int prot_id)
> > + for (; rdev; rdev = rdev->next)
> > + scmi_create_protocol_device(np, info, prot_id,
> > + rdev->id_table->name);
> > +}
> > +
> > +/**
> > + * scmi_request_protocol_device - Helper to request a device
> > + *
> > + * @id_table: A protocol/name pair descriptor for the device to be created.
> > + *
> > + * This helper let an SCMI driver request specific devices identified by the
> > + * @id_table to be created for each active SCMI instance.
> > + *
> > + * The requested device name MUST NOT be already existent for any protocol;
> > + * at first the freshly requested @id_table is annotated in the IDR table
> > + * @scmi_requested_devices, then a matching device is created for each already
> > + * active SCMI instance. (if any)
> > + *
> > + * This way the requested device is created straight-away for all the already
> > + * initialized(probed) SCMI instances (handles) but it remains instead pending
> > + * for creation if the requesting SCMI driver is loaded before some instance
> > + * and related transports was available: when such late SCMI instance is probed
> > + * it will take care to scan the list of pending requested devices and create
> > + * those on its own (see @scmi_create_protocol_devices and its enclosing loop)
> > + *
> > + * Return: 0 on Success
> > + */
> > +int scmi_request_protocol_device(const struct scmi_device_id *id_table)
> > {
> > - int loop, cnt;
> > + int ret = 0;
> > + unsigned int id = 0;
> > + struct scmi_requested_dev *rdev, *proto_rdev = NULL;
> > + struct scmi_info *info;
> > - for (loop = 0; loop < ARRAY_SIZE(devnames); loop++) {
> > - if (devnames[loop].protocol_id != prot_id)
> > - continue;
> > + pr_debug("Requesting SCMI device (%s) for protocol %x\n",
> > + id_table->name, id_table->protocol_id);
> > - for (cnt = 0; cnt < ARRAY_SIZE(devnames[loop].names); cnt++) {
> > - const char *name = devnames[loop].names[cnt];
> > + /*
> > + * Search for the matching protocol rdev list and then search
> > + * of any existent equally named device...fails if any duplicate found.
> > + */
> > + mutex_lock(&scmi_requested_devices_mutex);
> > + idr_for_each_entry(&scmi_requested_devices, rdev, id) {
> > + if (rdev->id_table->protocol_id == id_table->protocol_id)
> > + proto_rdev = rdev;
> > + for (; rdev; rdev = rdev->next) {
> > + if (!strcmp(rdev->id_table->name, id_table->name)) {
> > + pr_err("Ignoring duplicate request [%d] %s\n",
> > + rdev->id_table->protocol_id,
> > + rdev->id_table->name);
> > + ret = -EINVAL;
> > + goto out;
> > + }
> Shouldn't there be proto_rdev = rdev here as well ?
>
No, because each IDR entry points to one or more linked rdev descriptors
for the same protocol: while scanning each list in the IDR table I'm
searching for the proto_rdev representing the head of that protocol list
(if any already exist) and also scan all the lists fully to check for
duplicates, in such a case we give up.
The IDR map containing list resembles a lot a Linux hash implementation
but I decided not to use it because it seemed cumbersome to use an
hash given most of the time each IDR entry will contain just one single
element and this lookup happens really very infrequently (just at driver
loading time)
> > + }
> > + }
> > +
> > + /*
> > + * No duplicate found for requested id_table, so let's create a new
> > + * requested device entry for this new valid request.
> > + */
> > + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
> > + if (!rdev) {
> > + ret = -ENOMEM;
> > + goto out;
> > + }
> > + rdev->id_table = id_table;
> > +
> > + /*
> > + * Append the new requested device table descriptor to the head of the
> > + * related protocol chain, eventually creating such chain if not already
> > + * there.
> > + */
> > + if (!proto_rdev) {
> > + ret = idr_alloc(&scmi_requested_devices, (void *)rdev,
> > + rdev->id_table->protocol_id,
> > + rdev->id_table->protocol_id + 1, GFP_KERNEL);
> > + if (ret != rdev->id_table->protocol_id) {
> > + pr_err("Failed to save SCMI device - ret:%d\n", ret);
> > + kfree(rdev);
> > + ret = -EINVAL;
> > + goto out;
> > + }
> > + ret = 0;
> > + } else {
> > + proto_rdev->next = rdev;
> > + }
> > +
> > + /*
> > + * Now effectively create and initialize the requested device for every
> > + * already initialized SCMI instance which has registered the requested
> > + * protocol as a valid active one: i.e. defined in DT and supported by
> > + * current platform FW.
> > + */
> > + mutex_lock(&scmi_list_mutex);
> > + list_for_each_entry(info, &scmi_list, node) {
> > + struct device_node *child;
> > +
> > + child = idr_find(&info->active_protocols,
> > + id_table->protocol_id);
> > + if (child) {
> > + struct scmi_device *sdev;
> > +
> > + sdev = scmi_get_protocol_device(child, info,
> > + id_table->protocol_id,
> > + id_table->name);
> > + /* Set handle if not already set (device existed) */
> > + if (sdev && !sdev->handle)
> > + sdev->handle = scmi_handle_get_from_info(info);
> > + } else {
> > + dev_err(info->dev,
> > + "Failed. SCMI protocol %d not active.\n",
> > + id_table->protocol_id);
> > + }
> > + }
> > + mutex_unlock(&scmi_list_mutex);
> > +
> > +out:
> > + mutex_unlock(&scmi_requested_devices_mutex);
> > +
> > + return ret;
> > +}
> > +
> > +/**
> > + * scmi_unrequest_protocol_device - Helper to unrequest a device
> > + *
> > + * @id_table: A protocol/name pair descriptor for the device to be unrequested.
> > + *
> > + * An helper to let an SCMI driver release its request about devices; note that
> > + * devices are created and initialized once the first SCMI driver request them
> > + * but they destroyed only on SCMI core unloading/unbinding.
> > + *
> > + * The current SCMI transport layer uses such devices as internal references and
> > + * as such they could be shared as same transport between multiple drivers so
> > + * that cannot be safely destroyed till the whole SCMI stack is removed.
> > + * (unless adding further burden of refcounting.)
> > + */
> > +void scmi_unrequest_protocol_device(const struct scmi_device_id *id_table)
> > +{
> > + struct scmi_requested_dev *victim, *prev, *head;
> > +
> > + pr_debug("Unrequesting SCMI device (%s) for protocol %x\n",
> > + id_table->name, id_table->protocol_id);
> > - if (name)
> > - scmi_create_protocol_device(np, info, prot_id,
> > - name);
> > + head = idr_find(&scmi_requested_devices, id_table->protocol_id);
> > + if (!head)
> > + return;
> > +
> > + /*
> > + * Scan the protocol list of requested device name searching
> > + * for the victim.
> > + */
> > + victim = head;
> > + for (prev = victim; victim; prev = victim, victim = victim->next)
>
> The initial assignment for the for loop is wrong. With this when you break
> prev will be equal to victim. You want prev to be the one pointing to the
> victim. Or am I missing something?
>
Yes prev is the one preceding the victim, if any, but if it was the head
I'll remove the head and not use at all the prev really.
I think is right as it is, it is the naming that is misleading, because
yes in the initial assignment prev = victim BUT victim = head, so if I bail
out immediately I'm really removing the head.
It would be clearer like
prev = victim = head;
for (; victim; prev = victim, victim = victim->next)
...
But it's better that I review this whole loop in deep to simplify it; I
avoided using klist because seemed easier enough to handle a singly
linked list which most of the time is one element deep, buut maybe I
should just stick with well known and proven kists.
Thanks
Cristian
>
> --
> Warm Regards
> Thara
On 1/8/21 9:42 AM, Cristian Marussi wrote:
> On Thu, Jan 07, 2021 at 09:28:07AM -0500, Thara Gopinath wrote:
>> Hi Christian,
>>
>> On 1/6/21 3:16 PM, Cristian Marussi wrote:
>>> Having added the support for SCMI protocols as modules in order to let
>>> vendors extend the SCMI core with their own additions it seems odd to
>>> then force SCMI drivers built on top to use a static device table to
>>> declare their devices since this way any new SCMI drivers addition
>>> would need the core SCMI device table to be updated too.
>>>
>>> Remove the static core device table and let SCMI drivers to simply declare
>>> which device/protocol pair they need at initialization time: the core will
>>> then take care to generate such devices dynamically during platform
>>> initialization or at module loading time, as long as the requested
>>> underlying protocol is defined in the DT.
>>>
>>> Signed-off-by: Cristian Marussi <[email protected]>
>>> ---
>>
>> [snip]
>>
>>> -static inline void
>>> -scmi_create_protocol_devices(struct device_node *np, struct scmi_info *info,
>>> - int prot_id)
>>> + for (; rdev; rdev = rdev->next)
>>> + scmi_create_protocol_device(np, info, prot_id,
>>> + rdev->id_table->name);
>>> +}
>>> +
>>> +/**
>>> + * scmi_request_protocol_device - Helper to request a device
>>> + *
>>> + * @id_table: A protocol/name pair descriptor for the device to be created.
>>> + *
>>> + * This helper let an SCMI driver request specific devices identified by the
>>> + * @id_table to be created for each active SCMI instance.
>>> + *
>>> + * The requested device name MUST NOT be already existent for any protocol;
>>> + * at first the freshly requested @id_table is annotated in the IDR table
>>> + * @scmi_requested_devices, then a matching device is created for each already
>>> + * active SCMI instance. (if any)
>>> + *
>>> + * This way the requested device is created straight-away for all the already
>>> + * initialized(probed) SCMI instances (handles) but it remains instead pending
>>> + * for creation if the requesting SCMI driver is loaded before some instance
>>> + * and related transports was available: when such late SCMI instance is probed
>>> + * it will take care to scan the list of pending requested devices and create
>>> + * those on its own (see @scmi_create_protocol_devices and its enclosing loop)
>>> + *
>>> + * Return: 0 on Success
>>> + */
>>> +int scmi_request_protocol_device(const struct scmi_device_id *id_table)
>>> {
>>> - int loop, cnt;
>>> + int ret = 0;
>>> + unsigned int id = 0;
>>> + struct scmi_requested_dev *rdev, *proto_rdev = NULL;
>>> + struct scmi_info *info;
>>> - for (loop = 0; loop < ARRAY_SIZE(devnames); loop++) {
>>> - if (devnames[loop].protocol_id != prot_id)
>>> - continue;
>>> + pr_debug("Requesting SCMI device (%s) for protocol %x\n",
>>> + id_table->name, id_table->protocol_id);
>>> - for (cnt = 0; cnt < ARRAY_SIZE(devnames[loop].names); cnt++) {
>>> - const char *name = devnames[loop].names[cnt];
>>> + /*
>>> + * Search for the matching protocol rdev list and then search
>>> + * of any existent equally named device...fails if any duplicate found.
>>> + */
>>> + mutex_lock(&scmi_requested_devices_mutex);
>>> + idr_for_each_entry(&scmi_requested_devices, rdev, id) {
>>> + if (rdev->id_table->protocol_id == id_table->protocol_id)
>>> + proto_rdev = rdev;
>>> + for (; rdev; rdev = rdev->next) {
>>> + if (!strcmp(rdev->id_table->name, id_table->name)) {
>>> + pr_err("Ignoring duplicate request [%d] %s\n",
>>> + rdev->id_table->protocol_id,
>>> + rdev->id_table->name);
>>> + ret = -EINVAL;
>>> + goto out;
>>> + }
>> Shouldn't there be proto_rdev = rdev here as well ?
>>
>
> No, because each IDR entry points to one or more linked rdev descriptors
> for the same protocol: while scanning each list in the IDR table I'm
> searching for the proto_rdev representing the head of that protocol list
> (if any already exist) and also scan all the lists fully to check for
> duplicates, in such a case we give up.
> The IDR map containing list resembles a lot a Linux hash implementation
> but I decided not to use it because it seemed cumbersome to use an
> hash given most of the time each IDR entry will contain just one single
> element and this lookup happens really very infrequently (just at driver
> loading time)
I agree that using hash might be overkill here.
I still think you need proto_rdev = rdev so that proto_rdev points to
the last element and not the head. Else later on, below when you do
proto_rdev->next = rdev;
you will lose devices.
Basically in the current implementation if there are more than two
devices for a protocol, you will end up losing devices since you are
adding the new device as the second device always.
I think like you mentioned this should be a klist instead of a custom
linked list. And idr can keep track of head of each list.
>
>>> + }
>>> + }
>>> +
>>> + /*
>>> + * No duplicate found for requested id_table, so let's create a new
>>> + * requested device entry for this new valid request.
>>> + */
>>> + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
>>> + if (!rdev) {
>>> + ret = -ENOMEM;
>>> + goto out;
>>> + }
>>> + rdev->id_table = id_table;
>>> +
>>> + /*
>>> + * Append the new requested device table descriptor to the head of the
>>> + * related protocol chain, eventually creating such chain if not already
>>> + * there.
>>> + */
>>> + if (!proto_rdev) {
>>> + ret = idr_alloc(&scmi_requested_devices, (void *)rdev,
>>> + rdev->id_table->protocol_id,
>>> + rdev->id_table->protocol_id + 1, GFP_KERNEL);
>>> + if (ret != rdev->id_table->protocol_id) {
>>> + pr_err("Failed to save SCMI device - ret:%d\n", ret);
>>> + kfree(rdev);
>>> + ret = -EINVAL;
>>> + goto out;
>>> + }
>>> + ret = 0;
>>> + } else {
>>> + proto_rdev->next = rdev;
>>> + }
>>> +
>>> + /*
>>> + * Now effectively create and initialize the requested device for every
>>> + * already initialized SCMI instance which has registered the requested
>>> + * protocol as a valid active one: i.e. defined in DT and supported by
>>> + * current platform FW.
>>> + */
>>> + mutex_lock(&scmi_list_mutex);
>>> + list_for_each_entry(info, &scmi_list, node) {
>>> + struct device_node *child;
>>> +
>>> + child = idr_find(&info->active_protocols,
>>> + id_table->protocol_id);
>>> + if (child) {
>>> + struct scmi_device *sdev;
>>> +
>>> + sdev = scmi_get_protocol_device(child, info,
>>> + id_table->protocol_id,
>>> + id_table->name);
>>> + /* Set handle if not already set (device existed) */
>>> + if (sdev && !sdev->handle)
>>> + sdev->handle = scmi_handle_get_from_info(info);
>>> + } else {
>>> + dev_err(info->dev,
>>> + "Failed. SCMI protocol %d not active.\n",
>>> + id_table->protocol_id);
>>> + }
>>> + }
>>> + mutex_unlock(&scmi_list_mutex);
>>> +
>>> +out:
>>> + mutex_unlock(&scmi_requested_devices_mutex);
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +/**
>>> + * scmi_unrequest_protocol_device - Helper to unrequest a device
>>> + *
>>> + * @id_table: A protocol/name pair descriptor for the device to be unrequested.
>>> + *
>>> + * An helper to let an SCMI driver release its request about devices; note that
>>> + * devices are created and initialized once the first SCMI driver request them
>>> + * but they destroyed only on SCMI core unloading/unbinding.
>>> + *
>>> + * The current SCMI transport layer uses such devices as internal references and
>>> + * as such they could be shared as same transport between multiple drivers so
>>> + * that cannot be safely destroyed till the whole SCMI stack is removed.
>>> + * (unless adding further burden of refcounting.)
>>> + */
>>> +void scmi_unrequest_protocol_device(const struct scmi_device_id *id_table)
>>> +{
>>> + struct scmi_requested_dev *victim, *prev, *head;
>>> +
>>> + pr_debug("Unrequesting SCMI device (%s) for protocol %x\n",
>>> + id_table->name, id_table->protocol_id);
>>> - if (name)
>>> - scmi_create_protocol_device(np, info, prot_id,
>>> - name);
>>> + head = idr_find(&scmi_requested_devices, id_table->protocol_id);
>>> + if (!head)
>>> + return;
>>> +
>>> + /*
>>> + * Scan the protocol list of requested device name searching
>>> + * for the victim.
>>> + */
>>> + victim = head;
>>> + for (prev = victim; victim; prev = victim, victim = victim->next)
>>
>> The initial assignment for the for loop is wrong. With this when you break
>> prev will be equal to victim. You want prev to be the one pointing to the
>> victim. Or am I missing something?
>>
>
> Yes prev is the one preceding the victim, if any, but if it was the head
> I'll remove the head and not use at all the prev really.
> I think is right as it is, it is the naming that is misleading, because
> yes in the initial assignment prev = victim BUT victim = head, so if I bail
> out immediately I'm really removing the head.
> It would be clearer like
>
> prev = victim = head;
> for (; victim; prev = victim, victim = victim->next)
> ...
>
> But it's better that I review this whole loop in deep to simplify it; I
> avoided using klist because seemed easier enough to handle a singly
> linked list which most of the time is one element deep, buut maybe I
> should just stick with well known and proven kists.
Yes you are right. No bug here. Like I mentioned above, klists are
something to consider here.
>
> Thanks
>
> Cristian
>
>>
>> --
>> Warm Regards
>> Thara
--
Warm Regards
Thara
On Fri, Jan 08, 2021 at 11:32:17AM -0500, Thara Gopinath wrote:
>
>
> On 1/8/21 9:42 AM, Cristian Marussi wrote:
> > On Thu, Jan 07, 2021 at 09:28:07AM -0500, Thara Gopinath wrote:
> > > Hi Christian,
> > >
> > > On 1/6/21 3:16 PM, Cristian Marussi wrote:
> > > > Having added the support for SCMI protocols as modules in order to let
> > > > vendors extend the SCMI core with their own additions it seems odd to
> > > > then force SCMI drivers built on top to use a static device table to
> > > > declare their devices since this way any new SCMI drivers addition
> > > > would need the core SCMI device table to be updated too.
> > > >
> > > > Remove the static core device table and let SCMI drivers to simply declare
> > > > which device/protocol pair they need at initialization time: the core will
> > > > then take care to generate such devices dynamically during platform
> > > > initialization or at module loading time, as long as the requested
> > > > underlying protocol is defined in the DT.
> > > >
> > > > Signed-off-by: Cristian Marussi <[email protected]>
> > > > ---
> > >
> > > [snip]
> > >
> > > > -static inline void
> > > > -scmi_create_protocol_devices(struct device_node *np, struct scmi_info *info,
> > > > - int prot_id)
> > > > + for (; rdev; rdev = rdev->next)
> > > > + scmi_create_protocol_device(np, info, prot_id,
> > > > + rdev->id_table->name);
> > > > +}
> > > > +
> > > > +/**
> > > > + * scmi_request_protocol_device - Helper to request a device
> > > > + *
> > > > + * @id_table: A protocol/name pair descriptor for the device to be created.
> > > > + *
> > > > + * This helper let an SCMI driver request specific devices identified by the
> > > > + * @id_table to be created for each active SCMI instance.
> > > > + *
> > > > + * The requested device name MUST NOT be already existent for any protocol;
> > > > + * at first the freshly requested @id_table is annotated in the IDR table
> > > > + * @scmi_requested_devices, then a matching device is created for each already
> > > > + * active SCMI instance. (if any)
> > > > + *
> > > > + * This way the requested device is created straight-away for all the already
> > > > + * initialized(probed) SCMI instances (handles) but it remains instead pending
> > > > + * for creation if the requesting SCMI driver is loaded before some instance
> > > > + * and related transports was available: when such late SCMI instance is probed
> > > > + * it will take care to scan the list of pending requested devices and create
> > > > + * those on its own (see @scmi_create_protocol_devices and its enclosing loop)
> > > > + *
> > > > + * Return: 0 on Success
> > > > + */
> > > > +int scmi_request_protocol_device(const struct scmi_device_id *id_table)
> > > > {
> > > > - int loop, cnt;
> > > > + int ret = 0;
> > > > + unsigned int id = 0;
> > > > + struct scmi_requested_dev *rdev, *proto_rdev = NULL;
> > > > + struct scmi_info *info;
> > > > - for (loop = 0; loop < ARRAY_SIZE(devnames); loop++) {
> > > > - if (devnames[loop].protocol_id != prot_id)
> > > > - continue;
> > > > + pr_debug("Requesting SCMI device (%s) for protocol %x\n",
> > > > + id_table->name, id_table->protocol_id);
> > > > - for (cnt = 0; cnt < ARRAY_SIZE(devnames[loop].names); cnt++) {
> > > > - const char *name = devnames[loop].names[cnt];
> > > > + /*
> > > > + * Search for the matching protocol rdev list and then search
> > > > + * of any existent equally named device...fails if any duplicate found.
> > > > + */
> > > > + mutex_lock(&scmi_requested_devices_mutex);
> > > > + idr_for_each_entry(&scmi_requested_devices, rdev, id) {
> > > > + if (rdev->id_table->protocol_id == id_table->protocol_id)
> > > > + proto_rdev = rdev;
> > > > + for (; rdev; rdev = rdev->next) {
> > > > + if (!strcmp(rdev->id_table->name, id_table->name)) {
> > > > + pr_err("Ignoring duplicate request [%d] %s\n",
> > > > + rdev->id_table->protocol_id,
> > > > + rdev->id_table->name);
> > > > + ret = -EINVAL;
> > > > + goto out;
> > > > + }
> > > Shouldn't there be proto_rdev = rdev here as well ?
> > >
> >
> > No, because each IDR entry points to one or more linked rdev descriptors
> > for the same protocol: while scanning each list in the IDR table I'm
> > searching for the proto_rdev representing the head of that protocol list
> > (if any already exist) and also scan all the lists fully to check for
> > duplicates, in such a case we give up.
> > The IDR map containing list resembles a lot a Linux hash implementation
> > but I decided not to use it because it seemed cumbersome to use an
> > hash given most of the time each IDR entry will contain just one single
> > element and this lookup happens really very infrequently (just at driver
> > loading time)
>
> I agree that using hash might be overkill here.
> I still think you need proto_rdev = rdev so that proto_rdev points to the
> last element and not the head. Else later on, below when you do
> proto_rdev->next = rdev;
> you will lose devices.
>
> Basically in the current implementation if there are more than two devices
> for a protocol, you will end up losing devices since you are adding the new
> device as the second device always.
>
Ah right I missed that sorry...now I'm definitely convinced to use klist heads
in the IDRs and avoid all of this :D
> I think like you mentioned this should be a klist instead of a custom linked
> list. And idr can keep track of head of each list.
>
> >
> > > > + }
> > > > + }
> > > > +
> > > > + /*
> > > > + * No duplicate found for requested id_table, so let's create a new
> > > > + * requested device entry for this new valid request.
> > > > + */
> > > > + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
> > > > + if (!rdev) {
> > > > + ret = -ENOMEM;
> > > > + goto out;
> > > > + }
> > > > + rdev->id_table = id_table;
> > > > +
> > > > + /*
> > > > + * Append the new requested device table descriptor to the head of the
> > > > + * related protocol chain, eventually creating such chain if not already
> > > > + * there.
> > > > + */
> > > > + if (!proto_rdev) {
> > > > + ret = idr_alloc(&scmi_requested_devices, (void *)rdev,
> > > > + rdev->id_table->protocol_id,
> > > > + rdev->id_table->protocol_id + 1, GFP_KERNEL);
> > > > + if (ret != rdev->id_table->protocol_id) {
> > > > + pr_err("Failed to save SCMI device - ret:%d\n", ret);
> > > > + kfree(rdev);
> > > > + ret = -EINVAL;
> > > > + goto out;
> > > > + }
> > > > + ret = 0;
> > > > + } else {
> > > > + proto_rdev->next = rdev;
> > > > + }
> > > > +
> > > > + /*
> > > > + * Now effectively create and initialize the requested device for every
> > > > + * already initialized SCMI instance which has registered the requested
> > > > + * protocol as a valid active one: i.e. defined in DT and supported by
> > > > + * current platform FW.
> > > > + */
> > > > + mutex_lock(&scmi_list_mutex);
> > > > + list_for_each_entry(info, &scmi_list, node) {
> > > > + struct device_node *child;
> > > > +
> > > > + child = idr_find(&info->active_protocols,
> > > > + id_table->protocol_id);
> > > > + if (child) {
> > > > + struct scmi_device *sdev;
> > > > +
> > > > + sdev = scmi_get_protocol_device(child, info,
> > > > + id_table->protocol_id,
> > > > + id_table->name);
> > > > + /* Set handle if not already set (device existed) */
> > > > + if (sdev && !sdev->handle)
> > > > + sdev->handle = scmi_handle_get_from_info(info);
> > > > + } else {
> > > > + dev_err(info->dev,
> > > > + "Failed. SCMI protocol %d not active.\n",
> > > > + id_table->protocol_id);
> > > > + }
> > > > + }
> > > > + mutex_unlock(&scmi_list_mutex);
> > > > +
> > > > +out:
> > > > + mutex_unlock(&scmi_requested_devices_mutex);
> > > > +
> > > > + return ret;
> > > > +}
> > > > +
> > > > +/**
> > > > + * scmi_unrequest_protocol_device - Helper to unrequest a device
> > > > + *
> > > > + * @id_table: A protocol/name pair descriptor for the device to be unrequested.
> > > > + *
> > > > + * An helper to let an SCMI driver release its request about devices; note that
> > > > + * devices are created and initialized once the first SCMI driver request them
> > > > + * but they destroyed only on SCMI core unloading/unbinding.
> > > > + *
> > > > + * The current SCMI transport layer uses such devices as internal references and
> > > > + * as such they could be shared as same transport between multiple drivers so
> > > > + * that cannot be safely destroyed till the whole SCMI stack is removed.
> > > > + * (unless adding further burden of refcounting.)
> > > > + */
> > > > +void scmi_unrequest_protocol_device(const struct scmi_device_id *id_table)
> > > > +{
> > > > + struct scmi_requested_dev *victim, *prev, *head;
> > > > +
> > > > + pr_debug("Unrequesting SCMI device (%s) for protocol %x\n",
> > > > + id_table->name, id_table->protocol_id);
> > > > - if (name)
> > > > - scmi_create_protocol_device(np, info, prot_id,
> > > > - name);
> > > > + head = idr_find(&scmi_requested_devices, id_table->protocol_id);
> > > > + if (!head)
> > > > + return;
> > > > +
> > > > + /*
> > > > + * Scan the protocol list of requested device name searching
> > > > + * for the victim.
> > > > + */
> > > > + victim = head;
> > > > + for (prev = victim; victim; prev = victim, victim = victim->next)
> > >
> > > The initial assignment for the for loop is wrong. With this when you break
> > > prev will be equal to victim. You want prev to be the one pointing to the
> > > victim. Or am I missing something?
> > >
> >
> > Yes prev is the one preceding the victim, if any, but if it was the head
> > I'll remove the head and not use at all the prev really.
> > I think is right as it is, it is the naming that is misleading, because
> > yes in the initial assignment prev = victim BUT victim = head, so if I bail
> > out immediately I'm really removing the head.
> > It would be clearer like
> >
> > prev = victim = head;
> > for (; victim; prev = victim, victim = victim->next)
> > ...
> >
> > But it's better that I review this whole loop in deep to simplify it; I
> > avoided using klist because seemed easier enough to handle a singly
> > linked list which most of the time is one element deep, buut maybe I
> > should just stick with well known and proven kists.
>
> Yes you are right. No bug here. Like I mentioned above, klists are something
> to consider here.
>
Thanks, I'll switch to klist.
Cristian
> >
> > Thanks
> >
> > Cristian
> >
> > >
> > > --
> > > Warm Regards
> > > Thara
>
> --
> Warm Regards
> Thara