openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

bcm-diag.c (7773B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  */
      7 
      8 #include <gmodule.h> /* Must be included first */
      9 
     10 #include <sal/core/sync.h>
     11 #include <sal/core/thread.h>
     12 #include <sal/core/dpc.h>
     13 #include <sal/appl/sal.h>
     14 #include <soc/portmod/portmod_internal.h>
     15 
     16 #include <linux-bde.h>
     17 
     18 #include <appl/diag/sysconf.h>
     19 #include <appl/diag/system.h>
     20 
     21 #include <bcm-core.h>
     22 
     23 /* All shell io is done using a user/kernel proxy service. */
     24 #include <linux-uk-proxy.h>
     25 
     26 
     27 MODULE_AUTHOR("Broadcom Corporation");
     28 MODULE_DESCRIPTION("BCM Diag Shell");
     29 MODULE_LICENSE("Proprietary");
     30 
     31 /* Debug output */
     32 static int debug;
     33 LKM_MOD_PARAM(debug, "i", int, 0);
     34 MODULE_PARM_DESC(debug,
     35 "Set debug level (default 0)");
     36 
     37 static int boot_flags = 0;
     38 LKM_MOD_PARAM(boot_flags, "i", int, 0);
     39 MODULE_PARM_DESC(boot_flags, "boot flags");
     40 
     41 /* Module Information */
     42 #define MODULE_MAJOR 124
     43 #define MODULE_MINOR 0
     44 #define MODULE_NAME      "linux-bcm-diag"
     45 #define PROXY_SERVICE	 "BCM DIAG SHELL"
     46 
     47 /* Maximum string we can handle in printf */
     48 #define PROXY_STRING_MAX (LUK_MAX_DATA_SIZE * 6)
     49 
     50 /* Message buffer */
     51 #define DBUF_DATA_SIZE 128
     52 typedef struct _dbuf_t {
     53     char data[DBUF_DATA_SIZE];
     54 } dbuf_t;
     55 #define DBUF_DATA(dbuf) dbuf->data
     56 
     57 /* Buffer console messages from interrupt context */
     58 #define DBUF_CNT_MAX 32
     59 static dbuf_t dbuf[DBUF_CNT_MAX];
     60 static dbuf_t dbuf_flush[DBUF_CNT_MAX];
     61 static volatile int dbuf_cnt;
     62 static spinlock_t dbuf_lock;
     63 static struct semaphore dbuf_sem;
     64 
     65 /* Thread control flags */
     66 static volatile int _bcm_shell_running;
     67 static sal_thread_t _bcm_shell_thread;
     68 static sal_thread_t orig_main_thread;
     69 
     70 extern int 
     71 tty_vprintf(const char* fmt, va_list args)
     72     __attribute__ ((format (printf, 1, 0)));
     73 
     74 extern int
     75 tty_printf(const char* fmt, ...)
     76     __attribute__ ((format (printf, 1, 2)));
     77 
     78 /* Linux kernel threads must check signals explicitely. */
     79 static void
     80 check_exit_signals(void)
     81 {
     82     if(signal_pending(current)) {
     83         sal_dpc_term();
     84         sal_thread_exit(0);
     85     }
     86 }
     87 
     88 static void
     89 _tty_flush(void *p1, void *p2, void *p3, void *p4, void *p5)
     90 {
     91     int cnt;
     92     int dbuf_flush_cnt;
     93     unsigned long flags;
     94     dbuf_t *d;
     95     char *p;
     96 
     97     /* Prevent flushing from multiple threads simultaneously */
     98     if (down_interruptible(&dbuf_sem) != 0) {
     99         /* Something's wrong */
    100         return;
    101     }
    102 
    103     /* Copy pending data to flush buffer */
    104     spin_lock_irqsave(&dbuf_lock, flags);
    105     memcpy(dbuf_flush, dbuf, dbuf_cnt * sizeof(dbuf_t));
    106     dbuf_flush_cnt = dbuf_cnt;
    107     dbuf_cnt = 0;
    108     spin_unlock_irqrestore(&dbuf_lock, flags);
    109 
    110     /* Note that we may sleep during flush */
    111     for (cnt = 0; cnt < dbuf_flush_cnt; cnt++) {
    112         d = &dbuf_flush[cnt];
    113         p = DBUF_DATA(d);
    114         linux_uk_proxy_send(PROXY_SERVICE, p, strlen(p));
    115     }
    116 
    117     up(&dbuf_sem);
    118 }
    119 
    120 int 
    121 tty_vprintf(const char* fmt, va_list args)
    122 {
    123     int cnt, tmp_cnt, offset=0; 
    124     unsigned long flags;
    125     static char s[PROXY_STRING_MAX]; 
    126 
    127     if (sal_no_sleep()) {
    128         /* Schedule flush function */
    129         if (dbuf_cnt == 0) {
    130             sal_dpc(_tty_flush, 0, 0, 0, 0, 0);
    131         }
    132         /* Buffer message */
    133         spin_lock_irqsave(&dbuf_lock, flags);
    134         if (dbuf_cnt < DBUF_CNT_MAX) {
    135             dbuf_t *d = &dbuf[dbuf_cnt++];
    136             vsnprintf(DBUF_DATA(d), DBUF_DATA_SIZE-1, fmt, args);
    137         }
    138         spin_unlock_irqrestore(&dbuf_lock, flags);
    139         return 0;
    140     }
    141 
    142     if (dbuf_cnt) {
    143         /* Flush buffered messages */
    144         _tty_flush(0, 0, 0, 0, 0);
    145     }
    146 
    147     tmp_cnt = cnt = vsnprintf(s, PROXY_STRING_MAX - 1, fmt, args);
    148     if (tmp_cnt >= PROXY_STRING_MAX) {
    149         tmp_cnt = PROXY_STRING_MAX;
    150     }
    151     while (tmp_cnt > 0) {
    152         linux_uk_proxy_send(PROXY_SERVICE, &s[offset],
    153                    (tmp_cnt < LUK_MAX_DATA_SIZE) ? tmp_cnt : LUK_MAX_DATA_SIZE);
    154         tmp_cnt -= LUK_MAX_DATA_SIZE;
    155         offset += LUK_MAX_DATA_SIZE;
    156     }
    157     check_exit_signals();
    158     return cnt; 
    159 }
    160 
    161 /*
    162  * Function: tty_printf
    163  *
    164  * Purpose:
    165  *    Application-specific console output function.
    166  * Parameters:
    167  *    Same as standard C printf.
    168  * Returns:
    169  *    Same as standard C printf.
    170  */
    171 int
    172 tty_printf(const char* fmt, ...)
    173 {
    174     va_list args;
    175     va_start(args, fmt);
    176     return tty_vprintf(fmt, args);
    177 }
    178 
    179 /*
    180  * Function: tty_gets
    181  *
    182  * Purpose:
    183  *    Application-specific console input function.
    184  * Parameters:
    185  *    Same as standard C fgets.
    186  * Returns:
    187  *    Same as standard C fgets.
    188  */
    189 char *
    190 tty_gets(char* dst, int size)
    191 {
    192     linux_uk_proxy_recv(PROXY_SERVICE, dst, (unsigned int *)&size); 
    193     check_exit_signals();
    194     return dst; 
    195 }
    196 
    197 /*
    198  * Function: _bcm_shell
    199  *
    200  * Purpose:
    201  *    Thread entry used to run an instance of the BCM diag shell
    202  * Parameters:
    203  *    None
    204  * Returns:
    205  *    Nothing
    206  */
    207 static void
    208 _bcm_shell(void* p)
    209 {
    210     if (sal_core_init() < 0 || sal_appl_init() < 0) {
    211 	gprintk("SAL Initialization failed\n");
    212 	sal_thread_exit(0); 
    213     }
    214     _bcm_shell_thread = sal_thread_self();
    215 
    216     if (boot_flags) {
    217         sal_boot_flags_set(boot_flags);
    218     }
    219 
    220     if (debug >= 1) gprintk("BCM Diag Module Initialized. Starting proxy...\n"); 
    221 
    222     /* A small delay here prevents the telnet proxy 
    223      * from choking on the first command.
    224      */
    225     sal_usleep(100*1000);
    226     
    227     _bcm_shell_running = 1; 
    228     if (debug >= 1) gprintk("Starting Diag Shell...\n"); 
    229     diag_shell();
    230     if (debug >= 1) gprintk("Diag Shell is done.\n"); 
    231     sal_dpc_term();
    232     linux_bde_destroy(bde);
    233     _bcm_shell_running = 0; 
    234 }
    235 
    236 /*
    237  * Generic module functions
    238  */
    239 
    240 /*
    241  * Function: _pprint
    242  *
    243  * Purpose:
    244  *    Print proc filesystem information.
    245  * Parameters:
    246  *    None
    247  * Returns:
    248  *    Always 0
    249  */
    250 static int
    251 _pprint(void)
    252 {	
    253     pprintf("Broadcom Linux BCM Diagnostic Shell\n"); 
    254     pprintf("\tProxy Service: '%s'\n", PROXY_SERVICE); 
    255     return 0;
    256 }
    257 
    258 /*
    259  * Function: _init
    260  *
    261  * Purpose:
    262  *    Module initialization.
    263  *    Starts the BCM diag thread. 
    264  * Parameters:
    265  *    None
    266  * Returns:
    267  *    Always 0
    268  */
    269 static int
    270 _init(void)
    271 {
    272     spin_lock_init(&dbuf_lock);
    273     sema_init(&dbuf_sem, 1);
    274     orig_main_thread = sal_thread_main_get();
    275     linux_uk_proxy_service_create(PROXY_SERVICE, 1, 0); 
    276     sal_thread_create("bcm-shell", 0, 0, _bcm_shell, 0);
    277     return 0;
    278 }
    279 
    280 /*
    281  * Function: _cleanup
    282  *
    283  * Purpose:
    284  *    Module cleanup function
    285  * Parameters:
    286  *    None
    287  * Returns:
    288  *    Always 0
    289  * Notes:
    290  *    The BCM diag thread will be destroyed to avoid page faults.
    291  */
    292 static int
    293 _cleanup(void)
    294 {
    295     /* Restore debug print vectors */
    296     bcore_debug_set_default();
    297 
    298     /* Restore assert handler */
    299     bcore_assert_set_default();
    300 
    301     /* Close the shell */
    302     if (_bcm_shell_thread) {
    303         sal_thread_destroy(_bcm_shell_thread);
    304 	sal_usleep(200000);
    305     }
    306     /* This should only be relavant on a really busy system */
    307     if (_bcm_shell_running) {
    308 	sal_usleep(200000);
    309     }
    310 
    311     linux_uk_proxy_service_destroy(PROXY_SERVICE);
    312 
    313     /* Restore main thread */
    314     sal_thread_main_set(orig_main_thread);
    315 
    316     return 0;
    317 }	
    318 
    319 /* Module vectors */
    320 static gmodule_t _gmodule = {
    321     name: MODULE_NAME, 
    322     major: MODULE_MAJOR, 
    323     minor: MODULE_MINOR, 
    324     init: _init,
    325     cleanup: _cleanup, 
    326     pprint: _pprint, 
    327     ioctl: NULL,
    328     open: NULL, 
    329     close: NULL, 
    330 }; 
    331 
    332 gmodule_t*
    333 gmodule_get(void)
    334 {
    335 #ifdef LKM_2_4
    336     EXPORT_NO_SYMBOLS;
    337 #endif
    338     return &_gmodule;
    339 }
    340 
    341 #ifdef LKM_2_6
    342 EXPORT_SYMBOL(tty_vprintf);
    343 EXPORT_SYMBOL(tty_printf);
    344 EXPORT_SYMBOL(tty_gets);
    345 #endif
    346 
    347 #if defined(INCLUDE_REGEX)
    348 #include <appl/diag/cmdlist.h>
    349 EXPORT_SYMBOL(cmd_regex);
    350 EXPORT_SYMBOL(cmd_regex_usage);
    351 #endif /* INCLUDE_REGEX */
    352 
    353 EXPORT_SYMBOL(portmod_pm_info_get);