1 /* $NetBSD: drm_print.c,v 1.16 2021/12/29 23:59:37 riastradh Exp $ */ 2 3 /* 4 * Copyright (C) 2016 Red Hat 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Rob Clark <robdclark (at) gmail.com> 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: drm_print.c,v 1.16 2021/12/29 23:59:37 riastradh Exp $"); 30 31 #ifndef __NetBSD__ /* XXX ??? */ 32 #define DEBUG /* for pr_debug() */ 33 #endif 34 35 #ifdef __NetBSD__ 36 #include <sys/param.h> 37 #include <sys/stdarg.h> 38 #include <sys/cpu.h> 39 #include <sys/device.h> 40 #include <sys/ksyms.h> 41 #include <sys/pserialize.h> 42 #else 43 #include <stdarg.h> 44 #endif 45 46 #include <linux/io.h> 47 #include <linux/moduleparam.h> 48 #include <linux/seq_file.h> 49 #include <linux/slab.h> 50 51 #include <drm/drm.h> 52 #include <drm/drm_drv.h> 53 #include <drm/drm_print.h> 54 55 /* 56 * __drm_debug: Enable debug output. 57 * Bitmask of DRM_UT_x. See include/drm/drm_print.h for details. 58 */ 59 unsigned int __drm_debug; 60 EXPORT_SYMBOL(__drm_debug); 61 62 MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" 63 "\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" 64 "\t\tBit 1 (0x02) will enable DRIVER messages (drm controller code)\n" 65 "\t\tBit 2 (0x04) will enable KMS messages (modesetting code)\n" 66 "\t\tBit 3 (0x08) will enable PRIME messages (prime code)\n" 67 "\t\tBit 4 (0x10) will enable ATOMIC messages (atomic code)\n" 68 "\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n" 69 "\t\tBit 7 (0x80) will enable LEASE messages (leasing code)\n" 70 "\t\tBit 8 (0x100) will enable DP messages (displayport code)"); 71 module_param_named(debug, __drm_debug, int, 0600); 72 73 #ifdef __NetBSD__ 74 static void 75 drm_symstr(vaddr_t val, char *out, size_t outsize) 76 { 77 unsigned long naddr; 78 const char *mod; 79 const char *sym; 80 int s; 81 82 s = pserialize_read_enter(); 83 if (ksyms_getname(&mod, &sym, val, KSYMS_PROC|KSYMS_CLOSEST) == 0) { 84 char offset[32]; 85 86 if (ksyms_getval(mod, sym, &naddr, KSYMS_ANY) == 0 && 87 (val - naddr) != 0) 88 snprintf(offset, sizeof offset, "+%p", 89 (void *)(val - naddr)); 90 else 91 offset[0] = '\0'; 92 pserialize_read_exit(s); 93 snprintf(out, outsize, "%s:%s%s", mod, sym, offset); 94 return; 95 } 96 pserialize_read_exit(s); 97 snprintf(out, outsize, "%p", (void *)val); 98 } 99 #endif 100 101 void __drm_puts_coredump(struct drm_printer *p, const char *str) 102 { 103 struct drm_print_iterator *iterator = p->arg; 104 ssize_t len; 105 106 if (!iterator->remain) 107 return; 108 109 if (iterator->offset < iterator->start) { 110 ssize_t copy; 111 112 len = strlen(str); 113 114 if (iterator->offset + len <= iterator->start) { 115 iterator->offset += len; 116 return; 117 } 118 119 copy = len - (iterator->start - iterator->offset); 120 121 if (copy > iterator->remain) 122 copy = iterator->remain; 123 124 /* Copy out the bit of the string that we need */ 125 memcpy(iterator->data, 126 str + (iterator->start - iterator->offset), copy); 127 128 iterator->offset = iterator->start + copy; 129 iterator->remain -= copy; 130 } else { 131 ssize_t pos = iterator->offset - iterator->start; 132 133 len = min_t(ssize_t, strlen(str), iterator->remain); 134 135 memcpy((char *)iterator->data + pos, str, len); 136 137 iterator->offset += len; 138 iterator->remain -= len; 139 } 140 } 141 EXPORT_SYMBOL(__drm_puts_coredump); 142 143 void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) 144 { 145 struct drm_print_iterator *iterator = p->arg; 146 size_t len; 147 char *buf; 148 149 if (!iterator->remain) 150 return; 151 152 /* Figure out how big the string will be */ 153 len = snprintf(NULL, 0, "%pV", vaf); 154 155 /* This is the easiest path, we've already advanced beyond the offset */ 156 if (iterator->offset + len <= iterator->start) { 157 iterator->offset += len; 158 return; 159 } 160 161 /* Then check if we can directly copy into the target buffer */ 162 if ((iterator->offset >= iterator->start) && (len < iterator->remain)) { 163 ssize_t pos = iterator->offset - iterator->start; 164 165 snprintf(((char *) iterator->data) + pos, 166 iterator->remain, "%pV", vaf); 167 168 iterator->offset += len; 169 iterator->remain -= len; 170 171 return; 172 } 173 174 /* 175 * Finally, hit the slow path and make a temporary string to copy over 176 * using _drm_puts_coredump 177 */ 178 buf = kmalloc(len + 1, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); 179 if (!buf) 180 return; 181 182 snprintf(buf, len + 1, "%pV", vaf); 183 __drm_puts_coredump(p, (const char *) buf); 184 185 kfree(buf); 186 } 187 EXPORT_SYMBOL(__drm_printfn_coredump); 188 189 #ifndef __NetBSD__ /* XXX seq file */ 190 void __drm_puts_seq_file(struct drm_printer *p, const char *str) 191 { 192 seq_puts(p->arg, str); 193 } 194 EXPORT_SYMBOL(__drm_puts_seq_file); 195 #endif 196 197 #ifndef __NetBSD__ /* XXX seq file */ 198 void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf) 199 { 200 seq_printf(p->arg, "%pV", vaf); 201 } 202 EXPORT_SYMBOL(__drm_printfn_seq_file); 203 #endif 204 205 void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf) 206 { 207 #ifdef __NetBSD__ 208 dev_info(p->arg, "{" DRM_NAME "} "); 209 vprintf(vaf->fmt, *vaf->va); /* XXX */ 210 #else 211 dev_info(p->arg, "[" DRM_NAME "] %pV", vaf); 212 #endif 213 } 214 EXPORT_SYMBOL(__drm_printfn_info); 215 216 void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf) 217 { 218 #ifdef __NetBSD__ 219 pr_debug("%s ", p->prefix); 220 vprintf(vaf->fmt, *vaf->va); /* XXX */ 221 #else 222 pr_debug("%s %pV", p->prefix, vaf); 223 #endif 224 } 225 EXPORT_SYMBOL(__drm_printfn_debug); 226 227 void __drm_printfn_err(struct drm_printer *p, struct va_format *vaf) 228 { 229 #ifdef __NetBSD__ 230 pr_err("*ERROR* %s ", p->prefix); 231 vprintf(vaf->fmt, *vaf->va); /* XXX */ 232 #else 233 pr_err("*ERROR* %s %pV", p->prefix, vaf); 234 #endif 235 } 236 EXPORT_SYMBOL(__drm_printfn_err); 237 238 /** 239 * drm_puts - print a const string to a &drm_printer stream 240 * @p: the &drm printer 241 * @str: const string 242 * 243 * Allow &drm_printer types that have a constant string 244 * option to use it. 245 */ 246 void drm_puts(struct drm_printer *p, const char *str) 247 { 248 if (p->puts) 249 p->puts(p, str); 250 else 251 drm_printf(p, "%s", str); 252 } 253 EXPORT_SYMBOL(drm_puts); 254 255 /** 256 * drm_printf - print to a &drm_printer stream 257 * @p: the &drm_printer 258 * @f: format string 259 */ 260 void drm_printf(struct drm_printer *p, const char *f, ...) 261 { 262 va_list args; 263 264 va_start(args, f); 265 drm_vprintf(p, f, &args); 266 va_end(args); 267 } 268 EXPORT_SYMBOL(drm_printf); 269 270 /** 271 * drm_print_bits - print bits to a &drm_printer stream 272 * 273 * Print bits (in flag fields for example) in human readable form. 274 * 275 * @p: the &drm_printer 276 * @value: field value. 277 * @bits: Array with bit names. 278 * @nbits: Size of bit names array. 279 */ 280 void drm_print_bits(struct drm_printer *p, unsigned long value, 281 const char * const bits[], unsigned int nbits) 282 { 283 bool first = true; 284 unsigned int i; 285 286 if (WARN_ON_ONCE(nbits > BITS_PER_TYPE(value))) 287 nbits = BITS_PER_TYPE(value); 288 289 for_each_set_bit(i, &value, nbits) { 290 if (WARN_ON_ONCE(!bits[i])) 291 continue; 292 drm_printf(p, "%s%s", first ? "" : ",", 293 bits[i]); 294 first = false; 295 } 296 if (first) 297 drm_printf(p, "(none)"); 298 } 299 EXPORT_SYMBOL(drm_print_bits); 300 301 void drm_dev_printk(const struct device *dev, const char *level, 302 const char *format, ...) 303 { 304 #ifdef __NetBSD__ 305 va_list va; 306 char symbuf[128]; 307 308 drm_symstr((vaddr_t)__builtin_return_address(0), symbuf, sizeof symbuf); 309 if (dev) { 310 printf("%s {" DRM_NAME ":%s} ", device_xname(__UNCONST(dev)), 311 symbuf); 312 } else { 313 printf("{" DRM_NAME ":%s} ", symbuf); 314 } 315 316 va_start(va, format); 317 vprintf(format, va); 318 va_end(va); 319 #else 320 struct va_format vaf; 321 va_list args; 322 323 va_start(args, format); 324 vaf.fmt = format; 325 vaf.va = &args; 326 327 if (dev) 328 dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV", 329 __builtin_return_address(0), &vaf); 330 else 331 printk("%s" "[" DRM_NAME ":%ps] %pV", 332 level, __builtin_return_address(0), &vaf); 333 334 va_end(args); 335 #endif 336 } 337 EXPORT_SYMBOL(drm_dev_printk); 338 339 void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, 340 const char *format, ...) 341 { 342 #ifdef __NetBSD__ 343 va_list va; 344 char symbuf[128]; 345 346 if (!(__drm_debug & category)) 347 return; 348 349 drm_symstr((vaddr_t)__builtin_return_address(0), symbuf, sizeof symbuf); 350 if (dev) { 351 printf("%s {" DRM_NAME ":%s} ", device_xname(__UNCONST(dev)), 352 symbuf); 353 } else { 354 printf("{" DRM_NAME ":%s} ", symbuf); 355 } 356 357 va_start(va, format); 358 vprintf(format, va); 359 va_end(va); 360 #else 361 struct va_format vaf; 362 va_list args; 363 364 if (!drm_debug_enabled(category)) 365 return; 366 367 va_start(args, format); 368 vaf.fmt = format; 369 vaf.va = &args; 370 371 if (dev) 372 dev_printk(KERN_DEBUG, dev, "[" DRM_NAME ":%ps] %pV", 373 __builtin_return_address(0), &vaf); 374 else 375 printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV", 376 __builtin_return_address(0), &vaf); 377 378 va_end(args); 379 #endif 380 } 381 EXPORT_SYMBOL(drm_dev_dbg); 382 383 void __drm_dbg(enum drm_debug_category category, const char *format, ...) 384 { 385 #ifdef __NetBSD__ 386 char symbuf[128]; 387 va_list va; 388 389 if (!(__drm_debug & category)) 390 return; 391 392 memset(symbuf, 0, sizeof symbuf); 393 drm_symstr((vaddr_t)__builtin_return_address(0), symbuf, sizeof symbuf); 394 printf("{" DRM_NAME ":%s} ", symbuf); 395 396 va_start(va, format); 397 vprintf(format, va); 398 va_end(va); 399 #else 400 struct va_format vaf; 401 va_list args; 402 403 if (!drm_debug_enabled(category)) 404 return; 405 406 va_start(args, format); 407 vaf.fmt = format; 408 vaf.va = &args; 409 410 printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV", 411 __builtin_return_address(0), &vaf); 412 413 va_end(args); 414 #endif 415 } 416 EXPORT_SYMBOL(__drm_dbg); 417 418 void __drm_err(const char *format, ...) 419 { 420 #ifdef __NetBSD__ 421 char symbuf[128]; 422 va_list va; 423 424 drm_symstr((vaddr_t)__builtin_return_address(0), symbuf, sizeof symbuf); 425 printf("{" DRM_NAME ":%s} *ERROR* ", symbuf); 426 427 va_start(va, format); 428 vprintf(format, va); 429 va_end(va); 430 #else 431 struct va_format vaf; 432 va_list args; 433 434 va_start(args, format); 435 vaf.fmt = format; 436 vaf.va = &args; 437 438 printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV", 439 __builtin_return_address(0), &vaf); 440 441 va_end(args); 442 #endif 443 } 444 EXPORT_SYMBOL(__drm_err); 445 446 #ifndef __NetBSD__ 447 /** 448 * drm_print_regset32 - print the contents of registers to a 449 * &drm_printer stream. 450 * 451 * @p: the &drm printer 452 * @regset: the list of registers to print. 453 * 454 * Often in driver debug, it's useful to be able to either capture the 455 * contents of registers in the steady state using debugfs or at 456 * specific points during operation. This lets the driver have a 457 * single list of registers for both. 458 */ 459 void drm_print_regset32(struct drm_printer *p, struct debugfs_regset32 *regset) 460 { 461 int namelen = 0; 462 int i; 463 464 for (i = 0; i < regset->nregs; i++) 465 namelen = max(namelen, (int)strlen(regset->regs[i].name)); 466 467 for (i = 0; i < regset->nregs; i++) { 468 drm_printf(p, "%*s = 0x%08x\n", 469 namelen, regset->regs[i].name, 470 readl(regset->base + regset->regs[i].offset)); 471 } 472 } 473 EXPORT_SYMBOL(drm_print_regset32); 474 #endif 475