Home | History | Annotate | Line # | Download | only in drm
drm_print.c revision 1.6
      1 /*	$NetBSD: drm_print.c,v 1.6 2021/12/19 09:50:04 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.6 2021/12/19 09:50:04 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/device.h>
     39 #else
     40 #include <stdarg.h>
     41 
     42 #include <linux/io.h>
     43 #include <linux/moduleparam.h>
     44 #endif
     45 #include <linux/seq_file.h>
     46 #include <linux/slab.h>
     47 
     48 #include <drm/drm.h>
     49 #include <drm/drm_drv.h>
     50 #include <drm/drm_print.h>
     51 
     52 /*
     53  * __drm_debug: Enable debug output.
     54  * Bitmask of DRM_UT_x. See include/drm/drm_print.h for details.
     55  */
     56 unsigned int __drm_debug;
     57 EXPORT_SYMBOL(__drm_debug);
     58 
     59 MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n"
     60 "\t\tBit 0 (0x01)  will enable CORE messages (drm core code)\n"
     61 "\t\tBit 1 (0x02)  will enable DRIVER messages (drm controller code)\n"
     62 "\t\tBit 2 (0x04)  will enable KMS messages (modesetting code)\n"
     63 "\t\tBit 3 (0x08)  will enable PRIME messages (prime code)\n"
     64 "\t\tBit 4 (0x10)  will enable ATOMIC messages (atomic code)\n"
     65 "\t\tBit 5 (0x20)  will enable VBL messages (vblank code)\n"
     66 "\t\tBit 7 (0x80)  will enable LEASE messages (leasing code)\n"
     67 "\t\tBit 8 (0x100) will enable DP messages (displayport code)");
     68 module_param_named(debug, __drm_debug, int, 0600);
     69 
     70 void __drm_puts_coredump(struct drm_printer *p, const char *str)
     71 {
     72 	struct drm_print_iterator *iterator = p->arg;
     73 	ssize_t len;
     74 
     75 	if (!iterator->remain)
     76 		return;
     77 
     78 	if (iterator->offset < iterator->start) {
     79 		ssize_t copy;
     80 
     81 		len = strlen(str);
     82 
     83 		if (iterator->offset + len <= iterator->start) {
     84 			iterator->offset += len;
     85 			return;
     86 		}
     87 
     88 		copy = len - (iterator->start - iterator->offset);
     89 
     90 		if (copy > iterator->remain)
     91 			copy = iterator->remain;
     92 
     93 		/* Copy out the bit of the string that we need */
     94 		memcpy(iterator->data,
     95 			str + (iterator->start - iterator->offset), copy);
     96 
     97 		iterator->offset = iterator->start + copy;
     98 		iterator->remain -= copy;
     99 	} else {
    100 		ssize_t pos = iterator->offset - iterator->start;
    101 
    102 		len = min_t(ssize_t, strlen(str), iterator->remain);
    103 
    104 		memcpy((char *)iterator->data + pos, str, len);
    105 
    106 		iterator->offset += len;
    107 		iterator->remain -= len;
    108 	}
    109 }
    110 EXPORT_SYMBOL(__drm_puts_coredump);
    111 
    112 void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf)
    113 {
    114 	struct drm_print_iterator *iterator = p->arg;
    115 	size_t len;
    116 	char *buf;
    117 
    118 	if (!iterator->remain)
    119 		return;
    120 
    121 	/* Figure out how big the string will be */
    122 	len = snprintf(NULL, 0, "%pV", vaf);
    123 
    124 	/* This is the easiest path, we've already advanced beyond the offset */
    125 	if (iterator->offset + len <= iterator->start) {
    126 		iterator->offset += len;
    127 		return;
    128 	}
    129 
    130 	/* Then check if we can directly copy into the target buffer */
    131 	if ((iterator->offset >= iterator->start) && (len < iterator->remain)) {
    132 		ssize_t pos = iterator->offset - iterator->start;
    133 
    134 		snprintf(((char *) iterator->data) + pos,
    135 			iterator->remain, "%pV", vaf);
    136 
    137 		iterator->offset += len;
    138 		iterator->remain -= len;
    139 
    140 		return;
    141 	}
    142 
    143 	/*
    144 	 * Finally, hit the slow path and make a temporary string to copy over
    145 	 * using _drm_puts_coredump
    146 	 */
    147 	buf = kmalloc(len + 1, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
    148 	if (!buf)
    149 		return;
    150 
    151 	snprintf(buf, len + 1, "%pV", vaf);
    152 	__drm_puts_coredump(p, (const char *) buf);
    153 
    154 	kfree(buf);
    155 }
    156 EXPORT_SYMBOL(__drm_printfn_coredump);
    157 
    158 #ifndef __NetBSD__		/* XXX seq file */
    159 void __drm_puts_seq_file(struct drm_printer *p, const char *str)
    160 {
    161 	seq_puts(p->arg, str);
    162 }
    163 EXPORT_SYMBOL(__drm_puts_seq_file);
    164 #endif
    165 
    166 #ifndef __NetBSD__		/* XXX seq file */
    167 void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf)
    168 {
    169 	seq_printf(p->arg, "%pV", vaf);
    170 }
    171 EXPORT_SYMBOL(__drm_printfn_seq_file);
    172 #endif
    173 
    174 void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf)
    175 {
    176 	dev_info(p->arg, "[" DRM_NAME "] %pV", vaf);
    177 }
    178 EXPORT_SYMBOL(__drm_printfn_info);
    179 
    180 void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf)
    181 {
    182 	pr_debug("%s %pV", p->prefix, vaf);
    183 }
    184 EXPORT_SYMBOL(__drm_printfn_debug);
    185 
    186 void __drm_printfn_err(struct drm_printer *p, struct va_format *vaf)
    187 {
    188 	pr_err("*ERROR* %s %pV", p->prefix, vaf);
    189 }
    190 EXPORT_SYMBOL(__drm_printfn_err);
    191 
    192 /**
    193  * drm_puts - print a const string to a &drm_printer stream
    194  * @p: the &drm printer
    195  * @str: const string
    196  *
    197  * Allow &drm_printer types that have a constant string
    198  * option to use it.
    199  */
    200 void drm_puts(struct drm_printer *p, const char *str)
    201 {
    202 	if (p->puts)
    203 		p->puts(p, str);
    204 	else
    205 		drm_printf(p, "%s", str);
    206 }
    207 EXPORT_SYMBOL(drm_puts);
    208 
    209 /**
    210  * drm_printf - print to a &drm_printer stream
    211  * @p: the &drm_printer
    212  * @f: format string
    213  */
    214 void drm_printf(struct drm_printer *p, const char *f, ...)
    215 {
    216 	va_list args;
    217 
    218 	va_start(args, f);
    219 	drm_vprintf(p, f, &args);
    220 	va_end(args);
    221 }
    222 EXPORT_SYMBOL(drm_printf);
    223 
    224 /**
    225  * drm_print_bits - print bits to a &drm_printer stream
    226  *
    227  * Print bits (in flag fields for example) in human readable form.
    228  *
    229  * @p: the &drm_printer
    230  * @value: field value.
    231  * @bits: Array with bit names.
    232  * @nbits: Size of bit names array.
    233  */
    234 void drm_print_bits(struct drm_printer *p, unsigned long value,
    235 		    const char * const bits[], unsigned int nbits)
    236 {
    237 	bool first = true;
    238 	unsigned int i;
    239 
    240 	if (WARN_ON_ONCE(nbits > BITS_PER_TYPE(value)))
    241 		nbits = BITS_PER_TYPE(value);
    242 
    243 	for_each_set_bit(i, &value, nbits) {
    244 		if (WARN_ON_ONCE(!bits[i]))
    245 			continue;
    246 		drm_printf(p, "%s%s", first ? "" : ",",
    247 			   bits[i]);
    248 		first = false;
    249 	}
    250 	if (first)
    251 		drm_printf(p, "(none)");
    252 }
    253 EXPORT_SYMBOL(drm_print_bits);
    254 
    255 void drm_dev_printk(const struct device *dev, const char *level,
    256 		    const char *format, ...)
    257 {
    258 #ifdef __NetBSD__
    259 	va_list va;
    260 
    261 	va_start(va, format);
    262 	if (dev)
    263 		printf("%s: ", device_xname(__UNCONST(dev)));
    264 	vprintf(format, va);
    265 	va_end(va);
    266 #else
    267 	struct va_format vaf;
    268 	va_list args;
    269 
    270 	va_start(args, format);
    271 	vaf.fmt = format;
    272 	vaf.va = &args;
    273 
    274 	if (dev)
    275 		dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV",
    276 			   __builtin_return_address(0), &vaf);
    277 	else
    278 		printk("%s" "[" DRM_NAME ":%ps] %pV",
    279 		       level, __builtin_return_address(0), &vaf);
    280 
    281 	va_end(args);
    282 #endif
    283 }
    284 EXPORT_SYMBOL(drm_dev_printk);
    285 
    286 void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
    287 		 const char *format, ...)
    288 {
    289 #ifdef __NetBSD__
    290 	va_list va;
    291 
    292 	if (!(drm_debug & category))
    293 		return;
    294 
    295 	va_start(va, format);
    296 	if (dev)
    297 		printf("%s: ", device_xname(__UNCONST(dev)));
    298 	vprintf(format, va);
    299 	va_end(va);
    300 #else
    301 	struct va_format vaf;
    302 	va_list args;
    303 
    304 	if (!drm_debug_enabled(category))
    305 		return;
    306 
    307 	va_start(args, format);
    308 	vaf.fmt = format;
    309 	vaf.va = &args;
    310 
    311 	if (dev)
    312 		dev_printk(KERN_DEBUG, dev, "[" DRM_NAME ":%ps] %pV",
    313 			   __builtin_return_address(0), &vaf);
    314 	else
    315 		printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
    316 		       __builtin_return_address(0), &vaf);
    317 
    318 	va_end(args);
    319 #endif
    320 }
    321 EXPORT_SYMBOL(drm_dev_dbg);
    322 
    323 void __drm_dbg(enum drm_debug_category category, const char *format, ...)
    324 {
    325 #ifdef __NetBSD__
    326 	va_list va;
    327 
    328 	if (!(drm_debug & category))
    329 		return;
    330 
    331 	va_start(va, format);
    332 	vprintf(format, va);
    333 	va_end(va);
    334 #else
    335 	struct va_format vaf;
    336 	va_list args;
    337 
    338 	if (!drm_debug_enabled(category))
    339 		return;
    340 
    341 	va_start(args, format);
    342 	vaf.fmt = format;
    343 	vaf.va = &args;
    344 
    345 	printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
    346 	       __builtin_return_address(0), &vaf);
    347 
    348 	va_end(args);
    349 #endif
    350 }
    351 EXPORT_SYMBOL(__drm_dbg);
    352 
    353 void __drm_err(const char *format, ...)
    354 {
    355 	struct va_format vaf;
    356 	va_list args;
    357 
    358 	va_start(args, format);
    359 	vaf.fmt = format;
    360 	vaf.va = &args;
    361 
    362 	printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
    363 	       __builtin_return_address(0), &vaf);
    364 
    365 	va_end(args);
    366 }
    367 EXPORT_SYMBOL(__drm_err);
    368 
    369 #ifndef __NetBSD__
    370 /**
    371  * drm_print_regset32 - print the contents of registers to a
    372  * &drm_printer stream.
    373  *
    374  * @p: the &drm printer
    375  * @regset: the list of registers to print.
    376  *
    377  * Often in driver debug, it's useful to be able to either capture the
    378  * contents of registers in the steady state using debugfs or at
    379  * specific points during operation.  This lets the driver have a
    380  * single list of registers for both.
    381  */
    382 void drm_print_regset32(struct drm_printer *p, struct debugfs_regset32 *regset)
    383 {
    384 	int namelen = 0;
    385 	int i;
    386 
    387 	for (i = 0; i < regset->nregs; i++)
    388 		namelen = max(namelen, (int)strlen(regset->regs[i].name));
    389 
    390 	for (i = 0; i < regset->nregs; i++) {
    391 		drm_printf(p, "%*s = 0x%08x\n",
    392 			   namelen, regset->regs[i].name,
    393 			   readl(regset->base + regset->regs[i].offset));
    394 	}
    395 }
    396 EXPORT_SYMBOL(drm_print_regset32);
    397 #endif
    398