rxmon.c (12818B)
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 * File: rxmon.c 8 * Purpose: Implementation of rxmon command 9 * Requires: 10 */ 11 12 #include <shared/bsl.h> 13 14 #include <sal/core/thread.h> 15 #include <soc/types.h> 16 #include <soc/higig.h> 17 #include <soc/dma.h> 18 #include <soc/dcb.h> 19 #include <soc/drv.h> 20 21 #ifdef __KERNEL__ 22 #include <linux/kernel.h> 23 #include <linux/net.h> 24 #include <linux/in.h> 25 #else 26 #include <stdlib.h> 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <netinet/in.h> 30 #endif 31 32 #include <bcm/pkt.h> 33 #include <bcm/rx.h> 34 #include <bcm/error.h> 35 36 #include <appl/diag/system.h> 37 38 /* Default data for configuring RX system */ 39 static bcm_rx_cfg_t rx_cfg = { 40 8 * 1024, /* packet alloc size */ 41 4, /* Packets per chain */ 42 1000, /* Default pkt rate, global (all COS for this device) */ 43 100, /* Burst doesn't matter */ 44 { /* Just configure channel 1 */ 45 {0}, /* Channel 0 is usually TX */ 46 { /* Channel 1, default RX */ 47 4, /* DV count (number of chains) */ 48 1000, /* Default pkt rate */ 49 0, /* No flags */ 50 0xff /* All COS to this channel */ 51 } 52 }, 53 NULL, /* Used default RX alloc and free routines */ 54 NULL, 55 0 /* flags */ 56 }; 57 58 static bcm_rx_chan_cfg_t rx_chan_cfg = { 59 4, /* DV count (number of chains) */ 60 1000, /* Default pkt rate */ 61 0, /* No flags */ 62 0xff /* All COS to this channel */ 63 }; 64 65 static int rx_cb_count; 66 67 /* Packet free queue; use first word of data buffer as next ptr */ 68 static sal_mutex_t pkt_queue_lock[BCM_MAX_NUM_UNITS]; 69 static sal_sem_t pkts_are_ready[BCM_MAX_NUM_UNITS]; 70 static volatile uint32 *pkt_free_queue[BCM_MAX_NUM_UNITS]; 71 static volatile int enqueue_pkts[BCM_MAX_NUM_UNITS]; 72 static volatile int rx_pkt_count[BCM_MAX_NUM_UNITS]; 73 74 STATIC bcm_rx_t 75 rx_cb_handler(int unit, bcm_pkt_t *info, void *cookie) 76 { 77 int count; 78 79 COMPILER_REFERENCE(cookie); 80 81 count = ++rx_cb_count; 82 83 LOG_INFO(BSL_LS_APPL_RX, 84 (BSL_META_U(unit, 85 "RX packet %d: unit=%d len=%d rx_port=%d reason=%d cos=%d\n"), 86 count, unit, info->tot_len, info->rx_port, info->rx_reason, 87 info->cos)); 88 89 #ifdef BCM_XGS_SUPPORT 90 if (SOC_IS_XGS12_FABRIC(unit)) { 91 if (LOG_CHECK(BSL_LS_APPL_RX | BSL_INFO)) { 92 soc_higig_dump(unit, "HG HEADER: ", 93 (soc_higig_hdr_t *)BCM_PKT_HG_HDR(info)); 94 } 95 } 96 #endif /* BCM_XGS_SUPPORT */ 97 98 LOG_INFO(BSL_LS_APPL_RX, 99 (BSL_META_U(unit, 100 "Parsed packet info:\n"))); 101 LOG_INFO(BSL_LS_APPL_RX, 102 (BSL_META_U(unit, 103 " src mod=%d. src port=%d. op=%d.\n"), 104 info->src_mod, info->src_port, info->opcode)); 105 LOG_INFO(BSL_LS_APPL_RX, 106 (BSL_META_U(unit, 107 " dest mod=%d. dest port=%d. chan=%d.\n"), 108 info->dest_mod, info->dest_port, info->dma_channel)); 109 110 if (LOG_CHECK(BSL_LS_APPL_RX | BSL_INFO)) { 111 soc_dma_dump_pkt(unit, "Data: ", BCM_PKT_DMAC(info), 112 info->tot_len, TRUE); 113 } 114 115 if (enqueue_pkts[unit] > 0) { 116 sal_mutex_take(pkt_queue_lock[unit], sal_mutex_FOREVER); 117 *(uint32 **)(info->alloc_ptr) = (uint32 *)pkt_free_queue[unit]; 118 pkt_free_queue[unit] = info->alloc_ptr; 119 rx_pkt_count[unit]++; 120 if (rx_pkt_count[unit] >= enqueue_pkts[unit]) { 121 sal_sem_give(pkts_are_ready[unit]); 122 } 123 sal_mutex_give(pkt_queue_lock[unit]); 124 #if defined(BCM_RXP_DEBUG) 125 bcm_rx_pool_own(info->alloc_ptr, "rxmon"); 126 #endif 127 return BCM_RX_HANDLED_OWNED; 128 } 129 130 return BCM_RX_HANDLED; 131 } 132 133 STATIC void 134 rx_free_pkts(void *cookie) 135 { 136 uint32 *to_free; 137 uint32 *next; 138 int unit = PTR_TO_INT(cookie); 139 140 while (TRUE) { 141 sal_sem_take(pkts_are_ready[unit], sal_sem_FOREVER); 142 sal_mutex_take(pkt_queue_lock[unit], sal_mutex_FOREVER); 143 to_free = (uint32 *)pkt_free_queue[unit]; 144 pkt_free_queue[unit] = NULL; 145 rx_pkt_count[unit] = 0; 146 sal_mutex_give(pkt_queue_lock[unit]); 147 while (to_free != NULL) { 148 next = *(uint32 **)to_free; 149 bcm_rx_free(unit, to_free); 150 to_free = next; 151 } 152 } 153 } 154 155 #define BASIC_PRIO 100 156 157 STATIC int 158 _init_rx_api(int unit) 159 { 160 int r; 161 162 if (bcm_rx_active(unit)) { 163 cli_out("RX is already running\n"); 164 return -1; 165 } 166 167 if (pw_running(unit)) { 168 cli_out("rxmon: Error: Cannot start RX with packetwatcher running\n"); 169 return -1; 170 } 171 172 if ((r = bcm_rx_start(unit, &rx_cfg)) < 0) { 173 cli_out("rxmon: Error: Cannot start RX: %s.\n", bcm_errmsg(r)); 174 return -1; 175 } 176 177 return 0; 178 } 179 180 cmd_result_t 181 cmd_esw_rx_mon(int unit, args_t *args) 182 /* 183 * Function: rx 184 * Purpose: Perform simple RX test 185 * Parameters: unit - unit number 186 * args - arguments 187 * Returns: CMD_XX 188 */ 189 { 190 char *c; 191 uint32 active; 192 int r; 193 int rv = CMD_OK; 194 195 if (!sh_check_attached(ARG_CMD(args), unit)) { 196 return(CMD_FAIL); 197 } 198 199 bcm_rx_channels_running(unit, &active); 200 201 c = ARG_GET(args); 202 if (c == NULL) { 203 cli_out("Active bitmap for RX is %x.\n", active); 204 return CMD_OK; 205 } 206 207 if (sal_strcasecmp(c, "init") == 0) { 208 if (_init_rx_api(unit) < 0) { 209 return CMD_FAIL; 210 } else { 211 return CMD_OK; 212 } 213 } else if (sal_strcasecmp(c, "enqueue") == 0) { 214 if (pkt_queue_lock[unit] == NULL) { /* Init free pkt stuff */ 215 pkt_queue_lock[unit] = sal_mutex_create("rxmon"); 216 pkts_are_ready[unit] = sal_sem_create("rxmon", sal_sem_BINARY, 0); 217 if (sal_thread_create("rxmon", SAL_THREAD_STKSZ, 80, rx_free_pkts, 218 INT_TO_PTR(unit)) == SAL_THREAD_ERROR) { 219 cli_out("FAILED to start rxmon packet free thread\n"); 220 sal_mutex_destroy(pkt_queue_lock[unit]); 221 pkt_queue_lock[unit] = NULL; 222 sal_sem_destroy(pkts_are_ready[unit]); 223 pkts_are_ready[unit] = NULL; 224 return CMD_FAIL; 225 } 226 } 227 enqueue_pkts[unit] = 1; 228 if ((c = ARG_GET(args)) != NULL) { 229 enqueue_pkts[unit] = strtoul(c, NULL, 0); 230 } 231 } else if (sal_strcasecmp(c, "-enqueue") == 0) { 232 enqueue_pkts[unit] = 0; 233 } else if (sal_strcasecmp(c, "start") == 0) { 234 rx_cb_count = 0; 235 236 if (!bcm_rx_active(unit)) { /* Try to initialize */ 237 if (_init_rx_api(unit) < 0) { 238 cli_out("Warning: init failed. Will attempt register\n"); 239 } 240 } 241 242 /* Register to accept all cos */ 243 if ((r = bcm_rx_register(unit, "RX CMD", rx_cb_handler, 244 BASIC_PRIO, NULL, BCM_RCO_F_ALL_COS)) < 0) { 245 cli_out("%s: bcm_rx_register failed: %s\n", 246 ARG_CMD(args), bcm_errmsg(r)); 247 return CMD_FAIL; 248 } 249 250 cli_out("NOTE: 'debugmod diag rx' required for rxmon output\n"); 251 252 } else if (sal_strcasecmp(c, "stop") == 0) { 253 if ((r = bcm_rx_stop(unit, &rx_cfg)) < 0) { 254 cli_out("%s: Error: Cannot stop RX: %s. Is it running?\n", 255 ARG_CMD(args), bcm_errmsg(r)); 256 return CMD_FAIL; 257 } 258 /* Unregister handler */ 259 if ((r = bcm_rx_unregister(unit, rx_cb_handler, BASIC_PRIO)) < 0) { 260 cli_out("%s: bcm_rx_unregister failed: %s\n", 261 ARG_CMD(args), bcm_errmsg(r)); 262 return CMD_FAIL; 263 } 264 265 } else if (sal_strcasecmp(c, "show") == 0) { 266 #ifdef BROADCOM_DEBUG 267 bcm_rx_show(unit); 268 #else 269 cli_out("%s: ERROR: cannot show in non-BROADCOM_DEBUG compilation\n", 270 ARG_CMD(args)); 271 return CMD_FAIL; 272 #endif /* BROADCOM_DEBUG */ 273 } else { 274 return CMD_USAGE; 275 } 276 277 return rv; 278 } 279 280 static int free_buffers; 281 282 cmd_result_t 283 cmd_esw_rx_cfg(int unit, args_t *args) 284 /* 285 * Function: rx 286 * Purpose: Perform simple RX test 287 * Parameters: unit - unit number 288 * args - arguments 289 * Returns: CMD_XX 290 */ 291 { 292 int chan; 293 parse_table_t pt; 294 bcm_cos_queue_t queue_max; 295 /* This isn't configurable per unit yet. */ 296 int cos_pps[BCM_RX_COS]; 297 char cospps_str[BCM_RX_COS][20]; 298 uint8 cos_pps_init = 0; 299 int rv = BCM_E_NONE; 300 int i; 301 int system_pps = 0; 302 303 if (!cos_pps_init) { 304 for (i = 0; i < BCM_RX_COS; i++) { 305 cos_pps[i] = 100; 306 } 307 cos_pps_init = 1; 308 } 309 310 if (!sh_check_attached(ARG_CMD(args), unit)) { 311 return(CMD_FAIL); 312 } 313 314 if (BCM_FAILURE(bcm_rx_queue_max_get(unit, &queue_max))) { 315 return (CMD_FAIL); 316 } 317 318 if (!ARG_CUR(args)) { 319 int spps; 320 321 /* Display current configuration */ 322 cli_out("Current RX configuration:\n"); 323 cli_out(" Pkt Size %d. Pkts/chain %d. All COS PPS %d. Burst %d\n", 324 rx_cfg.pkt_size, rx_cfg.pkts_per_chain, 325 rx_cfg.global_pps, rx_cfg.max_burst); 326 for (chan = 0; chan < BCM_RX_CHANNELS; chan++) { 327 cli_out(" Channel %d: Chains %d. PPS %d. COSBMP 0x%x.\n", 328 chan, rx_cfg.chan_cfg[chan].chains, 329 rx_cfg.chan_cfg[chan].rate_pps, 330 rx_cfg.chan_cfg[chan].cos_bmp); 331 } 332 if ((rv = bcm_rx_cpu_rate_get(unit, &spps)) < 0) { 333 cli_out("ERROR getting system rate limit: %s\n", 334 bcm_errmsg(rv)); 335 } else { 336 cli_out(" System wide rate limit: %d\n", spps); 337 } 338 return CMD_OK; 339 } 340 341 if (isint(ARG_CUR(args))) { 342 chan = parse_integer(ARG_GET(args)); 343 if (chan < 0 || chan >= BCM_RX_CHANNELS) { 344 cli_out("Error: Bad channel %d\n", chan); 345 return CMD_FAIL; 346 } 347 } else { 348 chan = -1; 349 } 350 351 parse_table_init(unit, &pt); 352 353 /* SPPS must be first, or else adjust pt_entries index below */ 354 parse_table_add(&pt, "SPPS", PQ_DFL|PQ_INT, 0, 355 &system_pps, NULL); 356 parse_table_add(&pt, "GPPS", PQ_DFL|PQ_INT, 0, 357 &rx_cfg.global_pps, NULL); 358 parse_table_add(&pt, "PKTSIZE", PQ_DFL|PQ_INT, 0, 359 &rx_cfg.pkt_size, NULL); 360 parse_table_add(&pt, "PPC", PQ_DFL|PQ_INT, 0, 361 &rx_cfg.pkts_per_chain, NULL); 362 parse_table_add(&pt, "BURST", PQ_DFL|PQ_INT, 0, 363 &rx_cfg.max_burst, NULL); 364 parse_table_add(&pt, "FREE", PQ_DFL|PQ_BOOL, 0, 365 &free_buffers, NULL); 366 367 if (queue_max >= BCM_RX_COS) { 368 cli_out("Error: Too many queues %d > %d\n", queue_max, BCM_RX_COS); 369 parse_arg_eq_done(&pt); 370 return CMD_FAIL; 371 } 372 for (i = 0; i < queue_max; i++) { 373 sal_sprintf(cospps_str[i], "COSPPS%d", i); 374 parse_table_add(&pt, cospps_str[i], PQ_DFL|PQ_INT, 0, 375 &cos_pps[i], NULL); 376 } 377 378 if (chan >= 0) { 379 parse_table_add(&pt, "CHAINS", PQ_DFL|PQ_INT, 0, 380 &rx_chan_cfg.chains, NULL); 381 parse_table_add(&pt, "PPS", PQ_DFL|PQ_INT, 0, 382 &rx_chan_cfg.rate_pps, NULL); 383 parse_table_add(&pt, "COSBMP", PQ_DFL|PQ_HEX, 0, 384 &rx_chan_cfg.cos_bmp, NULL); 385 } 386 387 /* Parse remaining arguments */ 388 if (0 > parse_arg_eq(args, &pt)) { 389 cli_out("%s: Error: Invalid option or malformed expression: %s\n", 390 ARG_CMD(args), ARG_CUR(args)); 391 parse_arg_eq_done(&pt); 392 return(CMD_FAIL); 393 } 394 395 /* Check if SPPS was entered; if so do only that */ 396 if (pt.pt_entries[0].pq_type & PQ_PARSED) { 397 rv = bcm_rx_cpu_rate_set(unit, system_pps); 398 parse_arg_eq_done(&pt); 399 if (rv < 0) { 400 cli_out("Warning: system rate set (to %d) returned %s\n", 401 system_pps, bcm_errmsg(rv)); 402 return CMD_FAIL; 403 } 404 return CMD_OK; 405 } 406 407 parse_arg_eq_done(&pt); 408 409 for (i = 0; i < queue_max; i++) { 410 rv = bcm_rx_cos_rate_set(unit, i, cos_pps[i]); 411 if (rv < 0) { 412 cli_out("Warning: cos rate set(%d to %d) returned %s\n", i, 413 cos_pps[i], bcm_errmsg(rv)); 414 } 415 } 416 417 if (chan >=0 ) { /* Copy external chan cfg to right place */ 418 sal_memcpy(&rx_cfg.chan_cfg[chan], &rx_chan_cfg, 419 sizeof(bcm_rx_chan_cfg_t)); 420 } 421 return CMD_OK; 422 } 423