linux/drivers/bus/mhi/core/debugfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
   4 *
   5 */
   6
   7#include <linux/debugfs.h>
   8#include <linux/device.h>
   9#include <linux/interrupt.h>
  10#include <linux/list.h>
  11#include <linux/mhi.h>
  12#include <linux/module.h>
  13#include "internal.h"
  14
  15static int mhi_debugfs_states_show(struct seq_file *m, void *d)
  16{
  17        struct mhi_controller *mhi_cntrl = m->private;
  18
  19        /* states */
  20        seq_printf(m, "PM state: %s Device: %s MHI state: %s EE: %s wake: %s\n",
  21                   to_mhi_pm_state_str(mhi_cntrl->pm_state),
  22                   mhi_is_active(mhi_cntrl) ? "Active" : "Inactive",
  23                   TO_MHI_STATE_STR(mhi_cntrl->dev_state),
  24                   TO_MHI_EXEC_STR(mhi_cntrl->ee),
  25                   mhi_cntrl->wake_set ? "true" : "false");
  26
  27        /* counters */
  28        seq_printf(m, "M0: %u M2: %u M3: %u", mhi_cntrl->M0, mhi_cntrl->M2,
  29                   mhi_cntrl->M3);
  30
  31        seq_printf(m, " device wake: %u pending packets: %u\n",
  32                   atomic_read(&mhi_cntrl->dev_wake),
  33                   atomic_read(&mhi_cntrl->pending_pkts));
  34
  35        return 0;
  36}
  37
  38static int mhi_debugfs_events_show(struct seq_file *m, void *d)
  39{
  40        struct mhi_controller *mhi_cntrl = m->private;
  41        struct mhi_event *mhi_event;
  42        struct mhi_event_ctxt *er_ctxt;
  43        int i;
  44
  45        if (!mhi_is_active(mhi_cntrl)) {
  46                seq_puts(m, "Device not ready\n");
  47                return -ENODEV;
  48        }
  49
  50        er_ctxt = mhi_cntrl->mhi_ctxt->er_ctxt;
  51        mhi_event = mhi_cntrl->mhi_event;
  52        for (i = 0; i < mhi_cntrl->total_ev_rings;
  53                                                i++, er_ctxt++, mhi_event++) {
  54                struct mhi_ring *ring = &mhi_event->ring;
  55
  56                if (mhi_event->offload_ev) {
  57                        seq_printf(m, "Index: %d is an offload event ring\n",
  58                                   i);
  59                        continue;
  60                }
  61
  62                seq_printf(m, "Index: %d intmod count: %lu time: %lu",
  63                           i, (er_ctxt->intmod & EV_CTX_INTMODC_MASK) >>
  64                           EV_CTX_INTMODC_SHIFT,
  65                           (er_ctxt->intmod & EV_CTX_INTMODT_MASK) >>
  66                           EV_CTX_INTMODT_SHIFT);
  67
  68                seq_printf(m, " base: 0x%0llx len: 0x%llx", er_ctxt->rbase,
  69                           er_ctxt->rlen);
  70
  71                seq_printf(m, " rp: 0x%llx wp: 0x%llx", er_ctxt->rp,
  72                           er_ctxt->wp);
  73
  74                seq_printf(m, " local rp: 0x%pK db: 0x%pad\n", ring->rp,
  75                           &mhi_event->db_cfg.db_val);
  76        }
  77
  78        return 0;
  79}
  80
  81static int mhi_debugfs_channels_show(struct seq_file *m, void *d)
  82{
  83        struct mhi_controller *mhi_cntrl = m->private;
  84        struct mhi_chan *mhi_chan;
  85        struct mhi_chan_ctxt *chan_ctxt;
  86        int i;
  87
  88        if (!mhi_is_active(mhi_cntrl)) {
  89                seq_puts(m, "Device not ready\n");
  90                return -ENODEV;
  91        }
  92
  93        mhi_chan = mhi_cntrl->mhi_chan;
  94        chan_ctxt = mhi_cntrl->mhi_ctxt->chan_ctxt;
  95        for (i = 0; i < mhi_cntrl->max_chan; i++, chan_ctxt++, mhi_chan++) {
  96                struct mhi_ring *ring = &mhi_chan->tre_ring;
  97
  98                if (mhi_chan->offload_ch) {
  99                        seq_printf(m, "%s(%u) is an offload channel\n",
 100                                   mhi_chan->name, mhi_chan->chan);
 101                        continue;
 102                }
 103
 104                if (!mhi_chan->mhi_dev)
 105                        continue;
 106
 107                seq_printf(m,
 108                           "%s(%u) state: 0x%lx brstmode: 0x%lx pollcfg: 0x%lx",
 109                           mhi_chan->name, mhi_chan->chan, (chan_ctxt->chcfg &
 110                           CHAN_CTX_CHSTATE_MASK) >> CHAN_CTX_CHSTATE_SHIFT,
 111                           (chan_ctxt->chcfg & CHAN_CTX_BRSTMODE_MASK) >>
 112                           CHAN_CTX_BRSTMODE_SHIFT, (chan_ctxt->chcfg &
 113                           CHAN_CTX_POLLCFG_MASK) >> CHAN_CTX_POLLCFG_SHIFT);
 114
 115                seq_printf(m, " type: 0x%x event ring: %u", chan_ctxt->chtype,
 116                           chan_ctxt->erindex);
 117
 118                seq_printf(m, " base: 0x%llx len: 0x%llx rp: 0x%llx wp: 0x%llx",
 119                           chan_ctxt->rbase, chan_ctxt->rlen, chan_ctxt->rp,
 120                           chan_ctxt->wp);
 121
 122                seq_printf(m, " local rp: 0x%pK local wp: 0x%pK db: 0x%pad\n",
 123                           ring->rp, ring->wp,
 124                           &mhi_chan->db_cfg.db_val);
 125        }
 126
 127        return 0;
 128}
 129
 130static int mhi_device_info_show(struct device *dev, void *data)
 131{
 132        struct mhi_device *mhi_dev;
 133
 134        if (dev->bus != &mhi_bus_type)
 135                return 0;
 136
 137        mhi_dev = to_mhi_device(dev);
 138
 139        seq_printf((struct seq_file *)data, "%s: type: %s dev_wake: %u",
 140                   mhi_dev->name, mhi_dev->dev_type ? "Controller" : "Transfer",
 141                   mhi_dev->dev_wake);
 142
 143        /* for transfer device types only */
 144        if (mhi_dev->dev_type == MHI_DEVICE_XFER)
 145                seq_printf((struct seq_file *)data, " channels: %u(UL)/%u(DL)",
 146                           mhi_dev->ul_chan_id, mhi_dev->dl_chan_id);
 147
 148        seq_puts((struct seq_file *)data, "\n");
 149
 150        return 0;
 151}
 152
 153static int mhi_debugfs_devices_show(struct seq_file *m, void *d)
 154{
 155        struct mhi_controller *mhi_cntrl = m->private;
 156
 157        if (!mhi_is_active(mhi_cntrl)) {
 158                seq_puts(m, "Device not ready\n");
 159                return -ENODEV;
 160        }
 161
 162        /* Show controller and client(s) info */
 163        mhi_device_info_show(&mhi_cntrl->mhi_dev->dev, m);
 164        device_for_each_child(&mhi_cntrl->mhi_dev->dev, m, mhi_device_info_show);
 165
 166        return 0;
 167}
 168
 169static int mhi_debugfs_regdump_show(struct seq_file *m, void *d)
 170{
 171        struct mhi_controller *mhi_cntrl = m->private;
 172        enum mhi_state state;
 173        enum mhi_ee_type ee;
 174        int i, ret = -EIO;
 175        u32 val;
 176        void __iomem *mhi_base = mhi_cntrl->regs;
 177        void __iomem *bhi_base = mhi_cntrl->bhi;
 178        void __iomem *bhie_base = mhi_cntrl->bhie;
 179        void __iomem *wake_db = mhi_cntrl->wake_db;
 180        struct {
 181                const char *name;
 182                int offset;
 183                void __iomem *base;
 184        } regs[] = {
 185                { "MHI_REGLEN", MHIREGLEN, mhi_base},
 186                { "MHI_VER", MHIVER, mhi_base},
 187                { "MHI_CFG", MHICFG, mhi_base},
 188                { "MHI_CTRL", MHICTRL, mhi_base},
 189                { "MHI_STATUS", MHISTATUS, mhi_base},
 190                { "MHI_WAKE_DB", 0, wake_db},
 191                { "BHI_EXECENV", BHI_EXECENV, bhi_base},
 192                { "BHI_STATUS", BHI_STATUS, bhi_base},
 193                { "BHI_ERRCODE", BHI_ERRCODE, bhi_base},
 194                { "BHI_ERRDBG1", BHI_ERRDBG1, bhi_base},
 195                { "BHI_ERRDBG2", BHI_ERRDBG2, bhi_base},
 196                { "BHI_ERRDBG3", BHI_ERRDBG3, bhi_base},
 197                { "BHIE_TXVEC_DB", BHIE_TXVECDB_OFFS, bhie_base},
 198                { "BHIE_TXVEC_STATUS", BHIE_TXVECSTATUS_OFFS, bhie_base},
 199                { "BHIE_RXVEC_DB", BHIE_RXVECDB_OFFS, bhie_base},
 200                { "BHIE_RXVEC_STATUS", BHIE_RXVECSTATUS_OFFS, bhie_base},
 201                { NULL },
 202        };
 203
 204        if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
 205                return ret;
 206
 207        seq_printf(m, "Host PM state: %s Device state: %s EE: %s\n",
 208                   to_mhi_pm_state_str(mhi_cntrl->pm_state),
 209                   TO_MHI_STATE_STR(mhi_cntrl->dev_state),
 210                   TO_MHI_EXEC_STR(mhi_cntrl->ee));
 211
 212        state = mhi_get_mhi_state(mhi_cntrl);
 213        ee = mhi_get_exec_env(mhi_cntrl);
 214        seq_printf(m, "Device EE: %s state: %s\n", TO_MHI_EXEC_STR(ee),
 215                   TO_MHI_STATE_STR(state));
 216
 217        for (i = 0; regs[i].name; i++) {
 218                if (!regs[i].base)
 219                        continue;
 220                ret = mhi_read_reg(mhi_cntrl, regs[i].base, regs[i].offset,
 221                                   &val);
 222                if (ret)
 223                        continue;
 224
 225                seq_printf(m, "%s: 0x%x\n", regs[i].name, val);
 226        }
 227
 228        return 0;
 229}
 230
 231static int mhi_debugfs_device_wake_show(struct seq_file *m, void *d)
 232{
 233        struct mhi_controller *mhi_cntrl = m->private;
 234        struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
 235
 236        if (!mhi_is_active(mhi_cntrl)) {
 237                seq_puts(m, "Device not ready\n");
 238                return -ENODEV;
 239        }
 240
 241        seq_printf(m,
 242                   "Wake count: %d\n%s\n", mhi_dev->dev_wake,
 243                   "Usage: echo get/put > device_wake to vote/unvote for M0");
 244
 245        return 0;
 246}
 247
 248static ssize_t mhi_debugfs_device_wake_write(struct file *file,
 249                                             const char __user *ubuf,
 250                                             size_t count, loff_t *ppos)
 251{
 252        struct seq_file *m = file->private_data;
 253        struct mhi_controller *mhi_cntrl = m->private;
 254        struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
 255        char buf[16];
 256        int ret = -EINVAL;
 257
 258        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 259                return -EFAULT;
 260
 261        if (!strncmp(buf, "get", 3)) {
 262                ret = mhi_device_get_sync(mhi_dev);
 263        } else if (!strncmp(buf, "put", 3)) {
 264                mhi_device_put(mhi_dev);
 265                ret = 0;
 266        }
 267
 268        return ret ? ret : count;
 269}
 270
 271static int mhi_debugfs_timeout_ms_show(struct seq_file *m, void *d)
 272{
 273        struct mhi_controller *mhi_cntrl = m->private;
 274
 275        seq_printf(m, "%u ms\n", mhi_cntrl->timeout_ms);
 276
 277        return 0;
 278}
 279
 280static ssize_t mhi_debugfs_timeout_ms_write(struct file *file,
 281                                            const char __user *ubuf,
 282                                            size_t count, loff_t *ppos)
 283{
 284        struct seq_file *m = file->private_data;
 285        struct mhi_controller *mhi_cntrl = m->private;
 286        u32 timeout_ms;
 287
 288        if (kstrtou32_from_user(ubuf, count, 0, &timeout_ms))
 289                return -EINVAL;
 290
 291        mhi_cntrl->timeout_ms = timeout_ms;
 292
 293        return count;
 294}
 295
 296static int mhi_debugfs_states_open(struct inode *inode, struct file *fp)
 297{
 298        return single_open(fp, mhi_debugfs_states_show, inode->i_private);
 299}
 300
 301static int mhi_debugfs_events_open(struct inode *inode, struct file *fp)
 302{
 303        return single_open(fp, mhi_debugfs_events_show, inode->i_private);
 304}
 305
 306static int mhi_debugfs_channels_open(struct inode *inode, struct file *fp)
 307{
 308        return single_open(fp, mhi_debugfs_channels_show, inode->i_private);
 309}
 310
 311static int mhi_debugfs_devices_open(struct inode *inode, struct file *fp)
 312{
 313        return single_open(fp, mhi_debugfs_devices_show, inode->i_private);
 314}
 315
 316static int mhi_debugfs_regdump_open(struct inode *inode, struct file *fp)
 317{
 318        return single_open(fp, mhi_debugfs_regdump_show, inode->i_private);
 319}
 320
 321static int mhi_debugfs_device_wake_open(struct inode *inode, struct file *fp)
 322{
 323        return single_open(fp, mhi_debugfs_device_wake_show, inode->i_private);
 324}
 325
 326static int mhi_debugfs_timeout_ms_open(struct inode *inode, struct file *fp)
 327{
 328        return single_open(fp, mhi_debugfs_timeout_ms_show, inode->i_private);
 329}
 330
 331static const struct file_operations debugfs_states_fops = {
 332        .open = mhi_debugfs_states_open,
 333        .release = single_release,
 334        .read = seq_read,
 335};
 336
 337static const struct file_operations debugfs_events_fops = {
 338        .open = mhi_debugfs_events_open,
 339        .release = single_release,
 340        .read = seq_read,
 341};
 342
 343static const struct file_operations debugfs_channels_fops = {
 344        .open = mhi_debugfs_channels_open,
 345        .release = single_release,
 346        .read = seq_read,
 347};
 348
 349static const struct file_operations debugfs_devices_fops = {
 350        .open = mhi_debugfs_devices_open,
 351        .release = single_release,
 352        .read = seq_read,
 353};
 354
 355static const struct file_operations debugfs_regdump_fops = {
 356        .open = mhi_debugfs_regdump_open,
 357        .release = single_release,
 358        .read = seq_read,
 359};
 360
 361static const struct file_operations debugfs_device_wake_fops = {
 362        .open = mhi_debugfs_device_wake_open,
 363        .write = mhi_debugfs_device_wake_write,
 364        .release = single_release,
 365        .read = seq_read,
 366};
 367
 368static const struct file_operations debugfs_timeout_ms_fops = {
 369        .open = mhi_debugfs_timeout_ms_open,
 370        .write = mhi_debugfs_timeout_ms_write,
 371        .release = single_release,
 372        .read = seq_read,
 373};
 374
 375static struct dentry *mhi_debugfs_root;
 376
 377void mhi_create_debugfs(struct mhi_controller *mhi_cntrl)
 378{
 379        mhi_cntrl->debugfs_dentry =
 380                        debugfs_create_dir(dev_name(&mhi_cntrl->mhi_dev->dev),
 381                                           mhi_debugfs_root);
 382
 383        debugfs_create_file("states", 0444, mhi_cntrl->debugfs_dentry,
 384                            mhi_cntrl, &debugfs_states_fops);
 385        debugfs_create_file("events", 0444, mhi_cntrl->debugfs_dentry,
 386                            mhi_cntrl, &debugfs_events_fops);
 387        debugfs_create_file("channels", 0444, mhi_cntrl->debugfs_dentry,
 388                            mhi_cntrl, &debugfs_channels_fops);
 389        debugfs_create_file("devices", 0444, mhi_cntrl->debugfs_dentry,
 390                            mhi_cntrl, &debugfs_devices_fops);
 391        debugfs_create_file("regdump", 0444, mhi_cntrl->debugfs_dentry,
 392                            mhi_cntrl, &debugfs_regdump_fops);
 393        debugfs_create_file("device_wake", 0644, mhi_cntrl->debugfs_dentry,
 394                            mhi_cntrl, &debugfs_device_wake_fops);
 395        debugfs_create_file("timeout_ms", 0644, mhi_cntrl->debugfs_dentry,
 396                            mhi_cntrl, &debugfs_timeout_ms_fops);
 397}
 398
 399void mhi_destroy_debugfs(struct mhi_controller *mhi_cntrl)
 400{
 401        debugfs_remove_recursive(mhi_cntrl->debugfs_dentry);
 402        mhi_cntrl->debugfs_dentry = NULL;
 403}
 404
 405void mhi_debugfs_init(void)
 406{
 407        mhi_debugfs_root = debugfs_create_dir(mhi_bus_type.name, NULL);
 408}
 409
 410void mhi_debugfs_exit(void)
 411{
 412        debugfs_remove_recursive(mhi_debugfs_root);
 413}
 414