1 /* 2 * Copyright (c) 2017-2020 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 #else 180 181 void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf, 182 qdf_size_t len, int rowsize, int groupsize) 183 { 184 char *dst; 185 size_t dstlen, readlen, remaining = len; 186 int prefix = 0; 187 size_t commitlen; 188 189 while (remaining > 0 && (file->size > file->count)) { 190 seq_printf(file, "%.8x: ", prefix); 191 192 readlen = qdf_min(remaining, (qdf_size_t)rowsize); 193 dstlen = seq_get_buf(file, &dst); 194 hex_dump_to_buffer(buf, readlen, rowsize, groupsize, dst, 195 dstlen, false); 196 commitlen = strnlen(dst, dstlen); 197 seq_commit(file, commitlen); 198 seq_putc(file, '\n'); 199 200 remaining = (remaining > rowsize) ? remaining - rowsize : 0; 201 buf += readlen; 202 prefix += rowsize; 203 } 204 } 205 206 #endif 207 208 bool qdf_debugfs_overflow(qdf_debugfs_file_t file) 209 { 210 return seq_has_overflowed(file); 211 } 212 213 void qdf_debugfs_write(qdf_debugfs_file_t file, const uint8_t *buf, 214 qdf_size_t len) 215 { 216 seq_write(file, buf, len); 217 } 218 219 /* sequential file operation table */ 220 static const struct seq_operations __qdf_debugfs_seq_ops = { 221 .start = qdf_debugfs_seq_start, 222 .next = qdf_debugfs_seq_next, 223 .stop = qdf_debugfs_seq_stop, 224 .show = qdf_debugfs_seq_show, 225 }; 226 227 /* .open() */ 228 static int qdf_seq_open(struct inode *inode, struct file *file) 229 { 230 void *private = inode->i_private; 231 struct seq_file *seq; 232 int rc; 233 234 /** 235 * Note: seq_open() will allocate a struct seq_file and store its 236 * pointer in @file->private_data. It warns if private_data is not NULL. 237 */ 238 239 rc = seq_open(file, &__qdf_debugfs_seq_ops); 240 241 if (rc == 0) { 242 seq = file->private_data; 243 seq->private = private; 244 } 245 246 return rc; 247 } 248 249 /* .write() */ 250 static ssize_t qdf_seq_write(struct file *filp, const char __user *ubuf, 251 size_t len, loff_t *ppos) 252 { 253 struct qdf_debugfs_fops *fops; 254 struct seq_file *seq; 255 u8 *buf; 256 ssize_t rc = 0; 257 258 if (len == 0) 259 return 0; 260 261 seq = filp->private_data; 262 fops = seq->private; 263 if (fops && fops->write) { 264 buf = qdf_mem_malloc(len + 1); 265 if (buf) { 266 buf[len] = '\0'; 267 rc = simple_write_to_buffer(buf, len, ppos, ubuf, len); 268 fops->write(fops->priv, buf, len + 1); 269 qdf_mem_free(buf); 270 } 271 } 272 273 return rc; 274 } 275 276 /* debugfs file operation table */ 277 static const struct file_operations __qdf_debugfs_fops = { 278 .owner = THIS_MODULE, 279 .open = qdf_seq_open, 280 .read = seq_read, 281 .llseek = seq_lseek, 282 .release = seq_release, 283 .write = qdf_seq_write, 284 }; 285 286 qdf_dentry_t qdf_debugfs_create_dir(const char *name, qdf_dentry_t parent) 287 { 288 qdf_dentry_t dir; 289 290 if (!name) 291 return NULL; 292 if (!parent) 293 parent = qdf_debugfs_get_root(); 294 295 dir = debugfs_create_dir(name, parent); 296 297 if (IS_ERR_OR_NULL(dir)) { 298 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 299 "%s creation failed", name); 300 dir = NULL; 301 } 302 303 return dir; 304 } 305 qdf_export_symbol(qdf_debugfs_create_dir); 306 307 qdf_dentry_t qdf_debugfs_create_file(const char *name, uint16_t mode, 308 qdf_dentry_t parent, 309 struct qdf_debugfs_fops *fops) 310 { 311 qdf_dentry_t file; 312 umode_t filemode; 313 314 if (!name || !fops) 315 return NULL; 316 317 if (!parent) 318 parent = qdf_debugfs_get_root(); 319 320 filemode = qdf_debugfs_get_filemode(mode); 321 file = debugfs_create_file(name, filemode, parent, fops, 322 &__qdf_debugfs_fops); 323 324 if (IS_ERR_OR_NULL(file)) { 325 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 326 "%s creation failed 0x%pK", name, file); 327 file = NULL; 328 } 329 330 return file; 331 } 332 qdf_export_symbol(qdf_debugfs_create_file); 333 334 void qdf_debugfs_create_u8(const char *name, uint16_t mode, 335 qdf_dentry_t parent, u8 *value) 336 { 337 umode_t filemode; 338 339 if (!name) 340 return; 341 342 if (!parent) 343 parent = qdf_debugfs_get_root(); 344 345 filemode = qdf_debugfs_get_filemode(mode); 346 debugfs_create_u8(name, filemode, parent, value); 347 } 348 349 void qdf_debugfs_create_u16(const char *name, uint16_t mode, 350 qdf_dentry_t parent, u16 *value) 351 { 352 umode_t filemode; 353 354 if (!name) 355 return; 356 357 if (!parent) 358 parent = qdf_debugfs_get_root(); 359 360 filemode = qdf_debugfs_get_filemode(mode); 361 debugfs_create_u16(name, filemode, parent, value); 362 } 363 364 qdf_export_symbol(qdf_debugfs_create_u16); 365 366 void qdf_debugfs_create_u32(const char *name, 367 uint16_t mode, 368 qdf_dentry_t parent, u32 *value) 369 { 370 umode_t filemode; 371 372 if (!name) 373 return; 374 375 if (!parent) 376 parent = qdf_debugfs_get_root(); 377 378 filemode = qdf_debugfs_get_filemode(mode); 379 debugfs_create_u32(name, filemode, parent, value); 380 } 381 382 qdf_export_symbol(qdf_debugfs_create_u32); 383 384 void qdf_debugfs_create_u64(const char *name, uint16_t mode, 385 qdf_dentry_t parent, u64 *value) 386 { 387 umode_t filemode; 388 389 if (!name) 390 return; 391 392 if (!parent) 393 parent = qdf_debugfs_get_root(); 394 395 filemode = qdf_debugfs_get_filemode(mode); 396 debugfs_create_u64(name, filemode, parent, value); 397 } 398 399 qdf_export_symbol(qdf_debugfs_create_u64); 400 401 void qdf_debugfs_create_atomic(const char *name, uint16_t mode, 402 qdf_dentry_t parent, qdf_atomic_t *value) 403 { 404 umode_t filemode; 405 406 if (!name) 407 return; 408 409 if (!parent) 410 parent = qdf_debugfs_get_root(); 411 412 filemode = qdf_debugfs_get_filemode(mode); 413 debugfs_create_atomic_t(name, filemode, parent, value); 414 } 415 416 qdf_export_symbol(qdf_debugfs_create_atomic); 417 418 static int qdf_debugfs_string_show(struct seq_file *seq, void *pos) 419 { 420 char *str = seq->private; 421 422 seq_puts(seq, str); 423 seq_putc(seq, '\n'); 424 425 return 0; 426 } 427 428 static int qdf_debugfs_string_open(struct inode *inode, struct file *file) 429 { 430 return single_open(file, qdf_debugfs_string_show, inode->i_private); 431 } 432 433 static const struct file_operations qdf_string_fops = { 434 .owner = THIS_MODULE, 435 .open = qdf_debugfs_string_open, 436 .read = seq_read, 437 .llseek = seq_lseek, 438 .release = single_release 439 }; 440 441 qdf_dentry_t qdf_debugfs_create_string(const char *name, uint16_t mode, 442 qdf_dentry_t parent, char *str) 443 { 444 umode_t filemode; 445 446 if (!name) 447 return NULL; 448 449 if (!parent) 450 parent = qdf_debugfs_get_root(); 451 452 filemode = qdf_debugfs_get_filemode(mode); 453 return debugfs_create_file(name, filemode, parent, str, 454 &qdf_string_fops); 455 } 456 qdf_export_symbol(qdf_debugfs_create_string); 457 458 void qdf_debugfs_remove_dir_recursive(qdf_dentry_t d) 459 { 460 debugfs_remove_recursive(d); 461 } 462 qdf_export_symbol(qdf_debugfs_remove_dir_recursive); 463 464 void qdf_debugfs_remove_dir(qdf_dentry_t d) 465 { 466 debugfs_remove(d); 467 } 468 qdf_export_symbol(qdf_debugfs_remove_dir); 469 470 void qdf_debugfs_remove_file(qdf_dentry_t d) 471 { 472 debugfs_remove(d); 473 } 474 qdf_export_symbol(qdf_debugfs_remove_file); 475 476 static int qdf_debugfs_single_show(struct seq_file *seq, void *v) 477 { 478 struct qdf_debugfs_fops *fops = seq->private; 479 480 if (fops && fops->show) 481 fops->show(seq, fops->priv); 482 483 return 0; 484 } 485 486 /* .open() */ 487 static int qdf_debugfs_single_open(struct inode *inode, struct file *file) 488 { 489 return single_open(file, qdf_debugfs_single_show, 490 inode->i_private); 491 } 492 493 /* File operations for the simplified version */ 494 static const struct file_operations qdf_debugfs_fops_simple = { 495 .owner = THIS_MODULE, 496 .open = qdf_debugfs_single_open, 497 .release = single_release, 498 .read = seq_read, 499 .llseek = seq_lseek, 500 }; 501 502 qdf_dentry_t qdf_debugfs_create_file_simplified( 503 const char *name, uint16_t mode, 504 qdf_dentry_t parent, struct qdf_debugfs_fops *fops) 505 { 506 qdf_dentry_t file; 507 umode_t filemode; 508 509 if (!name || !fops) 510 return NULL; 511 512 if (!parent) 513 parent = qdf_debugfs_get_root(); 514 515 filemode = qdf_debugfs_get_filemode(mode); 516 file = debugfs_create_file(name, filemode, parent, fops, 517 &qdf_debugfs_fops_simple); 518 519 if (IS_ERR_OR_NULL(file)) { 520 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 521 "%s creation failed 0x%pK", name, file); 522 file = NULL; 523 } 524 525 return file; 526 } 527 qdf_export_symbol(qdf_debugfs_create_file_simplified); 528 529 int qdf_debugfs_printer(void *priv, const char *fmt, ...) 530 { 531 struct seq_file *file = priv; 532 va_list args; 533 534 va_start(args, fmt); 535 seq_vprintf(file, fmt, args); 536 seq_puts(file, "\n"); 537 va_end(args); 538 539 return 0; 540 } 541 qdf_export_symbol(qdf_debugfs_printer); 542