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