linux/drivers/remoteproc/remoteproc_debugfs.c
<<
>>
Prefs
   1/*
   2 * Remote Processor Framework
   3 *
   4 * Copyright (C) 2011 Texas Instruments, Inc.
   5 * Copyright (C) 2011 Google, Inc.
   6 *
   7 * Ohad Ben-Cohen <ohad@wizery.com>
   8 * Mark Grosen <mgrosen@ti.com>
   9 * Brian Swetland <swetland@google.com>
  10 * Fernando Guzman Lugo <fernando.lugo@ti.com>
  11 * Suman Anna <s-anna@ti.com>
  12 * Robert Tivy <rtivy@ti.com>
  13 * Armando Uribe De Leon <x0095078@ti.com>
  14 *
  15 * This program is free software; you can redistribute it and/or
  16 * modify it under the terms of the GNU General Public License
  17 * version 2 as published by the Free Software Foundation.
  18 *
  19 * This program is distributed in the hope that it will be useful,
  20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22 * GNU General Public License for more details.
  23 */
  24
  25#define pr_fmt(fmt)    "%s: " fmt, __func__
  26
  27#include <linux/kernel.h>
  28#include <linux/debugfs.h>
  29#include <linux/remoteproc.h>
  30#include <linux/device.h>
  31#include <linux/uaccess.h>
  32
  33#include "remoteproc_internal.h"
  34
  35/* remoteproc debugfs parent dir */
  36static struct dentry *rproc_dbg;
  37
  38/*
  39 * Some remote processors may support dumping trace logs into a shared
  40 * memory buffer. We expose this trace buffer using debugfs, so users
  41 * can easily tell what's going on remotely.
  42 *
  43 * We will most probably improve the rproc tracing facilities later on,
  44 * but this kind of lightweight and simple mechanism is always good to have,
  45 * as it provides very early tracing with little to no dependencies at all.
  46 */
  47static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
  48                                size_t count, loff_t *ppos)
  49{
  50        struct rproc_debug_trace *data = filp->private_data;
  51        struct rproc_mem_entry *trace = &data->trace_mem;
  52        void *va;
  53        char buf[100];
  54        int len;
  55
  56        va = rproc_da_to_va(data->rproc, trace->da, trace->len);
  57
  58        if (!va) {
  59                len = scnprintf(buf, sizeof(buf), "Trace %s not available\n",
  60                                trace->name);
  61                va = buf;
  62        } else {
  63                len = strnlen(va, trace->len);
  64        }
  65
  66        return simple_read_from_buffer(userbuf, count, ppos, va, len);
  67}
  68
  69static const struct file_operations trace_rproc_ops = {
  70        .read = rproc_trace_read,
  71        .open = simple_open,
  72        .llseek = generic_file_llseek,
  73};
  74
  75/* expose the name of the remote processor via debugfs */
  76static ssize_t rproc_name_read(struct file *filp, char __user *userbuf,
  77                               size_t count, loff_t *ppos)
  78{
  79        struct rproc *rproc = filp->private_data;
  80        /* need room for the name, a newline and a terminating null */
  81        char buf[100];
  82        int i;
  83
  84        i = scnprintf(buf, sizeof(buf), "%.98s\n", rproc->name);
  85
  86        return simple_read_from_buffer(userbuf, count, ppos, buf, i);
  87}
  88
  89static const struct file_operations rproc_name_ops = {
  90        .read = rproc_name_read,
  91        .open = simple_open,
  92        .llseek = generic_file_llseek,
  93};
  94
  95/* expose recovery flag via debugfs */
  96static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf,
  97                                   size_t count, loff_t *ppos)
  98{
  99        struct rproc *rproc = filp->private_data;
 100        char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n";
 101
 102        return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
 103}
 104
 105/*
 106 * By writing to the 'recovery' debugfs entry, we control the behavior of the
 107 * recovery mechanism dynamically. The default value of this entry is "enabled".
 108 *
 109 * The 'recovery' debugfs entry supports these commands:
 110 *
 111 * enabled:     When enabled, the remote processor will be automatically
 112 *              recovered whenever it crashes. Moreover, if the remote
 113 *              processor crashes while recovery is disabled, it will
 114 *              be automatically recovered too as soon as recovery is enabled.
 115 *
 116 * disabled:    When disabled, a remote processor will remain in a crashed
 117 *              state if it crashes. This is useful for debugging purposes;
 118 *              without it, debugging a crash is substantially harder.
 119 *
 120 * recover:     This function will trigger an immediate recovery if the
 121 *              remote processor is in a crashed state, without changing
 122 *              or checking the recovery state (enabled/disabled).
 123 *              This is useful during debugging sessions, when one expects
 124 *              additional crashes to happen after enabling recovery. In this
 125 *              case, enabling recovery will make it hard to debug subsequent
 126 *              crashes, so it's recommended to keep recovery disabled, and
 127 *              instead use the "recover" command as needed.
 128 */
 129static ssize_t
 130rproc_recovery_write(struct file *filp, const char __user *user_buf,
 131                     size_t count, loff_t *ppos)
 132{
 133        struct rproc *rproc = filp->private_data;
 134        char buf[10];
 135        int ret;
 136
 137        if (count < 1 || count > sizeof(buf))
 138                return -EINVAL;
 139
 140        ret = copy_from_user(buf, user_buf, count);
 141        if (ret)
 142                return -EFAULT;
 143
 144        /* remove end of line */
 145        if (buf[count - 1] == '\n')
 146                buf[count - 1] = '\0';
 147
 148        if (!strncmp(buf, "enabled", count)) {
 149                rproc->recovery_disabled = false;
 150                /* if rproc has crashed, trigger recovery */
 151                if (rproc->state == RPROC_CRASHED)
 152                        rproc_trigger_recovery(rproc);
 153        } else if (!strncmp(buf, "disabled", count)) {
 154                rproc->recovery_disabled = true;
 155        } else if (!strncmp(buf, "recover", count)) {
 156                /* if rproc has crashed, trigger recovery */
 157                if (rproc->state == RPROC_CRASHED)
 158                        rproc_trigger_recovery(rproc);
 159        }
 160
 161        return count;
 162}
 163
 164static const struct file_operations rproc_recovery_ops = {
 165        .read = rproc_recovery_read,
 166        .write = rproc_recovery_write,
 167        .open = simple_open,
 168        .llseek = generic_file_llseek,
 169};
 170
 171/* expose the crash trigger via debugfs */
 172static ssize_t
 173rproc_crash_write(struct file *filp, const char __user *user_buf,
 174                  size_t count, loff_t *ppos)
 175{
 176        struct rproc *rproc = filp->private_data;
 177        unsigned int type;
 178        int ret;
 179
 180        ret = kstrtouint_from_user(user_buf, count, 0, &type);
 181        if (ret < 0)
 182                return ret;
 183
 184        rproc_report_crash(rproc, type);
 185
 186        return count;
 187}
 188
 189static const struct file_operations rproc_crash_ops = {
 190        .write = rproc_crash_write,
 191        .open = simple_open,
 192        .llseek = generic_file_llseek,
 193};
 194
 195/* Expose resource table content via debugfs */
 196static int rproc_rsc_table_show(struct seq_file *seq, void *p)
 197{
 198        static const char * const types[] = {"carveout", "devmem", "trace", "vdev"};
 199        struct rproc *rproc = seq->private;
 200        struct resource_table *table = rproc->table_ptr;
 201        struct fw_rsc_carveout *c;
 202        struct fw_rsc_devmem *d;
 203        struct fw_rsc_trace *t;
 204        struct fw_rsc_vdev *v;
 205        int i, j;
 206
 207        if (!table) {
 208                seq_puts(seq, "No resource table found\n");
 209                return 0;
 210        }
 211
 212        for (i = 0; i < table->num; i++) {
 213                int offset = table->offset[i];
 214                struct fw_rsc_hdr *hdr = (void *)table + offset;
 215                void *rsc = (void *)hdr + sizeof(*hdr);
 216
 217                switch (hdr->type) {
 218                case RSC_CARVEOUT:
 219                        c = rsc;
 220                        seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
 221                        seq_printf(seq, "  Device Address 0x%x\n", c->da);
 222                        seq_printf(seq, "  Physical Address 0x%x\n", c->pa);
 223                        seq_printf(seq, "  Length 0x%x Bytes\n", c->len);
 224                        seq_printf(seq, "  Flags 0x%x\n", c->flags);
 225                        seq_printf(seq, "  Reserved (should be zero) [%d]\n", c->reserved);
 226                        seq_printf(seq, "  Name %s\n\n", c->name);
 227                        break;
 228                case RSC_DEVMEM:
 229                        d = rsc;
 230                        seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
 231                        seq_printf(seq, "  Device Address 0x%x\n", d->da);
 232                        seq_printf(seq, "  Physical Address 0x%x\n", d->pa);
 233                        seq_printf(seq, "  Length 0x%x Bytes\n", d->len);
 234                        seq_printf(seq, "  Flags 0x%x\n", d->flags);
 235                        seq_printf(seq, "  Reserved (should be zero) [%d]\n", d->reserved);
 236                        seq_printf(seq, "  Name %s\n\n", d->name);
 237                        break;
 238                case RSC_TRACE:
 239                        t = rsc;
 240                        seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
 241                        seq_printf(seq, "  Device Address 0x%x\n", t->da);
 242                        seq_printf(seq, "  Length 0x%x Bytes\n", t->len);
 243                        seq_printf(seq, "  Reserved (should be zero) [%d]\n", t->reserved);
 244                        seq_printf(seq, "  Name %s\n\n", t->name);
 245                        break;
 246                case RSC_VDEV:
 247                        v = rsc;
 248                        seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
 249
 250                        seq_printf(seq, "  ID %d\n", v->id);
 251                        seq_printf(seq, "  Notify ID %d\n", v->notifyid);
 252                        seq_printf(seq, "  Device features 0x%x\n", v->dfeatures);
 253                        seq_printf(seq, "  Guest features 0x%x\n", v->gfeatures);
 254                        seq_printf(seq, "  Config length 0x%x\n", v->config_len);
 255                        seq_printf(seq, "  Status 0x%x\n", v->status);
 256                        seq_printf(seq, "  Number of vrings %d\n", v->num_of_vrings);
 257                        seq_printf(seq, "  Reserved (should be zero) [%d][%d]\n\n",
 258                                   v->reserved[0], v->reserved[1]);
 259
 260                        for (j = 0; j < v->num_of_vrings; j++) {
 261                                seq_printf(seq, "  Vring %d\n", j);
 262                                seq_printf(seq, "    Device Address 0x%x\n", v->vring[j].da);
 263                                seq_printf(seq, "    Alignment %d\n", v->vring[j].align);
 264                                seq_printf(seq, "    Number of buffers %d\n", v->vring[j].num);
 265                                seq_printf(seq, "    Notify ID %d\n", v->vring[j].notifyid);
 266                                seq_printf(seq, "    Physical Address 0x%x\n\n",
 267                                           v->vring[j].pa);
 268                        }
 269                        break;
 270                default:
 271                        seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n",
 272                                   hdr->type, hdr);
 273                        break;
 274                }
 275        }
 276
 277        return 0;
 278}
 279
 280static int rproc_rsc_table_open(struct inode *inode, struct file *file)
 281{
 282        return single_open(file, rproc_rsc_table_show, inode->i_private);
 283}
 284
 285static const struct file_operations rproc_rsc_table_ops = {
 286        .open           = rproc_rsc_table_open,
 287        .read           = seq_read,
 288        .llseek         = seq_lseek,
 289        .release        = single_release,
 290};
 291
 292/* Expose carveout content via debugfs */
 293static int rproc_carveouts_show(struct seq_file *seq, void *p)
 294{
 295        struct rproc *rproc = seq->private;
 296        struct rproc_mem_entry *carveout;
 297
 298        list_for_each_entry(carveout, &rproc->carveouts, node) {
 299                seq_puts(seq, "Carveout memory entry:\n");
 300                seq_printf(seq, "\tName: %s\n", carveout->name);
 301                seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
 302                seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
 303                seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
 304                seq_printf(seq, "\tLength: 0x%x Bytes\n\n", carveout->len);
 305        }
 306
 307        return 0;
 308}
 309
 310static int rproc_carveouts_open(struct inode *inode, struct file *file)
 311{
 312        return single_open(file, rproc_carveouts_show, inode->i_private);
 313}
 314
 315static const struct file_operations rproc_carveouts_ops = {
 316        .open           = rproc_carveouts_open,
 317        .read           = seq_read,
 318        .llseek         = seq_lseek,
 319        .release        = single_release,
 320};
 321
 322void rproc_remove_trace_file(struct dentry *tfile)
 323{
 324        debugfs_remove(tfile);
 325}
 326
 327struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
 328                                       struct rproc_debug_trace *trace)
 329{
 330        struct dentry *tfile;
 331
 332        tfile = debugfs_create_file(name, 0400, rproc->dbg_dir, trace,
 333                                    &trace_rproc_ops);
 334        if (!tfile) {
 335                dev_err(&rproc->dev, "failed to create debugfs trace entry\n");
 336                return NULL;
 337        }
 338
 339        return tfile;
 340}
 341
 342void rproc_delete_debug_dir(struct rproc *rproc)
 343{
 344        if (!rproc->dbg_dir)
 345                return;
 346
 347        debugfs_remove_recursive(rproc->dbg_dir);
 348}
 349
 350void rproc_create_debug_dir(struct rproc *rproc)
 351{
 352        struct device *dev = &rproc->dev;
 353
 354        if (!rproc_dbg)
 355                return;
 356
 357        rproc->dbg_dir = debugfs_create_dir(dev_name(dev), rproc_dbg);
 358        if (!rproc->dbg_dir)
 359                return;
 360
 361        debugfs_create_file("name", 0400, rproc->dbg_dir,
 362                            rproc, &rproc_name_ops);
 363        debugfs_create_file("recovery", 0400, rproc->dbg_dir,
 364                            rproc, &rproc_recovery_ops);
 365        debugfs_create_file("crash", 0200, rproc->dbg_dir,
 366                            rproc, &rproc_crash_ops);
 367        debugfs_create_file("resource_table", 0400, rproc->dbg_dir,
 368                            rproc, &rproc_rsc_table_ops);
 369        debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir,
 370                            rproc, &rproc_carveouts_ops);
 371}
 372
 373void __init rproc_init_debugfs(void)
 374{
 375        if (debugfs_initialized()) {
 376                rproc_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
 377                if (!rproc_dbg)
 378                        pr_err("can't create debugfs dir\n");
 379        }
 380}
 381
 382void __exit rproc_exit_debugfs(void)
 383{
 384        debugfs_remove(rproc_dbg);
 385}
 386