Expose one debugfs entry for each discovered SHMTI that can be used to dump the related SHMTI in binary form from TBGN up to TEND markers. No processing is done kernel side, beside using proper accessors for device memory. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/telemetry.c | 90 +++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/drivers/firmware/arm_scmi/telemetry.c b/drivers/firmware/arm_scmi/telemetry.c index ab1be6c462f1..a43d67494d73 100644 --- a/drivers/firmware/arm_scmi/telemetry.c +++ b/drivers/firmware/arm_scmi/telemetry.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -371,6 +373,12 @@ struct telemetry_shmti { u32 last_magic; }; +struct scmi_telemetry_dbg_shmti { + struct telemetry_shmti *shmti; + size_t buf_sz; + void *buf; +}; + #define SHMTI_EPLG(s) \ ({ \ struct telemetry_shmti *_s = (s); \ @@ -1299,6 +1307,85 @@ scmi_telemetry_enumerate_common_intervals(struct telemetry_info *ti) ti->info.intervals); } +static int scmi_telemetry_dbg_shmti_open(struct inode *inode, struct file *filp) +{ + struct scmi_telemetry_dbg_shmti *sblob; + struct telemetry_shmti *shmti; + + if (!inode->i_private) + return -ENODEV; + + shmti = inode->i_private; + sblob = kzalloc_obj(*sblob); + if (!sblob) + return -ENOMEM; + + sblob->shmti = shmti; + sblob->buf = kzalloc(shmti->len, GFP_KERNEL); + if (!sblob->buf) { + kfree(sblob); + return -ENOMEM; + } + + filp->private_data = sblob; + + return 0; +} + +static ssize_t scmi_telemetry_dbg_shmti_read(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct scmi_telemetry_dbg_shmti *sblob = filp->private_data; + + /* Dump on first read and again after each rewind to start pos */ + if (!sblob->buf_sz || *ppos == 0) { + memcpy_fromio(sblob->buf, sblob->shmti->base, sblob->shmti->len); + sblob->buf_sz = sblob->shmti->len; + /* update inode timestamps */ + simple_inode_init_ts(file_inode(filp)); + } + + return simple_read_from_buffer(buf, count, ppos, sblob->buf, sblob->buf_sz); +} + +static int scmi_telemetry_dbg_shmti_release(struct inode *inode, struct file *filp) +{ + struct scmi_telemetry_dbg_shmti *sblob = filp->private_data; + + kfree(sblob->buf); + kfree(sblob); + + return 0; +} + +static const struct file_operations scmi_telemetry_dbg_shmti_fops = { + .open = scmi_telemetry_dbg_shmti_open, + .release = scmi_telemetry_dbg_shmti_release, + .read = scmi_telemetry_dbg_shmti_read, + .llseek = generic_file_llseek, + .owner = THIS_MODULE, +}; + +static void scmi_telemetry_debugfs_initialize(struct telemetry_info *ti) +{ + const struct scmi_protocol_handle *ph = ti->ph; + struct dentry *top, *shmti_top; + + top = ph->hops->debugfs_proto_dentry_get(ph); + shmti_top = debugfs_create_dir("shmtis", top); + + for (unsigned int i = 0; i < ti->num_shmti; i++) { + struct dentry *d; + char id[16]; + + snprintf(id, 16, "%u", i); + d = debugfs_create_file(id, 0444, shmti_top, &ti->shmti[i], + &scmi_telemetry_dbg_shmti_fops); + if (!IS_ERR(d)) + i_size_write(d->d_inode, ti->shmti[i].len); + } +} + static int iter_shmti_update_state(struct scmi_iterator_state *st, const void *response, void *priv) { @@ -3195,6 +3282,9 @@ static int scmi_telemetry_protocol_init(const struct scmi_protocol_handle *ph) "Could NOT register Telemetry notifications\n"); } + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_PROTOCOLS)) + scmi_telemetry_debugfs_initialize(ti); + return ret; } -- 2.54.0