1 /* 2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: qdf_debugfs 21 * This file provides QDF debug file system APIs 22 */ 23 24 #include <qdf_debugfs.h> 25 #include <i_qdf_debugfs.h> 26 #include <qdf_mem.h> 27 #include <qdf_trace.h> 28 #include <qdf_module.h> 29 30 /* A private structure definition to qdf sequence */ 31 struct qdf_debugfs_seq_priv { 32 bool stop; 33 }; 34 35 /* entry for root debugfs directory*/ 36 static qdf_dentry_t qdf_debugfs_root; 37 38 QDF_STATUS qdf_debugfs_init(void) 39 { 40 qdf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 41 42 if (!qdf_debugfs_root) 43 return QDF_STATUS_E_FAILURE; 44 45 return QDF_STATUS_SUCCESS; 46 } 47 qdf_export_symbol(qdf_debugfs_init); 48 49 void qdf_debugfs_exit(void) 50 { 51 if (!qdf_debugfs_root) 52 return; 53 54 debugfs_remove_recursive(qdf_debugfs_root); 55 qdf_debugfs_root = NULL; 56 } 57 qdf_export_symbol(qdf_debugfs_exit); 58 59 qdf_dentry_t qdf_debugfs_get_root(void) 60 { 61 return qdf_debugfs_root; 62 } 63 qdf_export_symbol(qdf_debugfs_get_root); 64 65 umode_t qdf_debugfs_get_filemode(uint16_t mode) 66 { 67 umode_t ret = 0; 68 69 if (mode & QDF_FILE_USR_READ) 70 ret |= 0400; 71 if (mode & QDF_FILE_USR_WRITE) 72 ret |= 0200; 73 74 if (mode & QDF_FILE_GRP_READ) 75 ret |= 0040; 76 if (mode & QDF_FILE_GRP_WRITE) 77 ret |= 0020; 78 79 if (mode & QDF_FILE_OTH_READ) 80 ret |= 0004; 81 if (mode & QDF_FILE_OTH_WRITE) 82 ret |= 0002; 83 84 return ret; 85 } 86 87 /** 88 * ---------------------- Implementation note --------------------------------- 89 * 90 * A read in debugfs file triggers seq_read() which calls seq_read api. A 91 * sequence begins with the call of the function start(). If the return is a non 92 * NULL value, the function next() is called. This function is an iterator, the 93 * goal is to go though all the data. Each time next() is called, the function 94 * show() is also called. It writes data values in the buffer read by the user. 95 * The function next() is called until it returns NULL. The sequence ends when 96 * next() returns NULL, then the function stop() is called. 97 * 98 * NOTE: When a sequence is finished, another one starts. That means that 99 * at the end of function stop(), the function start() is called again. This 100 * loop finishes when the function start() returns NULL. 101 * ---------------------------------------------------------------------------- 102 */ 103 104 /* .seq_start() */ 105 static void *qdf_debugfs_seq_start(struct seq_file *seq, loff_t *pos) 106 { 107 struct qdf_debugfs_seq_priv *priv; 108 109 priv = qdf_mem_malloc(sizeof(*priv)); 110 if (!priv) 111 return NULL; 112 113 priv->stop = false; 114 115 return priv; 116 } 117 118 /* .seq_next() */ 119 static void *qdf_debugfs_seq_next(struct seq_file *seq, void *v, loff_t *pos) 120 { 121 struct qdf_debugfs_seq_priv *priv = v; 122 123 if (priv) 124 ++*pos; 125 126 if (priv && priv->stop) { 127 qdf_mem_free(priv); 128 priv = NULL; 129 } 130 131 return priv; 132 } 133 134 /* .seq_stop() */ 135 static void qdf_debugfs_seq_stop(struct seq_file *seq, void *v) 136 { 137 qdf_mem_free(v); 138 } 139 140 /* .seq_show() */ 141 static int qdf_debugfs_seq_show(struct seq_file *seq, void *v) 142 { 143 struct qdf_debugfs_seq_priv *priv = v; 144 struct qdf_debugfs_fops *fops; 145 QDF_STATUS status; 146 147 fops = seq->private; 148 149 if (fops && fops->show) { 150 status = fops->show(seq, fops->priv); 151 152 if (priv && (status != QDF_STATUS_E_AGAIN)) 153 priv->stop = true; 154 } 155 156 return 0; 157 } 158 159 void qdf_debugfs_printf(qdf_debugfs_file_t file, const char *f, ...) 160 { 161 va_list args; 162 163 va_start(args, f); 164 seq_vprintf(file, f, args); 165 va_end(args); 166 } 167 168 qdf_export_symbol(qdf_debugfs_printf); 169 170 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) 171 172 void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf, 173 qdf_size_t len, int rowsize, int groupsize) 174 { 175 seq_hex_dump(file, "", DUMP_PREFIX_OFFSET, rowsize, groupsize, buf, len, 176 false); 177 } 178 179 qdf_export_symbol(qdf_debugfs_hexdump); 180 #else 181 182 void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf, 183 qdf_size_t len, int rowsize, int groupsize) 184 { 185 char *dst; 186 size_t dstlen, readlen, remaining = len; 187 int prefix = 0; 188 size_t commitlen; 189 190 while (remaining > 0 && (file->size > file->count)) { 191 seq_printf(file, "%.8x: ", prefix); 192 193 readlen = qdf_min(remaining, (qdf_size_t)rowsize); 194 dstlen = seq_get_buf(file, &dst); 195 hex_dump_to_buffer(buf, readlen, rowsize, groupsize, dst, 196 dstlen, false); 197 commitlen = strnlen(dst, dstlen); 198 seq_commit(file, commitlen); 199 seq_putc(file, '\n'); 200 201 remaining = (remaining > rowsize) ? remaining - rowsize : 0; 202 buf += readlen; 203 prefix += rowsize; 204 } 205 } 206 207 qdf_export_symbol(qdf_debugfs_hexdump); 208 #endif 209 210 bool qdf_debugfs_overflow(qdf_debugfs_file_t file) 211 { 212 return seq_has_overflowed(file); 213 } 214 215 qdf_export_symbol(qdf_debugfs_overflow); 216 217 void qdf_debugfs_write(qdf_debugfs_file_t file, const uint8_t *buf, 218 qdf_size_t len) 219 { 220 seq_write(file, buf, len); 221 } 222 223 /* sequential file operation table */ 224 static const struct seq_operations __qdf_debugfs_seq_ops = { 225 .start = qdf_debugfs_seq_start, 226 .next = qdf_debugfs_seq_next, 227 .stop = qdf_debugfs_seq_stop, 228 .show = qdf_debugfs_seq_show, 229 }; 230 231 /* .open() */ 232 static int qdf_seq_open(struct inode *inode, struct file *file) 233 { 234 void *private = inode->i_private; 235 struct seq_file *seq; 236 int rc; 237 238 /** 239 * Note: seq_open() will allocate a struct seq_file and store its 240 * pointer in @file->private_data. It warns if private_data is not NULL. 241 */ 242 243 rc = seq_open(file, &__qdf_debugfs_seq_ops); 244 245 if (rc == 0) { 246 seq = file->private_data; 247 seq->private = private; 248 } 249 250 return rc; 251 } 252 253 /* .write() */ 254 static ssize_t qdf_seq_write(struct file *filp, const char __user *ubuf, 255 size_t len, loff_t *ppos) 256 { 257 struct qdf_debugfs_fops *fops; 258 struct seq_file *seq; 259 u8 *buf; 260 ssize_t rc = 0; 261 262 if (len == 0) 263 return 0; 264 265 seq = filp->private_data; 266 fops = seq->private; 267 if (fops && fops->write) { 268 buf = qdf_mem_malloc(len + 1); 269 if (buf) { 270 buf[len] = '\0'; 271 rc = simple_write_to_buffer(buf, len, ppos, ubuf, len); 272 fops->write(fops->priv, buf, len + 1); 273 qdf_mem_free(buf); 274 } 275 } 276 277 return rc; 278 } 279 280 /* debugfs file operation table */ 281 static const struct file_operations __qdf_debugfs_fops = { 282 .owner = THIS_MODULE, 283 .open = qdf_seq_open, 284 .read = seq_read, 285 .llseek = seq_lseek, 286 .release = seq_release, 287 .write = qdf_seq_write, 288 }; 289 290 qdf_dentry_t qdf_debugfs_create_dir(const char *name, qdf_dentry_t parent) 291 { 292 qdf_dentry_t dir; 293 294 if (!name) 295 return NULL; 296 if (!parent) 297 parent = qdf_debugfs_get_root(); 298 299 dir = debugfs_create_dir(name, parent); 300 301 if (IS_ERR_OR_NULL(dir)) { 302 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 303 "%s creation failed", name); 304 dir = NULL; 305 } 306 307 return dir; 308 } 309 qdf_export_symbol(qdf_debugfs_create_dir); 310 311 qdf_dentry_t qdf_debugfs_create_file(const char *name, uint16_t mode, 312 qdf_dentry_t parent, 313 struct qdf_debugfs_fops *fops) 314 { 315 qdf_dentry_t file; 316 umode_t filemode; 317 318 if (!name || !fops) 319 return NULL; 320 321 if (!parent) 322 parent = qdf_debugfs_get_root(); 323 324 filemode = qdf_debugfs_get_filemode(mode); 325 file = debugfs_create_file(name, filemode, parent, fops, 326 &__qdf_debugfs_fops); 327 328 if (IS_ERR_OR_NULL(file)) { 329 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 330 "%s creation failed 0x%pK", name, file); 331 file = NULL; 332 } 333 334 return file; 335 } 336 qdf_export_symbol(qdf_debugfs_create_file); 337 338 void qdf_debugfs_create_u8(const char *name, uint16_t mode, 339 qdf_dentry_t parent, u8 *value) 340 { 341 umode_t filemode; 342 343 if (!name) 344 return; 345 346 if (!parent) 347 parent = qdf_debugfs_get_root(); 348 349 filemode = qdf_debugfs_get_filemode(mode); 350 debugfs_create_u8(name, filemode, parent, value); 351 } 352 353 void qdf_debugfs_create_u16(const char *name, uint16_t mode, 354 qdf_dentry_t parent, u16 *value) 355 { 356 umode_t filemode; 357 358 if (!name) 359 return; 360 361 if (!parent) 362 parent = qdf_debugfs_get_root(); 363 364 filemode = qdf_debugfs_get_filemode(mode); 365 debugfs_create_u16(name, filemode, parent, value); 366 } 367 368 qdf_export_symbol(qdf_debugfs_create_u16); 369 370 void qdf_debugfs_create_u32(const char *name, 371 uint16_t mode, 372 qdf_dentry_t parent, u32 *value) 373 { 374 umode_t filemode; 375 376 if (!name) 377 return; 378 379 if (!parent) 380 parent = qdf_debugfs_get_root(); 381 382 filemode = qdf_debugfs_get_filemode(mode); 383 debugfs_create_u32(name, filemode, parent, value); 384 } 385 386 qdf_export_symbol(qdf_debugfs_create_u32); 387 388 void qdf_debugfs_create_u64(const char *name, uint16_t mode, 389 qdf_dentry_t parent, u64 *value) 390 { 391 umode_t filemode; 392 393 if (!name) 394 return; 395 396 if (!parent) 397 parent = qdf_debugfs_get_root(); 398 399 filemode = qdf_debugfs_get_filemode(mode); 400 debugfs_create_u64(name, filemode, parent, value); 401 } 402 403 qdf_export_symbol(qdf_debugfs_create_u64); 404 405 void qdf_debugfs_create_atomic(const char *name, uint16_t mode, 406 qdf_dentry_t parent, qdf_atomic_t *value) 407 { 408 umode_t filemode; 409 410 if (!name) 411 return; 412 413 if (!parent) 414 parent = qdf_debugfs_get_root(); 415 416 filemode = qdf_debugfs_get_filemode(mode); 417 debugfs_create_atomic_t(name, filemode, parent, value); 418 } 419 420 qdf_export_symbol(qdf_debugfs_create_atomic); 421 422 static int qdf_debugfs_string_show(struct seq_file *seq, void *pos) 423 { 424 char *str = seq->private; 425 426 seq_puts(seq, str); 427 seq_putc(seq, '\n'); 428 429 return 0; 430 } 431 432 static int qdf_debugfs_string_open(struct inode *inode, struct file *file) 433 { 434 return single_open(file, qdf_debugfs_string_show, inode->i_private); 435 } 436 437 static const struct file_operations qdf_string_fops = { 438 .owner = THIS_MODULE, 439 .open = qdf_debugfs_string_open, 440 .read = seq_read, 441 .llseek = seq_lseek, 442 .release = single_release 443 }; 444 445 qdf_dentry_t qdf_debugfs_create_string(const char *name, uint16_t mode, 446 qdf_dentry_t parent, char *str) 447 { 448 umode_t filemode; 449 450 if (!name) 451 return NULL; 452 453 if (!parent) 454 parent = qdf_debugfs_get_root(); 455 456 filemode = qdf_debugfs_get_filemode(mode); 457 return debugfs_create_file(name, filemode, parent, str, 458 &qdf_string_fops); 459 } 460 qdf_export_symbol(qdf_debugfs_create_string); 461 462 void qdf_debugfs_remove_dir_recursive(qdf_dentry_t d) 463 { 464 debugfs_remove_recursive(d); 465 } 466 qdf_export_symbol(qdf_debugfs_remove_dir_recursive); 467 468 void qdf_debugfs_remove_dir(qdf_dentry_t d) 469 { 470 debugfs_remove(d); 471 } 472 qdf_export_symbol(qdf_debugfs_remove_dir); 473 474 void qdf_debugfs_remove_file(qdf_dentry_t d) 475 { 476 debugfs_remove(d); 477 } 478 qdf_export_symbol(qdf_debugfs_remove_file); 479 480 static int qdf_debugfs_single_show(struct seq_file *seq, void *v) 481 { 482 struct qdf_debugfs_fops *fops = seq->private; 483 484 if (fops && fops->show) 485 fops->show(seq, fops->priv); 486 487 return 0; 488 } 489 490 /* .open() */ 491 static int qdf_debugfs_single_open(struct inode *inode, struct file *file) 492 { 493 return single_open(file, qdf_debugfs_single_show, 494 inode->i_private); 495 } 496 497 /* File operations for the simplified version */ 498 static const struct file_operations qdf_debugfs_fops_simple = { 499 .owner = THIS_MODULE, 500 .open = qdf_debugfs_single_open, 501 .release = single_release, 502 .read = seq_read, 503 .llseek = seq_lseek, 504 }; 505 506 qdf_dentry_t qdf_debugfs_create_file_simplified( 507 const char *name, uint16_t mode, 508 qdf_dentry_t parent, struct qdf_debugfs_fops *fops) 509 { 510 qdf_dentry_t file; 511 umode_t filemode; 512 513 if (!name || !fops) 514 return NULL; 515 516 if (!parent) 517 parent = qdf_debugfs_get_root(); 518 519 filemode = qdf_debugfs_get_filemode(mode); 520 file = debugfs_create_file(name, filemode, parent, fops, 521 &qdf_debugfs_fops_simple); 522 523 if (IS_ERR_OR_NULL(file)) { 524 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 525 "%s creation failed 0x%pK", name, file); 526 file = NULL; 527 } 528 529 return file; 530 } 531 qdf_export_symbol(qdf_debugfs_create_file_simplified); 532 533 int qdf_debugfs_printer(void *priv, const char *fmt, ...) 534 { 535 struct seq_file *file = priv; 536 va_list args; 537 538 va_start(args, fmt); 539 seq_vprintf(file, fmt, args); 540 seq_puts(file, "\n"); 541 va_end(args); 542 543 return 0; 544 } 545 qdf_export_symbol(qdf_debugfs_printer); 546 547 qdf_dentry_t qdf_debugfs_create_blob(const char *name, umode_t mode, 548 qdf_dentry_t parent, 549 qdf_debugfs_blob_wrap_t blob) 550 { 551 return debugfs_create_blob(name, mode, parent, blob); 552 } 553 554 qdf_export_symbol(qdf_debugfs_create_blob); 555 556 qdf_dentry_t qdf_debugfs_create_entry(const char *name, uint16_t mode, 557 qdf_dentry_t parent, 558 qdf_entry_t data, 559 const qdf_file_ops_t fops) 560 { 561 qdf_dentry_t file; 562 umode_t filemode; 563 564 if (!name || !fops) 565 return NULL; 566 567 if (!parent) 568 parent = qdf_debugfs_get_root(); 569 570 filemode = qdf_debugfs_get_filemode(mode); 571 file = debugfs_create_file(name, filemode, parent, data, fops); 572 573 if (IS_ERR_OR_NULL(file)) { 574 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 575 "%s creation failed 0x%pK", name, file); 576 file = NULL; 577 } 578 579 return file; 580 } 581 582 qdf_export_symbol(qdf_debugfs_create_entry); 583