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