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        device_for_each_child(mhi_cntrl->cntrl_dev, m, mhi_device_info_show);
 163
 164        return 0;
 165}
 166
 167static int mhi_debugfs_regdump_show(struct seq_file *m, void *d)
 168{
 169        struct mhi_controller *mhi_cntrl = m->private;
 170        enum mhi_state state;
 171        enum mhi_ee_type ee;
 172        int i, ret = -EIO;
 173        u32 val;
 174        void __iomem *mhi_base = mhi_cntrl->regs;
 175        void __iomem *bhi_base = mhi_cntrl->bhi;
 176        void __iomem *bhie_base = mhi_cntrl->bhie;
 177        void __iomem *wake_db = mhi_cntrl->wake_db;
 178        struct {
 179                const char *name;
 180                int offset;
 181                void __iomem *base;
 182        } regs[] = {
 183                { "MHI_REGLEN", MHIREGLEN, mhi_base},
 184                { "MHI_VER", MHIVER, mhi_base},
 185                { "MHI_CFG", MHICFG, mhi_base},
 186                { "MHI_CTRL", MHICTRL, mhi_base},
 187                { "MHI_STATUS", MHISTATUS, mhi_base},
 188                { "MHI_WAKE_DB", 0, wake_db},
 189                { "BHI_EXECENV", BHI_EXECENV, bhi_base},
 190                { "BHI_STATUS", BHI_STATUS, bhi_base},
 191                { "BHI_ERRCODE", BHI_ERRCODE, bhi_base},
 192                { "BHI_ERRDBG1", BHI_ERRDBG1, bhi_base},
 193                { "BHI_ERRDBG2", BHI_ERRDBG2, bhi_base},
 194                { "BHI_ERRDBG3", BHI_ERRDBG3, bhi_base},
 195                { "BHIE_TXVEC_DB", BHIE_TXVECDB_OFFS, bhie_base},
 196                { "BHIE_TXVEC_STATUS", BHIE_TXVECSTATUS_OFFS, bhie_base},
 197                { "BHIE_RXVEC_DB", BHIE_RXVECDB_OFFS, bhie_base},
 198                { "BHIE_RXVEC_STATUS", BHIE_RXVECSTATUS_OFFS, bhie_base},
 199                { NULL },
 200        };
 201
 202        if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
 203                return ret;
 204
 205        seq_printf(m, "Host PM state: %s Device state: %s EE: %s\n",
 206                   to_mhi_pm_state_str(mhi_cntrl->pm_state),
 207                   TO_MHI_STATE_STR(mhi_cntrl->dev_state),
 208                   TO_MHI_EXEC_STR(mhi_cntrl->ee));
 209
 210        state = mhi_get_mhi_state(mhi_cntrl);
 211        ee = mhi_get_exec_env(mhi_cntrl);
 212        seq_printf(m, "Device EE: %s state: %s\n", TO_MHI_EXEC_STR(ee),
 213                   TO_MHI_STATE_STR(state));
 214
 215        for (i = 0; regs[i].name; i++) {
 216                if (!regs[i].base)
 217                        continue;
 218                ret = mhi_read_reg(mhi_cntrl, regs[i].base, regs[i].offset,
 219                                   &val);
 220                if (ret)
 221                        continue;
 222
 223                seq_printf(m, "%s: 0x%x\n", regs[i].name, val);
 224        }
 225
 226        return 0;
 227}
 228
 229static int mhi_debugfs_device_wake_show(struct seq_file *m, void *d)
 230{
 231        struct mhi_controller *mhi_cntrl = m->private;
 232        struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
 233
 234        if (!mhi_is_active(mhi_cntrl)) {
 235                seq_puts(m, "Device not ready\n");
 236                return -ENODEV;
 237        }
 238
 239        seq_printf(m,
 240                   "Wake count: %d\n%s\n", mhi_dev->dev_wake,
 241                   "Usage: echo get/put > device_wake to vote/unvote for M0");
 242
 243        return 0;
 244}
 245
 246static ssize_t mhi_debugfs_device_wake_write(struct file *file,
 247                                             const char __user *ubuf,
 248                                             size_t count, loff_t *ppos)
 249{
 250        struct seq_file *m = file->private_data;
 251        struct mhi_controller *mhi_cntrl = m->private;
 252        struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
 253        char buf[16];
 254        int ret = -EINVAL;
 255
 256        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 257                return -EFAULT;
 258
 259        if (!strncmp(buf, "get", 3)) {
 260                ret = mhi_device_get_sync(mhi_dev);
 261        } else if (!strncmp(buf, "put", 3)) {
 262                mhi_device_put(mhi_dev);
 263                ret = 0;
 264        }
 265
 266        return ret ? ret : count;
 267}
 268
 269static int mhi_debugfs_timeout_ms_show(struct seq_file *m, void *d)
 270{
 271        struct mhi_controller *mhi_cntrl = m->private;
 272
 273        seq_printf(m, "%u ms\n", mhi_cntrl->timeout_ms);
 274
 275        return 0;
 276}
 277
 278static ssize_t mhi_debugfs_timeout_ms_write(struct file *file,
 279                                            const char __user *ubuf,
 280                                            size_t count, loff_t *ppos)
 281{
 282        struct seq_file *m = file->private_data;
 283        struct mhi_controller *mhi_cntrl = m->private;
 284        u32 timeout_ms;
 285
 286        if (kstrtou32_from_user(ubuf, count, 0, &timeout_ms))
 287                return -EINVAL;
 288
 289        mhi_cntrl->timeout_ms = timeout_ms;
 290
 291        return count;
 292}
 293
 294static int mhi_debugfs_states_open(struct inode *inode, struct file *fp)
 295{
 296        return single_open(fp, mhi_debugfs_states_show, inode->i_private);
 297}
 298
 299static int mhi_debugfs_events_open(struct inode *inode, struct file *fp)
 300{
 301        return single_open(fp, mhi_debugfs_events_show, inode->i_private);
 302}
 303
 304static int mhi_debugfs_channels_open(struct inode *inode, struct file *fp)
 305{
 306        return single_open(fp, mhi_debugfs_channels_show, inode->i_private);
 307}
 308
 309static int mhi_debugfs_devices_open(struct inode *inode, struct file *fp)
 310{
 311        return single_open(fp, mhi_debugfs_devices_show, inode->i_private);
 312}
 313
 314static int mhi_debugfs_regdump_open(struct inode *inode, struct file *fp)
 315{
 316        return single_open(fp, mhi_debugfs_regdump_show, inode->i_private);
 317}
 318
 319static int mhi_debugfs_device_wake_open(struct inode *inode, struct file *fp)
 320{
 321        return single_open(fp, mhi_debugfs_device_wake_show, inode->i_private);
 322}
 323
 324static int mhi_debugfs_timeout_ms_open(struct inode *inode, struct file *fp)
 325{
 326        return single_open(fp, mhi_debugfs_timeout_ms_show, inode->i_private);
 327}
 328
 329static const struct file_operations debugfs_states_fops = {
 330        .open = mhi_debugfs_states_open,
 331        .release = single_release,
 332        .read = seq_read,
 333};
 334
 335static const struct file_operations debugfs_events_fops = {
 336        .open = mhi_debugfs_events_open,
 337        .release = single_release,
 338        .read = seq_read,
 339};
 340
 341static const struct file_operations debugfs_channels_fops = {
 342        .open = mhi_debugfs_channels_open,
 343        .release = single_release,
 344        .read = seq_read,
 345};
 346
 347static const struct file_operations debugfs_devices_fops = {
 348        .open = mhi_debugfs_devices_open,
 349        .release = single_release,
 350        .read = seq_read,
 351};
 352
 353static const struct file_operations debugfs_regdump_fops = {
 354        .open = mhi_debugfs_regdump_open,
 355        .release = single_release,
 356        .read = seq_read,
 357};
 358
 359static const struct file_operations debugfs_device_wake_fops = {
 360        .open = mhi_debugfs_device_wake_open,
 361        .write = mhi_debugfs_device_wake_write,
 362        .release = single_release,
 363        .read = seq_read,
 364};
 365
 366static const struct file_operations debugfs_timeout_ms_fops = {
 367        .open = mhi_debugfs_timeout_ms_open,
 368        .write = mhi_debugfs_timeout_ms_write,
 369        .release = single_release,
 370        .read = seq_read,
 371};
 372
 373static struct dentry *mhi_debugfs_root;
 374
 375void mhi_create_debugfs(struct mhi_controller *mhi_cntrl)
 376{
 377        mhi_cntrl->debugfs_dentry =
 378                        debugfs_create_dir(dev_name(mhi_cntrl->cntrl_dev),
 379                                           mhi_debugfs_root);
 380
 381        debugfs_create_file("states", 0444, mhi_cntrl->debugfs_dentry,
 382                            mhi_cntrl, &debugfs_states_fops);
 383        debugfs_create_file("events", 0444, mhi_cntrl->debugfs_dentry,
 384                            mhi_cntrl, &debugfs_events_fops);
 385        debugfs_create_file("channels", 0444, mhi_cntrl->debugfs_dentry,
 386                            mhi_cntrl, &debugfs_channels_fops);
 387        debugfs_create_file("devices", 0444, mhi_cntrl->debugfs_dentry,
 388                            mhi_cntrl, &debugfs_devices_fops);
 389        debugfs_create_file("regdump", 0444, mhi_cntrl->debugfs_dentry,
 390                            mhi_cntrl, &debugfs_regdump_fops);
 391        debugfs_create_file("device_wake", 0644, mhi_cntrl->debugfs_dentry,
 392                            mhi_cntrl, &debugfs_device_wake_fops);
 393        debugfs_create_file("timeout_ms", 0644, mhi_cntrl->debugfs_dentry,
 394                            mhi_cntrl, &debugfs_timeout_ms_fops);
 395}
 396
 397void mhi_destroy_debugfs(struct mhi_controller *mhi_cntrl)
 398{
 399        debugfs_remove_recursive(mhi_cntrl->debugfs_dentry);
 400        mhi_cntrl->debugfs_dentry = NULL;
 401}
 402
 403void mhi_debugfs_init(void)
 404{
 405        mhi_debugfs_root = debugfs_create_dir(mhi_bus_type.name, NULL);
 406}
 407
 408void mhi_debugfs_exit(void)
 409{
 410        debugfs_remove_recursive(mhi_debugfs_root);
 411}
 412