debugfs.c (11509B)
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 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, (le32_to_cpu(er_ctxt->intmod) & EV_CTX_INTMODC_MASK) >> 64 __ffs(EV_CTX_INTMODC_MASK), 65 (le32_to_cpu(er_ctxt->intmod) & EV_CTX_INTMODT_MASK) >> 66 __ffs(EV_CTX_INTMODT_MASK)); 67 68 seq_printf(m, " base: 0x%0llx len: 0x%llx", le64_to_cpu(er_ctxt->rbase), 69 le64_to_cpu(er_ctxt->rlen)); 70 71 seq_printf(m, " rp: 0x%llx wp: 0x%llx", le64_to_cpu(er_ctxt->rp), 72 le64_to_cpu(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, (le32_to_cpu(chan_ctxt->chcfg) & 110 CHAN_CTX_CHSTATE_MASK) >> __ffs(CHAN_CTX_CHSTATE_MASK), 111 (le32_to_cpu(chan_ctxt->chcfg) & CHAN_CTX_BRSTMODE_MASK) >> 112 __ffs(CHAN_CTX_BRSTMODE_MASK), (le32_to_cpu(chan_ctxt->chcfg) & 113 CHAN_CTX_POLLCFG_MASK) >> __ffs(CHAN_CTX_POLLCFG_MASK)); 114 115 seq_printf(m, " type: 0x%x event ring: %u", le32_to_cpu(chan_ctxt->chtype), 116 le32_to_cpu(chan_ctxt->erindex)); 117 118 seq_printf(m, " base: 0x%llx len: 0x%llx rp: 0x%llx wp: 0x%llx", 119 le64_to_cpu(chan_ctxt->rbase), le64_to_cpu(chan_ctxt->rlen), 120 le64_to_cpu(chan_ctxt->rp), le64_to_cpu(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 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 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}