2016-11-05 11:08:07 -04:00
/*
* Copyright ( C ) 2016 Red Hat
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*
* Authors :
* Rob Clark < robdclark @ gmail . com >
*/
2017-10-27 12:06:02 +01:00
# define DEBUG /* for pr_debug() */
2016-11-05 11:08:07 -04:00
# include <stdarg.h>
2019-05-26 19:35:35 +02:00
# include <linux/io.h>
2019-09-24 15:58:57 +03:00
# include <linux/moduleparam.h>
2016-11-05 11:08:07 -04:00
# include <linux/seq_file.h>
2019-05-26 19:35:35 +02:00
# include <linux/slab.h>
# include <drm/drm.h>
# include <drm/drm_drv.h>
2016-11-05 11:08:07 -04:00
# include <drm/drm_print.h>
2019-09-24 15:58:57 +03:00
/*
2019-10-28 12:38:18 +02:00
* __drm_debug : Enable debug output .
2019-09-24 15:58:57 +03:00
* Bitmask of DRM_UT_x . See include / drm / drm_print . h for details .
*/
2019-10-28 12:38:18 +02:00
unsigned int __drm_debug ;
EXPORT_SYMBOL ( __drm_debug ) ;
2019-09-24 15:58:57 +03:00
MODULE_PARM_DESC ( debug , " Enable debug output, where each bit enables a debug category. \n "
" \t \t Bit 0 (0x01) will enable CORE messages (drm core code) \n "
" \t \t Bit 1 (0x02) will enable DRIVER messages (drm controller code) \n "
" \t \t Bit 2 (0x04) will enable KMS messages (modesetting code) \n "
" \t \t Bit 3 (0x08) will enable PRIME messages (prime code) \n "
" \t \t Bit 4 (0x10) will enable ATOMIC messages (atomic code) \n "
" \t \t Bit 5 (0x20) will enable VBL messages (vblank code) \n "
" \t \t Bit 7 (0x80) will enable LEASE messages (leasing code) \n "
" \t \t Bit 8 (0x100) will enable DP messages (displayport code) " ) ;
2019-10-28 12:38:18 +02:00
module_param_named ( debug , __drm_debug , int , 0600 ) ;
2019-09-24 15:58:57 +03:00
2018-07-24 10:33:23 -06:00
void __drm_puts_coredump ( struct drm_printer * p , const char * str )
2018-07-24 10:33:20 -06:00
{
struct drm_print_iterator * iterator = p - > arg ;
ssize_t len ;
if ( ! iterator - > remain )
return ;
if ( iterator - > offset < iterator - > start ) {
ssize_t copy ;
2018-07-24 10:33:23 -06:00
len = strlen ( str ) ;
2018-07-24 10:33:20 -06:00
if ( iterator - > offset + len < = iterator - > start ) {
iterator - > offset + = len ;
return ;
}
copy = len - ( iterator - > start - iterator - > offset ) ;
if ( copy > iterator - > remain )
copy = iterator - > remain ;
/* Copy out the bit of the string that we need */
memcpy ( iterator - > data ,
2018-07-24 10:33:23 -06:00
str + ( iterator - > start - iterator - > offset ) , copy ) ;
2018-07-24 10:33:20 -06:00
iterator - > offset = iterator - > start + copy ;
iterator - > remain - = copy ;
} else {
ssize_t pos = iterator - > offset - iterator - > start ;
2018-07-24 10:33:23 -06:00
len = min_t ( ssize_t , strlen ( str ) , iterator - > remain ) ;
2018-07-24 10:33:20 -06:00
2018-07-24 10:33:23 -06:00
memcpy ( iterator - > data + pos , str , len ) ;
2018-07-24 10:33:20 -06:00
2018-07-24 10:33:23 -06:00
iterator - > offset + = len ;
iterator - > remain - = len ;
}
}
EXPORT_SYMBOL ( __drm_puts_coredump ) ;
2018-07-24 10:33:20 -06:00
2018-07-24 10:33:23 -06:00
void __drm_printfn_coredump ( struct drm_printer * p , struct va_format * vaf )
{
struct drm_print_iterator * iterator = p - > arg ;
size_t len ;
char * buf ;
if ( ! iterator - > remain )
return ;
/* Figure out how big the string will be */
len = snprintf ( NULL , 0 , " %pV " , vaf ) ;
/* This is the easiest path, we've already advanced beyond the offset */
if ( iterator - > offset + len < = iterator - > start ) {
iterator - > offset + = len ;
return ;
}
2018-07-24 10:33:20 -06:00
2018-07-24 10:33:23 -06:00
/* Then check if we can directly copy into the target buffer */
if ( ( iterator - > offset > = iterator - > start ) & & ( len < iterator - > remain ) ) {
ssize_t pos = iterator - > offset - iterator - > start ;
2018-07-24 10:33:20 -06:00
2018-07-24 10:33:23 -06:00
snprintf ( ( ( char * ) iterator - > data ) + pos ,
iterator - > remain , " %pV " , vaf ) ;
2018-07-24 10:33:20 -06:00
2018-07-24 10:33:23 -06:00
iterator - > offset + = len ;
iterator - > remain - = len ;
2018-07-24 10:33:20 -06:00
2018-07-24 10:33:23 -06:00
return ;
2018-07-24 10:33:20 -06:00
}
2018-07-24 10:33:23 -06:00
/*
* Finally , hit the slow path and make a temporary string to copy over
* using _drm_puts_coredump
*/
buf = kmalloc ( len + 1 , GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY ) ;
if ( ! buf )
return ;
snprintf ( buf , len + 1 , " %pV " , vaf ) ;
__drm_puts_coredump ( p , ( const char * ) buf ) ;
kfree ( buf ) ;
2018-07-24 10:33:20 -06:00
}
EXPORT_SYMBOL ( __drm_printfn_coredump ) ;
2018-07-24 10:33:22 -06:00
void __drm_puts_seq_file ( struct drm_printer * p , const char * str )
{
seq_puts ( p - > arg , str ) ;
}
EXPORT_SYMBOL ( __drm_puts_seq_file ) ;
2016-11-05 11:08:07 -04:00
void __drm_printfn_seq_file ( struct drm_printer * p , struct va_format * vaf )
{
seq_printf ( p - > arg , " %pV " , vaf ) ;
}
EXPORT_SYMBOL ( __drm_printfn_seq_file ) ;
void __drm_printfn_info ( struct drm_printer * p , struct va_format * vaf )
{
2017-02-15 15:33:18 -08:00
dev_info ( p - > arg , " [ " DRM_NAME " ] %pV " , vaf ) ;
2016-11-05 11:08:07 -04:00
}
EXPORT_SYMBOL ( __drm_printfn_info ) ;
2016-12-28 17:42:09 +01:00
void __drm_printfn_debug ( struct drm_printer * p , struct va_format * vaf )
{
pr_debug ( " %s %pV " , p - > prefix , vaf ) ;
}
EXPORT_SYMBOL ( __drm_printfn_debug ) ;
2019-09-03 16:45:43 -04:00
void __drm_printfn_err ( struct drm_printer * p , struct va_format * vaf )
{
pr_err ( " *ERROR* %s %pV " , p - > prefix , vaf ) ;
}
EXPORT_SYMBOL ( __drm_printfn_err ) ;
2018-07-24 10:33:21 -06:00
/**
* drm_puts - print a const string to a & drm_printer stream
* @ p : the & drm printer
* @ str : const string
*
* Allow & drm_printer types that have a constant string
* option to use it .
*/
void drm_puts ( struct drm_printer * p , const char * str )
{
if ( p - > puts )
p - > puts ( p , str ) ;
else
drm_printf ( p , " %s " , str ) ;
}
EXPORT_SYMBOL ( drm_puts ) ;
2016-11-14 12:58:22 +01:00
/**
* drm_printf - print to a & drm_printer stream
* @ p : the & drm_printer
* @ f : format string
*/
2016-11-05 11:08:07 -04:00
void drm_printf ( struct drm_printer * p , const char * f , . . . )
{
va_list args ;
va_start ( args , f ) ;
2017-11-23 08:40:46 +00:00
drm_vprintf ( p , f , & args ) ;
2016-11-05 11:08:07 -04:00
va_end ( args ) ;
}
EXPORT_SYMBOL ( drm_printf ) ;
2017-10-17 22:30:07 -06:00
2019-09-04 07:47:34 +02:00
/**
* drm_print_bits - print bits to a & drm_printer stream
*
* Print bits ( in flag fields for example ) in human readable form .
*
* @ p : the & drm_printer
* @ value : field value .
* @ bits : Array with bit names .
2019-09-23 08:58:14 +02:00
* @ nbits : Size of bit names array .
2019-09-04 07:47:34 +02:00
*/
2019-09-23 08:58:14 +02:00
void drm_print_bits ( struct drm_printer * p , unsigned long value ,
const char * const bits [ ] , unsigned int nbits )
2019-09-04 07:47:34 +02:00
{
bool first = true ;
unsigned int i ;
2019-09-23 08:58:14 +02:00
if ( WARN_ON_ONCE ( nbits > BITS_PER_TYPE ( value ) ) )
nbits = BITS_PER_TYPE ( value ) ;
for_each_set_bit ( i , & value , nbits ) {
if ( WARN_ON_ONCE ( ! bits [ i ] ) )
2019-09-04 07:47:34 +02:00
continue ;
drm_printf ( p , " %s%s " , first ? " " : " , " ,
2019-09-23 08:58:14 +02:00
bits [ i ] ) ;
2019-09-04 07:47:34 +02:00
first = false ;
}
if ( first )
drm_printf ( p , " (none) " ) ;
}
EXPORT_SYMBOL ( drm_print_bits ) ;
2017-10-17 22:30:07 -06:00
void drm_dev_printk ( const struct device * dev , const char * level ,
2018-03-16 13:56:27 -07:00
const char * format , . . . )
{
struct va_format vaf ;
va_list args ;
va_start ( args , format ) ;
vaf . fmt = format ;
vaf . va = & args ;
if ( dev )
dev_printk ( level , dev , " [ " DRM_NAME " :%ps] %pV " ,
__builtin_return_address ( 0 ) , & vaf ) ;
else
printk ( " %s " " [ " DRM_NAME " :%ps] %pV " ,
level , __builtin_return_address ( 0 ) , & vaf ) ;
va_end ( args ) ;
}
EXPORT_SYMBOL ( drm_dev_printk ) ;
void drm_dev_dbg ( const struct device * dev , unsigned int category ,
const char * format , . . . )
2017-10-17 22:30:07 -06:00
{
struct va_format vaf ;
va_list args ;
2019-10-01 17:06:14 +03:00
if ( ! drm_debug_enabled ( category ) )
2017-10-17 22:30:07 -06:00
return ;
va_start ( args , format ) ;
vaf . fmt = format ;
vaf . va = & args ;
if ( dev )
2018-03-16 13:56:27 -07:00
dev_printk ( KERN_DEBUG , dev , " [ " DRM_NAME " :%ps] %pV " ,
__builtin_return_address ( 0 ) , & vaf ) ;
2017-10-17 22:30:07 -06:00
else
2018-03-16 13:56:27 -07:00
printk ( KERN_DEBUG " [ " DRM_NAME " :%ps] %pV " ,
__builtin_return_address ( 0 ) , & vaf ) ;
2017-10-17 22:30:07 -06:00
va_end ( args ) ;
}
2018-03-16 13:56:27 -07:00
EXPORT_SYMBOL ( drm_dev_dbg ) ;
2017-10-17 22:30:07 -06:00
2018-03-13 15:02:15 -07:00
void drm_dbg ( unsigned int category , const char * format , . . . )
2017-10-17 22:30:07 -06:00
{
struct va_format vaf ;
va_list args ;
2019-10-01 17:06:14 +03:00
if ( ! drm_debug_enabled ( category ) )
2017-10-17 22:30:07 -06:00
return ;
va_start ( args , format ) ;
vaf . fmt = format ;
vaf . va = & args ;
2018-03-13 15:02:15 -07:00
printk ( KERN_DEBUG " [ " DRM_NAME " :%ps] %pV " ,
__builtin_return_address ( 0 ) , & vaf ) ;
va_end ( args ) ;
}
EXPORT_SYMBOL ( drm_dbg ) ;
void drm_err ( const char * format , . . . )
{
struct va_format vaf ;
va_list args ;
va_start ( args , format ) ;
vaf . fmt = format ;
vaf . va = & args ;
printk ( KERN_ERR " [ " DRM_NAME " :%ps] *ERROR* %pV " ,
__builtin_return_address ( 0 ) , & vaf ) ;
2017-10-17 22:30:07 -06:00
va_end ( args ) ;
}
2018-03-13 15:02:15 -07:00
EXPORT_SYMBOL ( drm_err ) ;
2019-02-20 13:03:37 -08:00
/**
* drm_print_regset32 - print the contents of registers to a
* & drm_printer stream .
*
* @ p : the & drm printer
* @ regset : the list of registers to print .
*
* Often in driver debug , it ' s useful to be able to either capture the
* contents of registers in the steady state using debugfs or at
* specific points during operation . This lets the driver have a
* single list of registers for both .
*/
void drm_print_regset32 ( struct drm_printer * p , struct debugfs_regset32 * regset )
{
int namelen = 0 ;
int i ;
for ( i = 0 ; i < regset - > nregs ; i + + )
namelen = max ( namelen , ( int ) strlen ( regset - > regs [ i ] . name ) ) ;
for ( i = 0 ; i < regset - > nregs ; i + + ) {
drm_printf ( p , " %*s = 0x%08x \n " ,
namelen , regset - > regs [ i ] . name ,
readl ( regset - > base + regset - > regs [ i ] . offset ) ) ;
}
}
EXPORT_SYMBOL ( drm_print_regset32 ) ;