Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Remote Processor Framework
0004  *
0005  * Copyright (C) 2011 Texas Instruments, Inc.
0006  * Copyright (C) 2011 Google, Inc.
0007  *
0008  * Ohad Ben-Cohen <ohad@wizery.com>
0009  * Mark Grosen <mgrosen@ti.com>
0010  * Brian Swetland <swetland@google.com>
0011  * Fernando Guzman Lugo <fernando.lugo@ti.com>
0012  * Suman Anna <s-anna@ti.com>
0013  * Robert Tivy <rtivy@ti.com>
0014  * Armando Uribe De Leon <x0095078@ti.com>
0015  */
0016 
0017 #define pr_fmt(fmt)    "%s: " fmt, __func__
0018 
0019 #include <linux/kernel.h>
0020 #include <linux/debugfs.h>
0021 #include <linux/remoteproc.h>
0022 #include <linux/device.h>
0023 #include <linux/uaccess.h>
0024 
0025 #include "remoteproc_internal.h"
0026 
0027 /* remoteproc debugfs parent dir */
0028 static struct dentry *rproc_dbg;
0029 
0030 /*
0031  * A coredump-configuration-to-string lookup table, for exposing a
0032  * human readable configuration via debugfs. Always keep in sync with
0033  * enum rproc_coredump_mechanism
0034  */
0035 static const char * const rproc_coredump_str[] = {
0036     [RPROC_COREDUMP_DISABLED]   = "disabled",
0037     [RPROC_COREDUMP_ENABLED]    = "enabled",
0038     [RPROC_COREDUMP_INLINE]     = "inline",
0039 };
0040 
0041 /* Expose the current coredump configuration via debugfs */
0042 static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf,
0043                    size_t count, loff_t *ppos)
0044 {
0045     struct rproc *rproc = filp->private_data;
0046     char buf[20];
0047     int len;
0048 
0049     len = scnprintf(buf, sizeof(buf), "%s\n",
0050             rproc_coredump_str[rproc->dump_conf]);
0051 
0052     return simple_read_from_buffer(userbuf, count, ppos, buf, len);
0053 }
0054 
0055 /*
0056  * By writing to the 'coredump' debugfs entry, we control the behavior of the
0057  * coredump mechanism dynamically. The default value of this entry is "disabled".
0058  *
0059  * The 'coredump' debugfs entry supports these commands:
0060  *
0061  * disabled:    By default coredump collection is disabled. Recovery will
0062  *      proceed without collecting any dump.
0063  *
0064  * enabled: When the remoteproc crashes the entire coredump will be copied
0065  *      to a separate buffer and exposed to userspace.
0066  *
0067  * inline:  The coredump will not be copied to a separate buffer and the
0068  *      recovery process will have to wait until data is read by
0069  *      userspace. But this avoid usage of extra memory.
0070  */
0071 static ssize_t rproc_coredump_write(struct file *filp,
0072                     const char __user *user_buf, size_t count,
0073                     loff_t *ppos)
0074 {
0075     struct rproc *rproc = filp->private_data;
0076     int ret, err = 0;
0077     char buf[20];
0078 
0079     if (count < 1 || count > sizeof(buf))
0080         return -EINVAL;
0081 
0082     ret = copy_from_user(buf, user_buf, count);
0083     if (ret)
0084         return -EFAULT;
0085 
0086     /* remove end of line */
0087     if (buf[count - 1] == '\n')
0088         buf[count - 1] = '\0';
0089 
0090     if (rproc->state == RPROC_CRASHED) {
0091         dev_err(&rproc->dev, "can't change coredump configuration\n");
0092         err = -EBUSY;
0093         goto out;
0094     }
0095 
0096     if (!strncmp(buf, "disabled", count)) {
0097         rproc->dump_conf = RPROC_COREDUMP_DISABLED;
0098     } else if (!strncmp(buf, "enabled", count)) {
0099         rproc->dump_conf = RPROC_COREDUMP_ENABLED;
0100     } else if (!strncmp(buf, "inline", count)) {
0101         rproc->dump_conf = RPROC_COREDUMP_INLINE;
0102     } else {
0103         dev_err(&rproc->dev, "Invalid coredump configuration\n");
0104         err = -EINVAL;
0105     }
0106 out:
0107     return err ? err : count;
0108 }
0109 
0110 static const struct file_operations rproc_coredump_fops = {
0111     .read = rproc_coredump_read,
0112     .write = rproc_coredump_write,
0113     .open = simple_open,
0114     .llseek = generic_file_llseek,
0115 };
0116 
0117 /*
0118  * Some remote processors may support dumping trace logs into a shared
0119  * memory buffer. We expose this trace buffer using debugfs, so users
0120  * can easily tell what's going on remotely.
0121  *
0122  * We will most probably improve the rproc tracing facilities later on,
0123  * but this kind of lightweight and simple mechanism is always good to have,
0124  * as it provides very early tracing with little to no dependencies at all.
0125  */
0126 static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
0127                 size_t count, loff_t *ppos)
0128 {
0129     struct rproc_debug_trace *data = filp->private_data;
0130     struct rproc_mem_entry *trace = &data->trace_mem;
0131     void *va;
0132     char buf[100];
0133     int len;
0134 
0135     va = rproc_da_to_va(data->rproc, trace->da, trace->len, NULL);
0136 
0137     if (!va) {
0138         len = scnprintf(buf, sizeof(buf), "Trace %s not available\n",
0139                 trace->name);
0140         va = buf;
0141     } else {
0142         len = strnlen(va, trace->len);
0143     }
0144 
0145     return simple_read_from_buffer(userbuf, count, ppos, va, len);
0146 }
0147 
0148 static const struct file_operations trace_rproc_ops = {
0149     .read = rproc_trace_read,
0150     .open = simple_open,
0151     .llseek = generic_file_llseek,
0152 };
0153 
0154 /* expose the name of the remote processor via debugfs */
0155 static ssize_t rproc_name_read(struct file *filp, char __user *userbuf,
0156                    size_t count, loff_t *ppos)
0157 {
0158     struct rproc *rproc = filp->private_data;
0159     /* need room for the name, a newline and a terminating null */
0160     char buf[100];
0161     int i;
0162 
0163     i = scnprintf(buf, sizeof(buf), "%.98s\n", rproc->name);
0164 
0165     return simple_read_from_buffer(userbuf, count, ppos, buf, i);
0166 }
0167 
0168 static const struct file_operations rproc_name_ops = {
0169     .read = rproc_name_read,
0170     .open = simple_open,
0171     .llseek = generic_file_llseek,
0172 };
0173 
0174 /* expose recovery flag via debugfs */
0175 static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf,
0176                    size_t count, loff_t *ppos)
0177 {
0178     struct rproc *rproc = filp->private_data;
0179     char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n";
0180 
0181     return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
0182 }
0183 
0184 /*
0185  * By writing to the 'recovery' debugfs entry, we control the behavior of the
0186  * recovery mechanism dynamically. The default value of this entry is "enabled".
0187  *
0188  * The 'recovery' debugfs entry supports these commands:
0189  *
0190  * enabled: When enabled, the remote processor will be automatically
0191  *      recovered whenever it crashes. Moreover, if the remote
0192  *      processor crashes while recovery is disabled, it will
0193  *      be automatically recovered too as soon as recovery is enabled.
0194  *
0195  * disabled:    When disabled, a remote processor will remain in a crashed
0196  *      state if it crashes. This is useful for debugging purposes;
0197  *      without it, debugging a crash is substantially harder.
0198  *
0199  * recover: This function will trigger an immediate recovery if the
0200  *      remote processor is in a crashed state, without changing
0201  *      or checking the recovery state (enabled/disabled).
0202  *      This is useful during debugging sessions, when one expects
0203  *      additional crashes to happen after enabling recovery. In this
0204  *      case, enabling recovery will make it hard to debug subsequent
0205  *      crashes, so it's recommended to keep recovery disabled, and
0206  *      instead use the "recover" command as needed.
0207  */
0208 static ssize_t
0209 rproc_recovery_write(struct file *filp, const char __user *user_buf,
0210              size_t count, loff_t *ppos)
0211 {
0212     struct rproc *rproc = filp->private_data;
0213     char buf[10];
0214     int ret;
0215 
0216     if (count < 1 || count > sizeof(buf))
0217         return -EINVAL;
0218 
0219     ret = copy_from_user(buf, user_buf, count);
0220     if (ret)
0221         return -EFAULT;
0222 
0223     /* remove end of line */
0224     if (buf[count - 1] == '\n')
0225         buf[count - 1] = '\0';
0226 
0227     if (!strncmp(buf, "enabled", count)) {
0228         /* change the flag and begin the recovery process if needed */
0229         rproc->recovery_disabled = false;
0230         rproc_trigger_recovery(rproc);
0231     } else if (!strncmp(buf, "disabled", count)) {
0232         rproc->recovery_disabled = true;
0233     } else if (!strncmp(buf, "recover", count)) {
0234         /* begin the recovery process without changing the flag */
0235         rproc_trigger_recovery(rproc);
0236     } else {
0237         return -EINVAL;
0238     }
0239 
0240     return count;
0241 }
0242 
0243 static const struct file_operations rproc_recovery_ops = {
0244     .read = rproc_recovery_read,
0245     .write = rproc_recovery_write,
0246     .open = simple_open,
0247     .llseek = generic_file_llseek,
0248 };
0249 
0250 /* expose the crash trigger via debugfs */
0251 static ssize_t
0252 rproc_crash_write(struct file *filp, const char __user *user_buf,
0253           size_t count, loff_t *ppos)
0254 {
0255     struct rproc *rproc = filp->private_data;
0256     unsigned int type;
0257     int ret;
0258 
0259     ret = kstrtouint_from_user(user_buf, count, 0, &type);
0260     if (ret < 0)
0261         return ret;
0262 
0263     rproc_report_crash(rproc, type);
0264 
0265     return count;
0266 }
0267 
0268 static const struct file_operations rproc_crash_ops = {
0269     .write = rproc_crash_write,
0270     .open = simple_open,
0271     .llseek = generic_file_llseek,
0272 };
0273 
0274 /* Expose resource table content via debugfs */
0275 static int rproc_rsc_table_show(struct seq_file *seq, void *p)
0276 {
0277     static const char * const types[] = {"carveout", "devmem", "trace", "vdev"};
0278     struct rproc *rproc = seq->private;
0279     struct resource_table *table = rproc->table_ptr;
0280     struct fw_rsc_carveout *c;
0281     struct fw_rsc_devmem *d;
0282     struct fw_rsc_trace *t;
0283     struct fw_rsc_vdev *v;
0284     int i, j;
0285 
0286     if (!table) {
0287         seq_puts(seq, "No resource table found\n");
0288         return 0;
0289     }
0290 
0291     for (i = 0; i < table->num; i++) {
0292         int offset = table->offset[i];
0293         struct fw_rsc_hdr *hdr = (void *)table + offset;
0294         void *rsc = (void *)hdr + sizeof(*hdr);
0295 
0296         switch (hdr->type) {
0297         case RSC_CARVEOUT:
0298             c = rsc;
0299             seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
0300             seq_printf(seq, "  Device Address 0x%x\n", c->da);
0301             seq_printf(seq, "  Physical Address 0x%x\n", c->pa);
0302             seq_printf(seq, "  Length 0x%x Bytes\n", c->len);
0303             seq_printf(seq, "  Flags 0x%x\n", c->flags);
0304             seq_printf(seq, "  Reserved (should be zero) [%d]\n", c->reserved);
0305             seq_printf(seq, "  Name %s\n\n", c->name);
0306             break;
0307         case RSC_DEVMEM:
0308             d = rsc;
0309             seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
0310             seq_printf(seq, "  Device Address 0x%x\n", d->da);
0311             seq_printf(seq, "  Physical Address 0x%x\n", d->pa);
0312             seq_printf(seq, "  Length 0x%x Bytes\n", d->len);
0313             seq_printf(seq, "  Flags 0x%x\n", d->flags);
0314             seq_printf(seq, "  Reserved (should be zero) [%d]\n", d->reserved);
0315             seq_printf(seq, "  Name %s\n\n", d->name);
0316             break;
0317         case RSC_TRACE:
0318             t = rsc;
0319             seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
0320             seq_printf(seq, "  Device Address 0x%x\n", t->da);
0321             seq_printf(seq, "  Length 0x%x Bytes\n", t->len);
0322             seq_printf(seq, "  Reserved (should be zero) [%d]\n", t->reserved);
0323             seq_printf(seq, "  Name %s\n\n", t->name);
0324             break;
0325         case RSC_VDEV:
0326             v = rsc;
0327             seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
0328 
0329             seq_printf(seq, "  ID %d\n", v->id);
0330             seq_printf(seq, "  Notify ID %d\n", v->notifyid);
0331             seq_printf(seq, "  Device features 0x%x\n", v->dfeatures);
0332             seq_printf(seq, "  Guest features 0x%x\n", v->gfeatures);
0333             seq_printf(seq, "  Config length 0x%x\n", v->config_len);
0334             seq_printf(seq, "  Status 0x%x\n", v->status);
0335             seq_printf(seq, "  Number of vrings %d\n", v->num_of_vrings);
0336             seq_printf(seq, "  Reserved (should be zero) [%d][%d]\n\n",
0337                    v->reserved[0], v->reserved[1]);
0338 
0339             for (j = 0; j < v->num_of_vrings; j++) {
0340                 seq_printf(seq, "  Vring %d\n", j);
0341                 seq_printf(seq, "    Device Address 0x%x\n", v->vring[j].da);
0342                 seq_printf(seq, "    Alignment %d\n", v->vring[j].align);
0343                 seq_printf(seq, "    Number of buffers %d\n", v->vring[j].num);
0344                 seq_printf(seq, "    Notify ID %d\n", v->vring[j].notifyid);
0345                 seq_printf(seq, "    Physical Address 0x%x\n\n",
0346                        v->vring[j].pa);
0347             }
0348             break;
0349         default:
0350             seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n",
0351                    hdr->type, hdr);
0352             break;
0353         }
0354     }
0355 
0356     return 0;
0357 }
0358 
0359 DEFINE_SHOW_ATTRIBUTE(rproc_rsc_table);
0360 
0361 /* Expose carveout content via debugfs */
0362 static int rproc_carveouts_show(struct seq_file *seq, void *p)
0363 {
0364     struct rproc *rproc = seq->private;
0365     struct rproc_mem_entry *carveout;
0366 
0367     list_for_each_entry(carveout, &rproc->carveouts, node) {
0368         seq_puts(seq, "Carveout memory entry:\n");
0369         seq_printf(seq, "\tName: %s\n", carveout->name);
0370         seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
0371         seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
0372         seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
0373         seq_printf(seq, "\tLength: 0x%zx Bytes\n\n", carveout->len);
0374     }
0375 
0376     return 0;
0377 }
0378 
0379 DEFINE_SHOW_ATTRIBUTE(rproc_carveouts);
0380 
0381 void rproc_remove_trace_file(struct dentry *tfile)
0382 {
0383     debugfs_remove(tfile);
0384 }
0385 
0386 struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
0387                        struct rproc_debug_trace *trace)
0388 {
0389     return debugfs_create_file(name, 0400, rproc->dbg_dir, trace,
0390                     &trace_rproc_ops);
0391 }
0392 
0393 void rproc_delete_debug_dir(struct rproc *rproc)
0394 {
0395     debugfs_remove_recursive(rproc->dbg_dir);
0396 }
0397 
0398 void rproc_create_debug_dir(struct rproc *rproc)
0399 {
0400     struct device *dev = &rproc->dev;
0401 
0402     if (!rproc_dbg)
0403         return;
0404 
0405     rproc->dbg_dir = debugfs_create_dir(dev_name(dev), rproc_dbg);
0406 
0407     debugfs_create_file("name", 0400, rproc->dbg_dir,
0408                 rproc, &rproc_name_ops);
0409     debugfs_create_file("recovery", 0600, rproc->dbg_dir,
0410                 rproc, &rproc_recovery_ops);
0411     debugfs_create_file("crash", 0200, rproc->dbg_dir,
0412                 rproc, &rproc_crash_ops);
0413     debugfs_create_file("resource_table", 0400, rproc->dbg_dir,
0414                 rproc, &rproc_rsc_table_fops);
0415     debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir,
0416                 rproc, &rproc_carveouts_fops);
0417     debugfs_create_file("coredump", 0600, rproc->dbg_dir,
0418                 rproc, &rproc_coredump_fops);
0419 }
0420 
0421 void __init rproc_init_debugfs(void)
0422 {
0423     if (debugfs_initialized())
0424         rproc_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
0425 }
0426 
0427 void __exit rproc_exit_debugfs(void)
0428 {
0429     debugfs_remove(rproc_dbg);
0430 }