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-full.c (13177B)


      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 <sal/appl/pci.h>
     15 
     16 #include <linux-bde.h>
     17 
     18 #include <appl/diag/sysconf.h>
     19 #include <appl/diag/system.h>
     20 
     21 #include <bcmx/cosq.h>
     22 #include <bcmx/switch.h>
     23 #include <bcm_int/common/ptp.h>
     24 #include <bcm_int/common/sw_an.h>
     25 #if defined(BCM_TOMAHAWK2_SUPPORT)
     26 #include <soc/tomahawk2.h>
     27 #endif
     28 #include <soc/i2c.h>
     29 #if defined(BCM_TRIDENT2_SUPPORT)
     30 #include <bcm_int/esw/trident2.h>
     31 #endif
     32 #include <bcm_int/esw_dispatch.h>
     33 
     34 /* All shell io is done using a user/kernel proxy service. */
     35 #include <linux-uk-proxy.h>
     36 
     37 
     38 
     39 MODULE_AUTHOR("Broadcom Corporation");
     40 MODULE_DESCRIPTION("BCM Diag Shell Full");
     41 MODULE_LICENSE("Proprietary");
     42 
     43 /* Debug output */
     44 static int debug;
     45 LKM_MOD_PARAM(debug, "i", int, 0);
     46 MODULE_PARM_DESC(debug,
     47 "Set debug level (default 0)");
     48 
     49 /* Create proxy service */
     50 static int proxy = 1;
     51 LKM_MOD_PARAM(proxy, "i", int, 0);
     52 MODULE_PARM_DESC(proxy,
     53 "Create proxy service (default 1)");
     54 
     55 static int boot_flags = 0;
     56 LKM_MOD_PARAM(boot_flags, "i", int, 0);
     57 MODULE_PARM_DESC(boot_flags, "boot flags");
     58 
     59 /*
     60  * Linux Module/Library References
     61  *
     62  * Not all of the BCM/BCMX functions are referenced by the driver
     63  * itself. Because of this, some of the orphan functions may not
     64  * get linked into the module. Since we want these functions to
     65  * be available to client modules which might be inserted later,
     66  * we reference them here to make sure they get linked in.
     67  */
     68 typedef void (*orphan)(void);
     69 
     70 static orphan orphans[] = {
     71 #if defined(INCLUDE_BCMX)
     72     (orphan)bcmx_cosq_config_set,
     73     (orphan)bcmx_cosq_mapping_set,
     74     (orphan)bcmx_switch_control_set
     75 #endif /* INCLUDE_BCMX */
     76 };
     77 
     78 /* Module Information */
     79 #define MODULE_MAJOR 124
     80 #define MODULE_MINOR 0
     81 #define MODULE_NAME      "linux-bcm-diag-full"
     82 #define PROXY_SERVICE	 "BCM DIAG SHELL"
     83 
     84 /* Maximum string we can handle in printf */
     85 #define PROXY_STRING_MAX (LUK_MAX_DATA_SIZE * 6)
     86 
     87 /* Message buffer */
     88 #define DBUF_DATA_SIZE 128
     89 typedef struct _dbuf_t {
     90     char data[DBUF_DATA_SIZE];
     91 } dbuf_t;
     92 #define DBUF_DATA(dbuf) dbuf->data
     93 
     94 /* Buffer console messages from interrupt context */
     95 #define DBUF_CNT_MAX 32
     96 static dbuf_t dbuf[DBUF_CNT_MAX];
     97 static dbuf_t dbuf_flush[DBUF_CNT_MAX];
     98 static volatile int dbuf_cnt;
     99 static spinlock_t dbuf_lock;
    100 static struct semaphore dbuf_sem;
    101 
    102 /* Thread control flags */
    103 static volatile int _bcm_shell_running = 0;
    104 static sal_thread_t _bcm_shell_thread = 0;
    105 
    106 extern int
    107 tty_vprintf(const char* fmt, va_list args)
    108     __attribute__ ((format (printf, 1, 0)));
    109 
    110 extern int
    111 tty_printf(const char* fmt, ...)
    112     __attribute__ ((format (printf, 1, 2)));
    113 
    114 /*
    115  * The system BDE.
    116  * This BDE can be used by all client modules.
    117  */
    118 ibde_t* bde;
    119 
    120 /* Linux kernel threads must check signals explicitely. */
    121 void
    122 check_exit_signals(void)
    123 {
    124     if(signal_pending(current)) {
    125         sal_dpc_term();
    126         sal_thread_exit(0);
    127     }
    128 }
    129 
    130 /* Proc filesystem information */
    131 static int
    132 _pprint(void)
    133 {
    134     pprintf("Broadcom Linux BCM Full Diagnostic Shell\n");
    135     pprintf("\tProxy Service: '%s'\n", PROXY_SERVICE);
    136     return 0;
    137 }
    138 
    139 static void
    140 _tty_flush(void *p1, void *p2, void *p3, void *p4, void *p5)
    141 {
    142     int cnt;
    143     int dbuf_flush_cnt;
    144     unsigned long flags;
    145     dbuf_t *d;
    146     char *p;
    147 
    148     /* Prevent flushing from multiple threads simultaneously */
    149     if (down_interruptible(&dbuf_sem) != 0) {
    150         /* Something's wrong */
    151         return;
    152     }
    153 
    154     /* Copy pending data to flush buffer */
    155     spin_lock_irqsave(&dbuf_lock, flags);
    156     memcpy(dbuf_flush, dbuf, dbuf_cnt * sizeof(dbuf_t));
    157     dbuf_flush_cnt = dbuf_cnt;
    158     dbuf_cnt = 0;
    159     spin_unlock_irqrestore(&dbuf_lock, flags);
    160 
    161     /* Note that we may sleep during flush */
    162     for (cnt = 0; cnt < dbuf_flush_cnt; cnt++) {
    163         d = &dbuf_flush[cnt];
    164         p = DBUF_DATA(d);
    165         linux_uk_proxy_send(PROXY_SERVICE, p, strlen(p));
    166     }
    167 
    168     up(&dbuf_sem);
    169 }
    170 
    171 int
    172 tty_vprintf(const char* fmt, va_list args)
    173 {
    174     int cnt, tmp_cnt, offset=0;
    175     unsigned long flags;
    176     static char s[PROXY_STRING_MAX];
    177 
    178     if (sal_no_sleep()) {
    179         /* Schedule flush function */
    180         if (dbuf_cnt == 0) {
    181             sal_dpc(_tty_flush, 0, 0, 0, 0, 0);
    182         }
    183         /* Buffer message */
    184         spin_lock_irqsave(&dbuf_lock, flags);
    185         if (dbuf_cnt < DBUF_CNT_MAX) {
    186             dbuf_t *d = &dbuf[dbuf_cnt++];
    187             vsnprintf(DBUF_DATA(d), DBUF_DATA_SIZE-1, fmt, args);
    188         }
    189         spin_unlock_irqrestore(&dbuf_lock, flags);
    190         return 0;
    191     }
    192 
    193     if (dbuf_cnt) {
    194         /* Flush buffered messages */
    195         _tty_flush(0, 0, 0, 0, 0);
    196     }
    197 
    198     tmp_cnt = cnt = vsnprintf(s, PROXY_STRING_MAX - 1, fmt, args);
    199     if (tmp_cnt >= PROXY_STRING_MAX) {
    200         tmp_cnt = PROXY_STRING_MAX;
    201     }
    202     while (tmp_cnt > 0) {
    203         linux_uk_proxy_send(PROXY_SERVICE, &s[offset],
    204                    (tmp_cnt < LUK_MAX_DATA_SIZE) ? tmp_cnt : LUK_MAX_DATA_SIZE);
    205         tmp_cnt -= LUK_MAX_DATA_SIZE;
    206         offset += LUK_MAX_DATA_SIZE;
    207     }
    208     check_exit_signals();
    209     return cnt;
    210 }
    211 
    212 int
    213 tty_printf(const char* fmt, ...)
    214 {
    215     va_list args;
    216     va_start(args, fmt);
    217     return tty_vprintf(fmt, args);
    218 }
    219 
    220 char*
    221 tty_gets(char* dst, int size)
    222 {
    223     while (linux_uk_proxy_recv(PROXY_SERVICE, dst, (unsigned int *)&size) < 0) {
    224         sal_sleep(1);
    225     }
    226     check_exit_signals();
    227     return dst;
    228 }
    229 
    230 char*
    231 tty_fgets(char* dst, int size, int fh)
    232 {
    233     while (linux_uk_proxy_recv(PROXY_SERVICE, dst, (unsigned int *)&size) < 0) {
    234         sal_sleep(1);
    235     }
    236     check_exit_signals();
    237     return dst;
    238 }
    239 
    240 /*
    241  * Function: _bcm_shell
    242  *
    243  * Purpose:
    244  *    Thread entry used to run an instance of the BCM diag shell
    245  * Parameters:
    246  *    None
    247  * Returns:
    248  *    Nothing
    249  */
    250 static void
    251 _bcm_shell(void* p)
    252 {
    253     if (sal_core_init() < 0 || sal_appl_init() < 0) {
    254 	gprintk("SAL Initialization failed\n");
    255 	sal_thread_exit(0);
    256     }
    257     _bcm_shell_thread = sal_thread_self();
    258 
    259     if (boot_flags) {
    260         sal_boot_flags_set(boot_flags);
    261     }
    262 
    263     if (debug >= 1) gprintk("BCM Diag Module Initialized. Starting proxy...\n");
    264 
    265     /* A small delay here prevents the telnet proxy
    266      * from choking on the first command.
    267      */
    268     sal_usleep(100*1000);
    269 
    270     _bcm_shell_running = 1;
    271     if (debug >= 1) gprintk("Starting Diag Shell...\n");
    272     diag_shell();
    273     if (debug >= 1) gprintk("Diag Shell is done.\n");
    274     sal_dpc_term();
    275     linux_bde_destroy(bde);
    276     _bcm_shell_running = 0;
    277 }
    278 
    279 
    280 /*
    281  * Function: bde_create
    282  *
    283  * Purpose:
    284  *    Create BDE for hardware platform.
    285  * Parameters:
    286  *    None
    287  * Returns:
    288  *    0 if no errors, otherwise -1.
    289  */
    290 int
    291 bde_create(void)
    292 {
    293     linux_bde_bus_t bus;
    294     bus.be_pio = SYS_BE_PIO;
    295     bus.be_packet = SYS_BE_PACKET;
    296     bus.be_other = SYS_BE_OTHER;
    297     if (debug >= 2) gprintk("BDE create\n");
    298     return linux_bde_create(&bus, &bde);
    299 }
    300 
    301 /*
    302  * Function: sal_dma_alloc
    303  *
    304  * Purpose:
    305  *    SAL DMA memory allocation function
    306  * Parameters:
    307  *    size - number of bytes to allocate
    308  *    s - string associated with allocation
    309  * Returns:
    310  *    Pointer to allocated memory or NULL.
    311  */
    312 void*
    313 sal_dma_alloc(unsigned int size, char * name)
    314 {
    315     return bde->salloc(0, size, name);
    316 }
    317 
    318 /*
    319  * Function: sal_dma_free
    320  *
    321  * Purpose:
    322  *    SAL DMA memory free function
    323  * Parameters:
    324  *    ptr - pointer to memory allocated memory with sal_dma_alloc
    325  * Returns:
    326  *    Nothing
    327  */
    328 void
    329 sal_dma_free(void *ptr)
    330 {
    331     bde->sfree(0, ptr);
    332 }
    333 
    334 /*
    335  * When compiled in debug mode (-DBROADCOM_DEBUG) the sal_alloc_purge function
    336  * will cleanup all memory allocated by sal_alloc. The optional callback
    337  * function will allow the caller to print information about memory
    338  * freed by the sal_alloc_purge function.
    339  */
    340 extern void
    341 sal_alloc_purge(void (*print_func)(void *ptr, unsigned int size, char *s));
    342 
    343 /*
    344  * Function: _purge_print_func
    345  *
    346  * Purpose:
    347  *    Print information about unfreed memory when module is unloaded.
    348  * Parameters:
    349  *    ptr - pointer to memory allocated memory with sal_alloc
    350  *    size - size of allocated memory
    351  *    s - user description of memory block
    352  * Returns:
    353  *    Nothing
    354  * Notes:
    355  *    Since this function may print a lot of information (which will
    356  *    take a while on a 9600 bps serial link), it will only be active
    357  *    if the module is loaded with the debug flag set to a non-zero
    358  *    value.
    359  */
    360 static void
    361 _purge_print_func(void *ptr, unsigned int size, char *s)
    362 {
    363     if (debug >= 1) {
    364         gprintk("Freeing %d bytes @ %08lx (%s)\n", size, (unsigned long)ptr, s);
    365     }
    366 }
    367 
    368 /*
    369  * Generic module functions
    370  */
    371 
    372 /*
    373  * Function: _init
    374  *
    375  * Purpose:
    376  *    Module initialization.
    377  *    Starts the BCM diag thread.
    378  * Parameters:
    379  *    None
    380  * Returns:
    381  *    Always 0
    382  */
    383 static int
    384 _init(void)
    385 {
    386     spin_lock_init(&dbuf_lock);
    387     sema_init(&dbuf_sem, 1);
    388     if (proxy) {
    389         linux_uk_proxy_service_create(PROXY_SERVICE, 1, 0);
    390     } else {
    391         gprintk("Proxy service disabled\n");
    392     }
    393     sal_thread_create("bcm-shell", 0, 0, _bcm_shell, 0);
    394     return 0;
    395 }
    396 
    397 /*
    398  * Function: _cleanup
    399  *
    400  * Purpose:
    401  *    Module cleanup function
    402  * Parameters:
    403  *    None
    404  * Returns:
    405  *    Always 0
    406  * Notes:
    407  *    The BCM diag thread will be destroyed to avoid page faults.
    408  */
    409 static int
    410 _cleanup(void)
    411 {
    412     /*
    413      * Try and close the shell
    414      */
    415 
    416     if (_bcm_shell_thread) {
    417         sal_thread_destroy(_bcm_shell_thread);
    418 	sal_usleep(200000);
    419     }
    420 
    421     if (_bcm_shell_running) {
    422 	sal_usleep(200000);
    423     }
    424 
    425     linux_uk_proxy_service_destroy(PROXY_SERVICE);
    426 
    427     /* Clean up all unfreed memory (debug mode only) */
    428     sal_alloc_purge(_purge_print_func);
    429 
    430     return 0;
    431 }
    432 
    433 /* Our module vectors */
    434 static gmodule_t _gmodule = {
    435     name: MODULE_NAME,
    436     major: MODULE_MAJOR,
    437     minor: MODULE_MINOR,
    438     init: _init,
    439     cleanup: _cleanup,
    440     pprint: _pprint,
    441     ioctl: NULL,
    442     open: NULL,
    443     close: NULL,
    444 };
    445 
    446 gmodule_t*
    447 gmodule_get(void)
    448 {
    449     COMPILER_REFERENCE(orphans);
    450     return &_gmodule;
    451 }
    452 
    453 /*
    454  * These stubs are here for legacy compatability reasons.
    455  * They are used only by the diag/test code, not the driver,
    456  * so they are really not that important.
    457  */
    458 
    459 void pci_print_all(void)
    460 {
    461 }
    462 
    463 #ifdef BCM_ESW_SUPPORT
    464 #ifdef INCLUDE_PTP
    465 /*
    466  * Function:
    467  *      diag_port_state_description
    468  * Purpose:
    469  *      Interpret PTP port state values.
    470  * Parameters:
    471  *      state - (IN) PTP port state code.
    472  * Returns:
    473  *      Port state description
    474  * Notes:
    475  *      Ref. IEEE Std. 1588-2008, Chapter 8.2.5.3.1, Table 8.
    476  */
    477 STATIC const char*
    478 diag_port_state_description(_bcm_ptp_port_state_t state)
    479 {
    480     switch(state) {
    481     case _bcm_ptp_state_initializing:
    482         return "Init";
    483 
    484     case _bcm_ptp_state_faulty:
    485         return "Faulty";
    486 
    487     case _bcm_ptp_state_disabled:
    488         return "Disabled";
    489 
    490     case _bcm_ptp_state_listening:
    491         return "Listening";
    492 
    493     case _bcm_ptp_state_pre_master:
    494         return "Pre-Master";
    495 
    496     case _bcm_ptp_state_master:
    497         return "Master";
    498 
    499     case _bcm_ptp_state_passive:
    500         return "Passive";
    501 
    502     case _bcm_ptp_state_uncalibrated:
    503         return "Uncalibrated";
    504 
    505     case _bcm_ptp_state_slave:
    506         return "Slave";
    507 
    508     default:
    509         return "<invalid>";
    510     }
    511 }
    512 
    513 EXPORT_SYMBOL(diag_port_state_description);
    514 
    515 #endif
    516 
    517 
    518 EXPORT_SYMBOL(bcm_esw_port_control_get);
    519 #endif /* End BCM_ESW_SUPPORT */
    520 
    521 LKM_EXPORT_SYM(check_exit_signals);
    522 LKM_EXPORT_SYM(tty_vprintf);
    523 LKM_EXPORT_SYM(tty_printf);
    524 LKM_EXPORT_SYM(tty_gets);
    525 LKM_EXPORT_SYM(bde_create);
    526 LKM_EXPORT_SYM(sal_dma_alloc);
    527 LKM_EXPORT_SYM(sal_dma_free);
    528 LKM_EXPORT_SYM(sal_alloc_purge);
    529 LKM_EXPORT_SYM(pci_print_all);
    530 LKM_EXPORT_SYM(bde);
    531 #ifdef SW_AUTONEG_SUPPORT
    532 EXPORT_SYMBOL(bcm_sw_an_enable_get);
    533 EXPORT_SYMBOL(bcm_sw_an_enable_set);
    534 EXPORT_SYMBOL(bcm_sw_an_port_diag);
    535 #endif
    536 #if defined(BCM_TOMAHAWK2_SUPPORT)
    537 EXPORT_SYMBOL(soc_tomahawk2_sed_base_index_check);
    538 #endif
    539 EXPORT_SYMBOL(soc_i2c_custom_device_add);
    540 EXPORT_SYMBOL(soc_i2c_custom_device_remove);
    541 EXPORT_SYMBOL(soc_i2c_dev_driver_get);
    542 #if defined(BCM_TRIDENT2_SUPPORT)
    543 EXPORT_SYMBOL(_bcm_td2_cosq_hw_idx_get);
    544 #endif
    545 
    546 #ifdef LKM_2_6
    547 /* Export all BCM and BCMX API symbols */
    548 #include <bcm_export.h>
    549 #if defined(INCLUDE_BCMX)
    550 #include <bcmx_export.h>
    551 #endif /* INCLUDE_BCMX */
    552 
    553 
    554 #if  defined(INCLUDE_MACSEC)
    555 #include <bcm-core.h>
    556 #endif /* INCLUDE_MACSEC */
    557 #endif /* LKM_2_6 */
    558 #if defined(BCM_DFE_SUPPORT) || defined(BCM_DPP_SUPPORT)
    559 extern int _cpu_write(int d, uint32 addr, uint32 *buf);
    560 extern int _cpu_read(int d, uint32 addr, uint32 *buf);
    561 EXPORT_SYMBOL(_cpu_write);
    562 EXPORT_SYMBOL(_cpu_read);
    563 #endif /* defined(BCM_DFE_SUPPORT) || defined(BCM_DPP_SUPPORT) */
    564 #ifdef BCM_DPP_SUPPORT
    565 extern int _cpu_pci_register(int d);
    566 EXPORT_SYMBOL(_cpu_pci_register);
    567 #endif /* BCM_DPP_SUPPORT */
    568 EXPORT_SYMBOL(sal_get_alloc_counters);
    569 
    570 #if defined (INCLUDE_REGEX)
    571 #include <appl/diag/cmdlist.h>
    572 EXPORT_SYMBOL(cmd_regex);
    573 EXPORT_SYMBOL(cmd_regex_usage);
    574 #endif /* INCLUDE_REGEX */
    575