162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Remote Processor Framework 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc. 662306a36Sopenharmony_ci * Copyright (C) 2011 Google, Inc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Ohad Ben-Cohen <ohad@wizery.com> 962306a36Sopenharmony_ci * Mark Grosen <mgrosen@ti.com> 1062306a36Sopenharmony_ci * Brian Swetland <swetland@google.com> 1162306a36Sopenharmony_ci * Fernando Guzman Lugo <fernando.lugo@ti.com> 1262306a36Sopenharmony_ci * Suman Anna <s-anna@ti.com> 1362306a36Sopenharmony_ci * Robert Tivy <rtivy@ti.com> 1462306a36Sopenharmony_ci * Armando Uribe De Leon <x0095078@ti.com> 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/debugfs.h> 2162306a36Sopenharmony_ci#include <linux/remoteproc.h> 2262306a36Sopenharmony_ci#include <linux/device.h> 2362306a36Sopenharmony_ci#include <linux/uaccess.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "remoteproc_internal.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* remoteproc debugfs parent dir */ 2862306a36Sopenharmony_cistatic struct dentry *rproc_dbg; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * A coredump-configuration-to-string lookup table, for exposing a 3262306a36Sopenharmony_ci * human readable configuration via debugfs. Always keep in sync with 3362306a36Sopenharmony_ci * enum rproc_coredump_mechanism 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic const char * const rproc_coredump_str[] = { 3662306a36Sopenharmony_ci [RPROC_COREDUMP_DISABLED] = "disabled", 3762306a36Sopenharmony_ci [RPROC_COREDUMP_ENABLED] = "enabled", 3862306a36Sopenharmony_ci [RPROC_COREDUMP_INLINE] = "inline", 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Expose the current coredump configuration via debugfs */ 4262306a36Sopenharmony_cistatic ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, 4362306a36Sopenharmony_ci size_t count, loff_t *ppos) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct rproc *rproc = filp->private_data; 4662306a36Sopenharmony_ci char buf[20]; 4762306a36Sopenharmony_ci int len; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%s\n", 5062306a36Sopenharmony_ci rproc_coredump_str[rproc->dump_conf]); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return simple_read_from_buffer(userbuf, count, ppos, buf, len); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci * By writing to the 'coredump' debugfs entry, we control the behavior of the 5762306a36Sopenharmony_ci * coredump mechanism dynamically. The default value of this entry is "disabled". 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * The 'coredump' debugfs entry supports these commands: 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * disabled: By default coredump collection is disabled. Recovery will 6262306a36Sopenharmony_ci * proceed without collecting any dump. 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * enabled: When the remoteproc crashes the entire coredump will be copied 6562306a36Sopenharmony_ci * to a separate buffer and exposed to userspace. 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * inline: The coredump will not be copied to a separate buffer and the 6862306a36Sopenharmony_ci * recovery process will have to wait until data is read by 6962306a36Sopenharmony_ci * userspace. But this avoid usage of extra memory. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_cistatic ssize_t rproc_coredump_write(struct file *filp, 7262306a36Sopenharmony_ci const char __user *user_buf, size_t count, 7362306a36Sopenharmony_ci loff_t *ppos) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct rproc *rproc = filp->private_data; 7662306a36Sopenharmony_ci int ret, err = 0; 7762306a36Sopenharmony_ci char buf[20]; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (count < 1 || count > sizeof(buf)) 8062306a36Sopenharmony_ci return -EINVAL; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ret = copy_from_user(buf, user_buf, count); 8362306a36Sopenharmony_ci if (ret) 8462306a36Sopenharmony_ci return -EFAULT; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* remove end of line */ 8762306a36Sopenharmony_ci if (buf[count - 1] == '\n') 8862306a36Sopenharmony_ci buf[count - 1] = '\0'; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (rproc->state == RPROC_CRASHED) { 9162306a36Sopenharmony_ci dev_err(&rproc->dev, "can't change coredump configuration\n"); 9262306a36Sopenharmony_ci err = -EBUSY; 9362306a36Sopenharmony_ci goto out; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (!strncmp(buf, "disabled", count)) { 9762306a36Sopenharmony_ci rproc->dump_conf = RPROC_COREDUMP_DISABLED; 9862306a36Sopenharmony_ci } else if (!strncmp(buf, "enabled", count)) { 9962306a36Sopenharmony_ci rproc->dump_conf = RPROC_COREDUMP_ENABLED; 10062306a36Sopenharmony_ci } else if (!strncmp(buf, "inline", count)) { 10162306a36Sopenharmony_ci rproc->dump_conf = RPROC_COREDUMP_INLINE; 10262306a36Sopenharmony_ci } else { 10362306a36Sopenharmony_ci dev_err(&rproc->dev, "Invalid coredump configuration\n"); 10462306a36Sopenharmony_ci err = -EINVAL; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ciout: 10762306a36Sopenharmony_ci return err ? err : count; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic const struct file_operations rproc_coredump_fops = { 11162306a36Sopenharmony_ci .read = rproc_coredump_read, 11262306a36Sopenharmony_ci .write = rproc_coredump_write, 11362306a36Sopenharmony_ci .open = simple_open, 11462306a36Sopenharmony_ci .llseek = generic_file_llseek, 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * Some remote processors may support dumping trace logs into a shared 11962306a36Sopenharmony_ci * memory buffer. We expose this trace buffer using debugfs, so users 12062306a36Sopenharmony_ci * can easily tell what's going on remotely. 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * We will most probably improve the rproc tracing facilities later on, 12362306a36Sopenharmony_ci * but this kind of lightweight and simple mechanism is always good to have, 12462306a36Sopenharmony_ci * as it provides very early tracing with little to no dependencies at all. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistatic ssize_t rproc_trace_read(struct file *filp, char __user *userbuf, 12762306a36Sopenharmony_ci size_t count, loff_t *ppos) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct rproc_debug_trace *data = filp->private_data; 13062306a36Sopenharmony_ci struct rproc_mem_entry *trace = &data->trace_mem; 13162306a36Sopenharmony_ci void *va; 13262306a36Sopenharmony_ci char buf[100]; 13362306a36Sopenharmony_ci int len; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci va = rproc_da_to_va(data->rproc, trace->da, trace->len, NULL); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (!va) { 13862306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "Trace %s not available\n", 13962306a36Sopenharmony_ci trace->name); 14062306a36Sopenharmony_ci va = buf; 14162306a36Sopenharmony_ci } else { 14262306a36Sopenharmony_ci len = strnlen(va, trace->len); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return simple_read_from_buffer(userbuf, count, ppos, va, len); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic const struct file_operations trace_rproc_ops = { 14962306a36Sopenharmony_ci .read = rproc_trace_read, 15062306a36Sopenharmony_ci .open = simple_open, 15162306a36Sopenharmony_ci .llseek = generic_file_llseek, 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* expose the name of the remote processor via debugfs */ 15562306a36Sopenharmony_cistatic ssize_t rproc_name_read(struct file *filp, char __user *userbuf, 15662306a36Sopenharmony_ci size_t count, loff_t *ppos) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct rproc *rproc = filp->private_data; 15962306a36Sopenharmony_ci /* need room for the name, a newline and a terminating null */ 16062306a36Sopenharmony_ci char buf[100]; 16162306a36Sopenharmony_ci int i; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci i = scnprintf(buf, sizeof(buf), "%.98s\n", rproc->name); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return simple_read_from_buffer(userbuf, count, ppos, buf, i); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic const struct file_operations rproc_name_ops = { 16962306a36Sopenharmony_ci .read = rproc_name_read, 17062306a36Sopenharmony_ci .open = simple_open, 17162306a36Sopenharmony_ci .llseek = generic_file_llseek, 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* expose recovery flag via debugfs */ 17562306a36Sopenharmony_cistatic ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, 17662306a36Sopenharmony_ci size_t count, loff_t *ppos) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct rproc *rproc = filp->private_data; 17962306a36Sopenharmony_ci char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n"; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* 18562306a36Sopenharmony_ci * By writing to the 'recovery' debugfs entry, we control the behavior of the 18662306a36Sopenharmony_ci * recovery mechanism dynamically. The default value of this entry is "enabled". 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * The 'recovery' debugfs entry supports these commands: 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * enabled: When enabled, the remote processor will be automatically 19162306a36Sopenharmony_ci * recovered whenever it crashes. Moreover, if the remote 19262306a36Sopenharmony_ci * processor crashes while recovery is disabled, it will 19362306a36Sopenharmony_ci * be automatically recovered too as soon as recovery is enabled. 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * disabled: When disabled, a remote processor will remain in a crashed 19662306a36Sopenharmony_ci * state if it crashes. This is useful for debugging purposes; 19762306a36Sopenharmony_ci * without it, debugging a crash is substantially harder. 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * recover: This function will trigger an immediate recovery if the 20062306a36Sopenharmony_ci * remote processor is in a crashed state, without changing 20162306a36Sopenharmony_ci * or checking the recovery state (enabled/disabled). 20262306a36Sopenharmony_ci * This is useful during debugging sessions, when one expects 20362306a36Sopenharmony_ci * additional crashes to happen after enabling recovery. In this 20462306a36Sopenharmony_ci * case, enabling recovery will make it hard to debug subsequent 20562306a36Sopenharmony_ci * crashes, so it's recommended to keep recovery disabled, and 20662306a36Sopenharmony_ci * instead use the "recover" command as needed. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic ssize_t 20962306a36Sopenharmony_cirproc_recovery_write(struct file *filp, const char __user *user_buf, 21062306a36Sopenharmony_ci size_t count, loff_t *ppos) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct rproc *rproc = filp->private_data; 21362306a36Sopenharmony_ci char buf[10]; 21462306a36Sopenharmony_ci int ret; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (count < 1 || count > sizeof(buf)) 21762306a36Sopenharmony_ci return -EINVAL; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ret = copy_from_user(buf, user_buf, count); 22062306a36Sopenharmony_ci if (ret) 22162306a36Sopenharmony_ci return -EFAULT; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* remove end of line */ 22462306a36Sopenharmony_ci if (buf[count - 1] == '\n') 22562306a36Sopenharmony_ci buf[count - 1] = '\0'; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (!strncmp(buf, "enabled", count)) { 22862306a36Sopenharmony_ci /* change the flag and begin the recovery process if needed */ 22962306a36Sopenharmony_ci rproc->recovery_disabled = false; 23062306a36Sopenharmony_ci rproc_trigger_recovery(rproc); 23162306a36Sopenharmony_ci } else if (!strncmp(buf, "disabled", count)) { 23262306a36Sopenharmony_ci rproc->recovery_disabled = true; 23362306a36Sopenharmony_ci } else if (!strncmp(buf, "recover", count)) { 23462306a36Sopenharmony_ci /* begin the recovery process without changing the flag */ 23562306a36Sopenharmony_ci rproc_trigger_recovery(rproc); 23662306a36Sopenharmony_ci } else { 23762306a36Sopenharmony_ci return -EINVAL; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return count; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic const struct file_operations rproc_recovery_ops = { 24462306a36Sopenharmony_ci .read = rproc_recovery_read, 24562306a36Sopenharmony_ci .write = rproc_recovery_write, 24662306a36Sopenharmony_ci .open = simple_open, 24762306a36Sopenharmony_ci .llseek = generic_file_llseek, 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* expose the crash trigger via debugfs */ 25162306a36Sopenharmony_cistatic ssize_t 25262306a36Sopenharmony_cirproc_crash_write(struct file *filp, const char __user *user_buf, 25362306a36Sopenharmony_ci size_t count, loff_t *ppos) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct rproc *rproc = filp->private_data; 25662306a36Sopenharmony_ci unsigned int type; 25762306a36Sopenharmony_ci int ret; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci ret = kstrtouint_from_user(user_buf, count, 0, &type); 26062306a36Sopenharmony_ci if (ret < 0) 26162306a36Sopenharmony_ci return ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci rproc_report_crash(rproc, type); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return count; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic const struct file_operations rproc_crash_ops = { 26962306a36Sopenharmony_ci .write = rproc_crash_write, 27062306a36Sopenharmony_ci .open = simple_open, 27162306a36Sopenharmony_ci .llseek = generic_file_llseek, 27262306a36Sopenharmony_ci}; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/* Expose resource table content via debugfs */ 27562306a36Sopenharmony_cistatic int rproc_rsc_table_show(struct seq_file *seq, void *p) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci static const char * const types[] = {"carveout", "devmem", "trace", "vdev"}; 27862306a36Sopenharmony_ci struct rproc *rproc = seq->private; 27962306a36Sopenharmony_ci struct resource_table *table = rproc->table_ptr; 28062306a36Sopenharmony_ci struct fw_rsc_carveout *c; 28162306a36Sopenharmony_ci struct fw_rsc_devmem *d; 28262306a36Sopenharmony_ci struct fw_rsc_trace *t; 28362306a36Sopenharmony_ci struct fw_rsc_vdev *v; 28462306a36Sopenharmony_ci int i, j; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (!table) { 28762306a36Sopenharmony_ci seq_puts(seq, "No resource table found\n"); 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci for (i = 0; i < table->num; i++) { 29262306a36Sopenharmony_ci int offset = table->offset[i]; 29362306a36Sopenharmony_ci struct fw_rsc_hdr *hdr = (void *)table + offset; 29462306a36Sopenharmony_ci void *rsc = (void *)hdr + sizeof(*hdr); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci switch (hdr->type) { 29762306a36Sopenharmony_ci case RSC_CARVEOUT: 29862306a36Sopenharmony_ci c = rsc; 29962306a36Sopenharmony_ci seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]); 30062306a36Sopenharmony_ci seq_printf(seq, " Device Address 0x%x\n", c->da); 30162306a36Sopenharmony_ci seq_printf(seq, " Physical Address 0x%x\n", c->pa); 30262306a36Sopenharmony_ci seq_printf(seq, " Length 0x%x Bytes\n", c->len); 30362306a36Sopenharmony_ci seq_printf(seq, " Flags 0x%x\n", c->flags); 30462306a36Sopenharmony_ci seq_printf(seq, " Reserved (should be zero) [%d]\n", c->reserved); 30562306a36Sopenharmony_ci seq_printf(seq, " Name %s\n\n", c->name); 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci case RSC_DEVMEM: 30862306a36Sopenharmony_ci d = rsc; 30962306a36Sopenharmony_ci seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]); 31062306a36Sopenharmony_ci seq_printf(seq, " Device Address 0x%x\n", d->da); 31162306a36Sopenharmony_ci seq_printf(seq, " Physical Address 0x%x\n", d->pa); 31262306a36Sopenharmony_ci seq_printf(seq, " Length 0x%x Bytes\n", d->len); 31362306a36Sopenharmony_ci seq_printf(seq, " Flags 0x%x\n", d->flags); 31462306a36Sopenharmony_ci seq_printf(seq, " Reserved (should be zero) [%d]\n", d->reserved); 31562306a36Sopenharmony_ci seq_printf(seq, " Name %s\n\n", d->name); 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci case RSC_TRACE: 31862306a36Sopenharmony_ci t = rsc; 31962306a36Sopenharmony_ci seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]); 32062306a36Sopenharmony_ci seq_printf(seq, " Device Address 0x%x\n", t->da); 32162306a36Sopenharmony_ci seq_printf(seq, " Length 0x%x Bytes\n", t->len); 32262306a36Sopenharmony_ci seq_printf(seq, " Reserved (should be zero) [%d]\n", t->reserved); 32362306a36Sopenharmony_ci seq_printf(seq, " Name %s\n\n", t->name); 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case RSC_VDEV: 32662306a36Sopenharmony_ci v = rsc; 32762306a36Sopenharmony_ci seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci seq_printf(seq, " ID %d\n", v->id); 33062306a36Sopenharmony_ci seq_printf(seq, " Notify ID %d\n", v->notifyid); 33162306a36Sopenharmony_ci seq_printf(seq, " Device features 0x%x\n", v->dfeatures); 33262306a36Sopenharmony_ci seq_printf(seq, " Guest features 0x%x\n", v->gfeatures); 33362306a36Sopenharmony_ci seq_printf(seq, " Config length 0x%x\n", v->config_len); 33462306a36Sopenharmony_ci seq_printf(seq, " Status 0x%x\n", v->status); 33562306a36Sopenharmony_ci seq_printf(seq, " Number of vrings %d\n", v->num_of_vrings); 33662306a36Sopenharmony_ci seq_printf(seq, " Reserved (should be zero) [%d][%d]\n\n", 33762306a36Sopenharmony_ci v->reserved[0], v->reserved[1]); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci for (j = 0; j < v->num_of_vrings; j++) { 34062306a36Sopenharmony_ci seq_printf(seq, " Vring %d\n", j); 34162306a36Sopenharmony_ci seq_printf(seq, " Device Address 0x%x\n", v->vring[j].da); 34262306a36Sopenharmony_ci seq_printf(seq, " Alignment %d\n", v->vring[j].align); 34362306a36Sopenharmony_ci seq_printf(seq, " Number of buffers %d\n", v->vring[j].num); 34462306a36Sopenharmony_ci seq_printf(seq, " Notify ID %d\n", v->vring[j].notifyid); 34562306a36Sopenharmony_ci seq_printf(seq, " Physical Address 0x%x\n\n", 34662306a36Sopenharmony_ci v->vring[j].pa); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci default: 35062306a36Sopenharmony_ci seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n", 35162306a36Sopenharmony_ci hdr->type, hdr); 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rproc_rsc_table); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/* Expose carveout content via debugfs */ 36262306a36Sopenharmony_cistatic int rproc_carveouts_show(struct seq_file *seq, void *p) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct rproc *rproc = seq->private; 36562306a36Sopenharmony_ci struct rproc_mem_entry *carveout; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci list_for_each_entry(carveout, &rproc->carveouts, node) { 36862306a36Sopenharmony_ci seq_puts(seq, "Carveout memory entry:\n"); 36962306a36Sopenharmony_ci seq_printf(seq, "\tName: %s\n", carveout->name); 37062306a36Sopenharmony_ci seq_printf(seq, "\tVirtual address: %pK\n", carveout->va); 37162306a36Sopenharmony_ci seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma); 37262306a36Sopenharmony_ci seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da); 37362306a36Sopenharmony_ci seq_printf(seq, "\tLength: 0x%zx Bytes\n\n", carveout->len); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rproc_carveouts); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_civoid rproc_remove_trace_file(struct dentry *tfile) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci debugfs_remove(tfile); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistruct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, 38762306a36Sopenharmony_ci struct rproc_debug_trace *trace) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci return debugfs_create_file(name, 0400, rproc->dbg_dir, trace, 39062306a36Sopenharmony_ci &trace_rproc_ops); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_civoid rproc_delete_debug_dir(struct rproc *rproc) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci debugfs_remove_recursive(rproc->dbg_dir); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_civoid rproc_create_debug_dir(struct rproc *rproc) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct device *dev = &rproc->dev; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (!rproc_dbg) 40362306a36Sopenharmony_ci return; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci rproc->dbg_dir = debugfs_create_dir(dev_name(dev), rproc_dbg); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci debugfs_create_file("name", 0400, rproc->dbg_dir, 40862306a36Sopenharmony_ci rproc, &rproc_name_ops); 40962306a36Sopenharmony_ci debugfs_create_file("recovery", 0600, rproc->dbg_dir, 41062306a36Sopenharmony_ci rproc, &rproc_recovery_ops); 41162306a36Sopenharmony_ci debugfs_create_file("crash", 0200, rproc->dbg_dir, 41262306a36Sopenharmony_ci rproc, &rproc_crash_ops); 41362306a36Sopenharmony_ci debugfs_create_file("resource_table", 0400, rproc->dbg_dir, 41462306a36Sopenharmony_ci rproc, &rproc_rsc_table_fops); 41562306a36Sopenharmony_ci debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, 41662306a36Sopenharmony_ci rproc, &rproc_carveouts_fops); 41762306a36Sopenharmony_ci debugfs_create_file("coredump", 0600, rproc->dbg_dir, 41862306a36Sopenharmony_ci rproc, &rproc_coredump_fops); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_civoid __init rproc_init_debugfs(void) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci if (debugfs_initialized()) 42462306a36Sopenharmony_ci rproc_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_civoid __exit rproc_exit_debugfs(void) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci debugfs_remove(rproc_dbg); 43062306a36Sopenharmony_ci} 431