Files
rtems/cpukit/libdrvmgr/drvmgr_print.c
T
2026-02-05 14:00:25 -06:00

531 lines
13 KiB
C

/* SPDX-License-Identifier: BSD-2-Clause */
/* Driver Manager Information printing Interface Implementation
*
* COPYRIGHT (c) 2009 Cobham Gaisler AB.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* These functions print stuff about the driver manager, what devices were
* found and were united with a driver, the Bus topology, memory taken, etc.
*
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <drvmgr/drvmgr.h>
#include "drvmgr_internal.h"
typedef void ( *fun_ptr )( void );
static int print_dev_found( struct drvmgr_dev *dev, void *arg )
{
char **pparg = arg;
if ( pparg && *pparg ) {
printf( *pparg );
*pparg = NULL;
}
printf(
" DEV %p %s on bus %p\n",
dev,
dev->name ? dev->name : "NO_NAME",
dev->parent
);
return 0; /* Continue to next device */
}
void drvmgr_print_devs( unsigned int options )
{
struct drvmgr *mgr = &drvmgr;
char *parg;
/* Print Drivers */
if ( options & PRINT_DEVS_ASSIGNED ) {
parg = " --- DEVICES ASSIGNED TO DRIVER ---\n";
drvmgr_for_each_listdev(
&mgr->devices[ DRVMGR_LEVEL_MAX ],
DEV_STATE_UNITED,
0,
print_dev_found,
&parg
);
if ( parg != NULL ) {
printf( "\n NO DEVICES WERE ASSIGNED A DRIVER\n" );
}
}
if ( options & PRINT_DEVS_UNASSIGNED ) {
parg = "\n --- DEVICES WITHOUT DRIVER ---\n";
drvmgr_for_each_listdev(
&mgr->devices_inactive,
0,
DEV_STATE_UNITED,
print_dev_found,
&parg
);
if ( parg != NULL ) {
printf( "\n NO DEVICES WERE WITHOUT DRIVER\n" );
}
}
if ( options & PRINT_DEVS_FAILED ) {
parg = "\n --- DEVICES FAILED TO INITIALIZE ---\n";
drvmgr_for_each_listdev(
&mgr->devices_inactive,
DEV_STATE_INIT_FAILED,
0,
print_dev_found,
&parg
);
if ( parg != NULL ) {
printf( "\n NO DEVICES FAILED TO INITIALIZE\n" );
}
}
if ( options & PRINT_DEVS_IGNORED ) {
parg = "\n --- DEVICES IGNORED ---\n";
drvmgr_for_each_listdev(
&mgr->devices_inactive,
DEV_STATE_IGNORED,
0,
print_dev_found,
&parg
);
if ( parg != NULL ) {
printf( "\n NO DEVICES WERE IGNORED\n" );
}
}
printf( "\n\n" );
}
static intptr_t drvmgr_topo_func( struct drvmgr_dev *dev, void *arg )
{
(void) arg;
char prefix[ 32 ];
int depth = dev->parent->depth;
if ( depth > 30 ) {
return 0; /* depth more than 30 not supported */
}
memset( prefix, ' ', depth + 1 );
prefix[ depth + 1 ] = '\0';
printf(
" %s|-> DEV %p %s\n",
prefix,
dev,
dev->name ? dev->name : "NO_NAME"
);
return 0;
}
void drvmgr_print_topo( void )
{
/* Print Bus topology */
printf( " --- BUS TOPOLOGY ---\n" );
drvmgr_for_each_dev( drvmgr_topo_func, NULL, DRVMGR_FED_DF );
printf( "\n\n" );
}
/* Print the memory usage */
void drvmgr_print_mem( void )
{
struct drvmgr *mgr = &drvmgr;
struct drvmgr_bus *bus;
struct drvmgr_dev *dev;
struct drvmgr_drv *drv;
struct drvmgr_bus_res *node;
struct drvmgr_drv_res *res;
struct drvmgr_key *key;
unsigned int busmem = 0;
unsigned int devmem = 0;
unsigned int drvmem = 0;
unsigned int resmem = 0;
unsigned int devprivmem = 0;
DRVMGR_LOCK_READ();
bus = BUS_LIST_HEAD( &mgr->buses[ DRVMGR_LEVEL_MAX ] );
while ( bus ) {
busmem += sizeof( struct drvmgr_bus );
/* Get size of resources on this bus */
node = bus->reslist;
while ( node ) {
resmem += sizeof( struct drvmgr_bus_res );
res = node->resource;
while ( res->keys ) {
resmem += sizeof( struct drvmgr_drv_res );
key = res->keys;
while ( key->key_type != DRVMGR_KT_NONE ) {
resmem += sizeof( struct drvmgr_key );
key++;
}
resmem += sizeof( struct drvmgr_key );
res++;
}
node = node->next;
}
bus = bus->next;
}
drv = DRV_LIST_HEAD( &mgr->drivers );
while ( drv ) {
drvmem += sizeof( struct drvmgr_drv );
drv = drv->next;
}
dev = DEV_LIST_HEAD( &mgr->devices[ DRVMGR_LEVEL_MAX ] );
while ( dev ) {
devmem += sizeof( struct drvmgr_dev );
if ( dev->drv && dev->drv->dev_priv_size > 0 ) {
devprivmem += dev->drv->dev_priv_size;
}
dev = dev->next;
}
DRVMGR_UNLOCK();
printf( " --- MEMORY USAGE ---\n" );
printf( " BUS: %d bytes\n", busmem );
printf( " DRV: %d bytes\n", drvmem );
printf( " DEV: %d bytes\n", devmem );
printf( " DEV private: %d bytes\n", devprivmem );
printf( " RES: %d bytes\n", resmem );
printf(
" TOTAL: %d bytes\n",
busmem + drvmem + devmem + devprivmem + resmem
);
printf( "\n\n" );
}
/* Print the memory usage */
void drvmgr_summary( void )
{
struct drvmgr *mgr = &drvmgr;
struct drvmgr_bus *bus;
struct drvmgr_dev *dev;
struct drvmgr_drv *drv;
int i, buscnt = 0, devcnt = 0, drvcnt = 0;
printf( " --- SUMMARY ---\n" );
drv = DRV_LIST_HEAD( &mgr->drivers );
while ( drv ) {
drvcnt++;
drv = drv->next;
}
printf( " NUMBER OF DRIVERS: %d\n", drvcnt );
DRVMGR_LOCK_READ();
for ( i = 0; i <= DRVMGR_LEVEL_MAX; i++ ) {
buscnt = 0;
bus = BUS_LIST_HEAD( &mgr->buses[ i ] );
while ( bus ) {
buscnt++;
bus = bus->next;
}
if ( buscnt > 0 ) {
printf( " NUMBER OF BUSES IN LEVEL[%d]: %d\n", i, buscnt );
}
}
for ( i = 0; i <= DRVMGR_LEVEL_MAX; i++ ) {
devcnt = 0;
dev = DEV_LIST_HEAD( &mgr->devices[ i ] );
while ( dev ) {
devcnt++;
dev = dev->next;
}
if ( devcnt > 0 ) {
printf( " NUMBER OF DEVS IN LEVEL[%d]: %d\n", i, devcnt );
}
}
DRVMGR_UNLOCK();
printf( "\n\n" );
}
static void print_info( void *p, char *str )
{
(void) p;
printf( " " );
puts( str );
}
void drvmgr_info_dev( struct drvmgr_dev *dev, unsigned int options )
{
if ( !dev ) {
return;
}
printf( " -- DEVICE %p --\n", dev );
if ( options & OPTION_DEV_GENINFO ) {
printf( " PARENT BUS: %p\n", dev->parent );
printf( " NAME: %s\n", dev->name ? dev->name : "NO_NAME" );
printf( " STATE: 0x%08x\n", dev->state );
if ( dev->bus ) {
printf( " BRIDGE TO: %p\n", dev->bus );
}
printf( " INIT LEVEL: %d\n", dev->level );
printf( " ERROR: %d\n", dev->error );
printf( " MINOR BUS: %d\n", dev->minor_bus );
if ( dev->drv ) {
printf( " MINOR DRV: %d\n", dev->minor_drv );
printf(
" DRIVER: %p (%s)\n",
dev->drv,
dev->drv->name ? dev->drv->name : "NO_NAME"
);
printf( " PRIVATE: %p\n", dev->priv );
}
}
if ( options & OPTION_DEV_BUSINFO ) {
printf( " --- DEVICE INFO FROM BUS DRIVER ---\n" );
if ( !dev->parent ) {
printf( " !! device has no parent bus !!\n" );
} else if ( dev->parent->ops->get_info_dev ) {
dev->parent->ops->get_info_dev( dev, print_info, NULL );
} else {
printf( " Bus doesn't implement get_info_dev func\n" );
}
}
if ( options & OPTION_DEV_DRVINFO ) {
if ( dev->drv ) {
printf( " --- DEVICE INFO FROM DEVICE DRIVER ---\n" );
if ( dev->drv->ops->info ) {
dev->drv->ops->info( dev, print_info, NULL, 0, 0 );
} else {
printf( " Driver doesn't implement info func\n" );
}
}
}
}
static void drvmgr_info_bus_map( struct drvmgr_map_entry *map )
{
if ( map == NULL ) {
printf( " Addresses mapped 1:1\n" );
} else if ( map == DRVMGR_TRANSLATE_NO_BRIDGE ) {
printf( " No bridge in this direction\n" );
} else {
while ( map->size != 0 ) {
printf(
" 0x%08lx-0x%08lx => 0x%08lx-0x%08lx %s\n",
(unsigned long) map->from_adr,
(unsigned long) ( map->from_adr + map->size - 1 ),
(unsigned long) map->to_adr,
(unsigned long) ( map->to_adr + map->size - 1 ),
map->name ? map->name : "no label"
);
map++;
}
}
}
void drvmgr_info_bus( struct drvmgr_bus *bus, unsigned int options )
{
struct drvmgr_dev *dev;
/* Print Driver */
printf( "-- BUS %p --\n", bus );
printf( " BUS TYPE: %d\n", bus->bus_type );
printf(
" DEVICE: %p (%s)\n",
bus->dev,
bus->dev->name ? bus->dev->name : "NO_NAME"
);
printf( " OPS: %p\n", bus->ops );
printf( " CHILDREN: %d devices\n", bus->dev_cnt );
printf( " LEVEL: %d\n", bus->level );
printf( " STATE: 0x%08x\n", bus->state );
printf( " ERROR: %d\n", bus->error );
/* Print address mappings up- (to parent) and down- (from parent to
* this bus) stream the bridge of this bus
*/
printf( " DOWN STREAMS BRIDGE MAPPINGS (from parent to this bus)\n" );
drvmgr_info_bus_map( bus->maps_down );
printf( " UP STREAMS BRIDGE MAPPINGS (from this bus to parent)\n" );
drvmgr_info_bus_map( bus->maps_up );
/* Print Devices on this bus? */
if ( options & OPTION_BUS_DEVS ) {
printf( " CHILDREN:\n" );
DRVMGR_LOCK_READ();
dev = bus->children;
while ( dev ) {
printf(
" |- DEV[%02d]: %p %s\n",
dev->minor_bus,
dev,
dev->name ? dev->name : "NO_NAME"
);
dev = dev->next_in_bus;
}
DRVMGR_UNLOCK();
}
}
void drvmgr_info_drv( struct drvmgr_drv *drv, unsigned int options )
{
struct drvmgr_dev *dev;
int i;
/* Print Driver */
printf( " -- DRIVER %p --\n", drv );
printf( " DRIVER ID: 0x%" PRIx64 "\n", drv->drv_id );
printf( " NAME: %s\n", drv->name ? drv->name : "NO_NAME" );
printf( " BUS TYPE: %d\n", drv->bus_type );
printf( " OPERATIONS:\n" );
for ( i = 0; i < DRVMGR_LEVEL_MAX; i++ ) {
printf( " init[%d]: %p\n", i + 1, drv->ops->init[ i ] );
}
printf( " remove: %p\n", drv->ops->remove );
printf( " info: %p\n", drv->ops->info );
printf( " NO. DEVICES: %d\n", drv->dev_cnt );
/* Print devices united with this driver? */
if ( options & OPTION_DRV_DEVS ) {
DRVMGR_LOCK_READ();
dev = drv->dev;
while ( dev ) {
printf(
" DEV[%02d]: %p %s\n",
dev->minor_drv,
dev,
dev->name ? dev->name : "NO_NAME"
);
dev = dev->next_in_drv;
}
DRVMGR_UNLOCK();
}
}
void ( *info_obj[ 3 ] )( void *obj, unsigned int ) = {
/* DRVMGR_OBJ_DRV */ (void ( * )( void *, unsigned int )) drvmgr_info_drv,
/* DRVMGR_OBJ_BUS */ (void ( * )( void *, unsigned int )) drvmgr_info_bus,
/* DRVMGR_OBJ_DEV */ (void ( * )( void *, unsigned int )) drvmgr_info_dev,
};
/* Get information about a device/bus/driver */
void drvmgr_info( void *id, unsigned int options )
{
int obj_type;
void ( *func )( void *, unsigned int );
if ( !id ) {
return;
}
obj_type = *(int *) id;
if ( ( obj_type < DRVMGR_OBJ_DRV ) || ( obj_type > DRVMGR_OBJ_DEV ) ) {
return;
}
func = info_obj[ obj_type - 1 ];
func( id, options );
}
void drvmgr_info_devs_on_bus( struct drvmgr_bus *bus, unsigned int options )
{
struct drvmgr_dev *dev;
/* Print All Devices on Bus */
printf( "\n\n -= All Devices on BUS %p =-\n\n", bus );
dev = bus->children;
while ( dev ) {
drvmgr_info_dev( dev, options );
puts( "" );
dev = dev->next_in_bus;
}
if ( ( options & OPTION_RECURSIVE ) == 0 ) {
return;
}
/* This device provides a bus, print the bus */
dev = bus->children;
while ( dev ) {
if ( dev->bus ) {
drvmgr_info_devs_on_bus( dev->bus, options );
}
dev = dev->next_in_bus;
}
}
void drvmgr_info_devs( unsigned int options )
{
struct drvmgr *mgr = &drvmgr;
struct drvmgr_dev *dev;
/* Print device information of all devices and their child devices */
dev = &mgr->root_dev;
drvmgr_info_devs_on_bus( dev->bus, options );
printf( "\n\n" );
}
void drvmgr_info_drvs( unsigned int options )
{
struct drvmgr *mgr = &drvmgr;
struct drvmgr_drv *drv;
drv = DRV_LIST_HEAD( &mgr->drivers );
while ( drv ) {
drvmgr_info_drv( drv, options );
puts( "\n" );
drv = drv->next;
}
}
void drvmgr_info_buses( unsigned int options )
{
struct drvmgr *mgr = &drvmgr;
struct drvmgr_bus *bus;
bus = BUS_LIST_HEAD( &mgr->buses[ DRVMGR_LEVEL_MAX ] );
while ( bus ) {
drvmgr_info_bus( bus, options );
puts( "\n" );
bus = bus->next;
}
}