[PATCH v10 15/24] firmware: arm_scmi: Add common per-protocol debugfs support
Cristian Marussi <[email protected]>
| Newsgroups | org.infradead.lists.linux-arm-kernel,org.kernel.vger.arm-scmi,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Allow interested SCMI protocols to register their own specific debugfs entries under a common per-instance and per-protocol subtree rooted at /sys/kernel/debug/scmi/<N>/protocols/<PROTO_ID>/ Expose a helper to enable protocol initialization code to get access to such per-protocol/per-instance dentries in order to be able to install their own dedicated debugfs entries. Per-protocol debugfs support is configurable and default off. Signed-off-by: Cristian Marussi <[email protected]> --- v8 --> v9 - avoid NULL deref on DBG cleanup path v5 --> v6 - bail out of dentry_get helper when SCMI debug susbsytem failed to init - remove stale SCMI protocol operations - add a preoper clean up of debugfs when protocol init fails --- drivers/firmware/arm_scmi/Kconfig | 14 +++++++++++ drivers/firmware/arm_scmi/common.h | 2 ++ drivers/firmware/arm_scmi/driver.c | 35 +++++++++++++++++++++++++-- drivers/firmware/arm_scmi/protocols.h | 6 +++++ include/linux/scmi_protocol.h | 1 - 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index 783c24a20e29..f506c4d1d96a 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -69,6 +69,20 @@ config ARM_SCMI_DEBUG_COUNTERS such useful debug counters. This can be helpful for debugging and SCMI monitoring. +config ARM_SCMI_DEBUG_PROTOCOLS + bool "Enable SCMI protocols debug" + select ARM_SCMI_NEED_DEBUGFS + depends on DEBUG_FS + default n + help + Enables per-protocol specific debug features, where available. + When provided, such per-protocol debugfs entries are grouped + inside a common a subtree named by the protocol number and rooted + under a per-instance 'protocols' directory. + + Such per-protocol entries subtree structure is freely defined + within the related protocol code. + config ARM_SCMI_QUIRKS bool "Enable SCMI Quirks framework" depends on JUMP_LABEL || COMPILE_TEST diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index e0a2549423ee..f78a9ec8a8c3 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -322,6 +322,7 @@ enum debug_counters { /** * struct scmi_debug_info - Debug common info * @top_dentry: A reference to the top debugfs dentry + * @protos: A reference to the top debugfs protocols subdirectory * @name: Name of this SCMI instance * @type: Type of this SCMI instance * @is_atomic: Flag to state if the transport of this instance is atomic @@ -329,6 +330,7 @@ enum debug_counters { */ struct scmi_debug_info { struct dentry *top_dentry; + struct dentry *protos; const char *name; const char *type; bool is_atomic; diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index c2fe984f0b47..39940086a143 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -18,6 +18,7 @@ #include <linux/bitmap.h> #include <linux/cleanup.h> +#include <linux/dcache.h> #include <linux/debugfs.h> #include <linux/device.h> #include <linux/export.h> @@ -101,6 +102,8 @@ struct scmi_xfers_info { * has completed. * @ph: An embedded protocol handle that will be passed down to protocol * initialization code to identify this instance. + * @dbg: An optional reference to this protocol top debugfs directory; it will + * be automatically recursively removed on protocol de-initialization. * * Each protocol is initialized independently once for each SCMI platform in * which is defined by DT and implemented by the SCMI server fw. @@ -115,6 +118,7 @@ struct scmi_protocol_instance { unsigned int version; unsigned int negotiated_version; struct scmi_protocol_handle ph; + struct dentry *dbg; }; #define ph_to_pi(h) container_of(h, struct scmi_protocol_instance, ph) @@ -2093,6 +2097,25 @@ static void scmi_common_fastchannel_db_ring(struct scmi_fc_db_info *db) SCMI_PROTO_FC_RING_DB(64); } +static struct dentry * +scmi_debugfs_proto_dentry_get(const struct scmi_protocol_handle *ph) +{ + struct scmi_protocol_instance *pi = ph_to_pi(ph); + struct scmi_info *info = handle_to_scmi_info(pi->handle); + + if (!IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_PROTOCOLS) || !info->dbg) + return ERR_PTR(-ENODEV); + + if (!pi->dbg) { + char proto_dir[8]; + + snprintf(proto_dir, 8, "0x%02X", pi->proto->id); + pi->dbg = debugfs_create_dir(proto_dir, info->dbg->protos); + } + + return pi->dbg; +} + static const struct scmi_proto_helpers_ops helpers_ops = { .extended_name_get = scmi_common_extended_name_get, .get_max_msg_size = scmi_common_get_max_msg_size, @@ -2103,6 +2126,7 @@ static const struct scmi_proto_helpers_ops helpers_ops = { .protocol_msg_check = scmi_protocol_msg_check, .fastchannel_init = scmi_common_fastchannel_init, .fastchannel_db_ring = scmi_common_fastchannel_db_ring, + .debugfs_proto_dentry_get = scmi_debugfs_proto_dentry_get, }; /** @@ -2288,12 +2312,12 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info, /* proto->init is assured NON NULL by scmi_protocol_register */ ret = pi->proto->instance_init(&pi->ph); if (ret) - goto clean; + goto clean_dbg; ret = idr_alloc(&info->protocols, pi, proto->id, proto->id + 1, GFP_KERNEL); if (ret != proto->id) - goto clean; + goto clean_dbg; /* * Warn but ignore events registration errors since we do not want @@ -2314,6 +2338,8 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info, return pi; +clean_dbg: + debugfs_remove_recursive(pi->dbg); clean: /* Take care to put the protocol module's owner before releasing all */ scmi_protocol_put(proto); @@ -2429,6 +2455,8 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id) if (refcount_dec_and_test(&pi->users)) { void *gid = pi->gid; + debugfs_remove_recursive(pi->dbg); + if (pi->proto->events) scmi_deregister_protocol_events(handle, protocol_id); @@ -3151,6 +3179,9 @@ static struct scmi_debug_info *scmi_debugfs_common_setup(struct scmi_info *info) if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) scmi_debugfs_counters_setup(dbg, trans); + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_PROTOCOLS)) + dbg->protos = debugfs_create_dir("protocols", top_dentry); + dbg->top_dentry = top_dentry; if (devm_add_action_or_reset(info->dev, diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h index 1f9925b8f495..04e196a9fbf4 100644 --- a/drivers/firmware/arm_scmi/protocols.h +++ b/drivers/firmware/arm_scmi/protocols.h @@ -11,6 +11,7 @@ #include <linux/bitfield.h> #include <linux/completion.h> +#include <linux/debugfs.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/kernel.h> @@ -284,6 +285,9 @@ struct scmi_fc_info { * gathering FC descriptions from the SCMI platform server. * @fastchannel_db_ring: A common helper to ring a FC doorbell. * @get_max_msg_size: A common helper to get the maximum message size. + * @debugfs_proto_dentry_get: A common helper to get a per-protocol debugfs top + * directory to use as a root. It will be + * recursively removed on protocol de-initialization. */ struct scmi_proto_helpers_ops { int (*extended_name_get)(const struct scmi_protocol_handle *ph, @@ -307,6 +311,8 @@ struct scmi_proto_helpers_ops { u32 *rate_limit); void (*fastchannel_db_ring)(struct scmi_fc_db_info *db); int (*get_max_msg_size)(const struct scmi_protocol_handle *ph); + struct dentry *(*debugfs_proto_dentry_get) + (const struct scmi_protocol_handle *ph); }; /** diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 83ab8edc0b13..037b486dc873 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -1156,7 +1156,6 @@ struct scmi_handle { void (*devm_protocol_put)(struct scmi_device *sdev, u8 proto); bool (*is_transport_atomic)(const struct scmi_handle *handle, unsigned int *atomic_threshold); - const struct scmi_notify_ops *notify_ops; }; -- 2.54.0