hercules.c (30675B)
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: hercules.c 8 * Purpose: Driver functions for 5670/5675 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <soc/hercules.h> 14 #include <soc/higig.h> 15 #include <soc/error.h> 16 #include <shared/bsl.h> 17 #include <soc/mem.h> 18 #include <soc/debug.h> 19 20 #ifdef BCM_HERCULES_SUPPORT 21 22 STATIC int 23 soc_hercules_uc_port_set(int unit, soc_port_t ingress_port, int modid, pbmp_t pbmp); 24 STATIC int 25 soc_hercules_vlan_port_init(int unit, soc_port_t ingress_port); 26 STATIC int 27 soc_hercules_vlan_port_init_all(int unit); 28 STATIC int 29 soc_hercules_vlan_port_set(int unit, 30 soc_port_t ingress_port, vlan_id_t vid, pbmp_t pbmp); 31 STATIC int 32 soc_hercules_mc_port_init(int unit, soc_port_t ingress_port); 33 STATIC int 34 soc_hercules_mc_port_init_all(int unit); 35 STATIC int 36 soc_hercules_mc_port_set(int unit, soc_port_t ingress_port, int mcidx, pbmp_t pbmp); 37 STATIC int 38 soc_hercules_mc_port_set_all(int unit, int mcidx, pbmp_t pbmp); 39 STATIC int 40 soc_hercules_port_mmu_init(int unit, int port); 41 STATIC int 42 soc_hercules_pie_init(int unit, int port, pbmp_t pbmp, int testmode); 43 44 /* 45 * ICM/Module Driver/API locals 46 */ 47 48 #define VLAN_RANGE_CHECK(unit)\ 49 if (vid < soc_mem_index_min(unit, MEM_VIDm) ||\ 50 vid > soc_mem_index_max(unit, MEM_VIDm)) {\ 51 return SOC_E_BADID;\ 52 } 53 #define MODID_RANGE_CHECK(unit)\ 54 if (modid < soc_mem_index_min(unit, MEM_UCm) ||\ 55 modid > soc_mem_index_max(unit, MEM_UCm)) {\ 56 return SOC_E_BADID;\ 57 } 58 #define MCIDX_RANGE_CHECK(unit)\ 59 if (mcidx < soc_mem_index_min(unit, MEM_MCm) ||\ 60 mcidx > soc_mem_index_max(unit, MEM_MCm)) {\ 61 return SOC_E_BADID;\ 62 } 63 64 /* 65 * Hercules 1.5 chip driver functions. 66 */ 67 soc_functions_t soc_hercules15_drv_funs = { 68 soc_hercules_misc_init, 69 soc_hercules_mmu_init, 70 soc_hercules_age_timer_get, 71 soc_hercules_age_timer_max_get, 72 soc_hercules_age_timer_set, 73 }; 74 75 int 76 soc_hercules_misc_init(int unit) 77 { 78 uint32 reg, oreg; 79 int use12G, eJitter, port; 80 81 use12G = soc_property_get(unit, spn_CORE_CLOCK_12G, 0); 82 READ_CMIC_RATE_ADJUSTr(unit, ®); 83 oreg = reg; 84 soc_reg_field_set(unit, CMIC_RATE_ADJUSTr, ®, DIVISORf, 85 (use12G ? 189 : 157)); 86 if (reg != oreg) { 87 WRITE_CMIC_RATE_ADJUSTr(unit, reg); 88 } 89 eJitter = soc_property_get(unit, spn_MMU_HOL_JITTER, 0); 90 PBMP_ALL_ITER(unit, port) { 91 SOC_IF_ERROR_RETURN(READ_MMU_CFGr(unit, port, ®)); 92 oreg = reg; 93 soc_reg_field_set(unit, MMU_CFGr, ®, JITTER_ENf, 94 eJitter ? 1 : 0); 95 /* Enable parity generation and checking */ 96 soc_reg_field_set(unit, MMU_CFGr, ®, 97 PARITY_DIAGf, (SAL_BOOT_SIMULATION) ? 0 : 1); 98 if (reg != oreg) { 99 SOC_IF_ERROR_RETURN(WRITE_MMU_CFGr(unit, port, reg)); 100 } 101 } 102 reg = 0; 103 soc_reg_field_set(unit, ING_CTRL2r, ®, 104 DISABLE_MIRROR_SRCMODBLKf, 1); 105 PBMP_HG_ITER(unit, port) { 106 SOC_IF_ERROR_RETURN(WRITE_ING_CTRL2r(unit, port, reg)); 107 } 108 109 /* 110 * The following tables should be initialized with Valid parity 111 * before enabling parity error interrupts. 112 * MEM_UCm 113 * MEM_VIDm 114 * MEM_INGBUFm - initialized by packet store operations. 115 * MEM_MCm 116 * MEM_IPMCm 117 * MEM_ING_SRCMODBLKm 118 * MEM_ING_MODMAPm 119 * MEM_EGR_MODMAPm 120 */ 121 122 return SOC_E_NONE; 123 } 124 125 126 /* 127 * Initialize Hercules MMU Hardware 128 * and setup module database definitions for API Layer. 129 */ 130 int 131 soc_hercules_mmu_init(int unit) 132 { 133 uint32 tmp; 134 int done, mod, port, rv; 135 pbmp_t pbmp_tmp; 136 char pfmt[SOC_PBMP_FMT_LEN]; 137 int idx_min, idx_max; 138 mem_ing_srcmodblk_entry_t mod_blk; 139 140 /* Only valid driver for interconnect devices */ 141 if (!SOC_IS_XGS_FABRIC(unit)) { 142 return SOC_E_NONE; 143 } 144 145 LOG_VERBOSE(BSL_LS_SOC_COMMON, 146 (BSL_META_U(unit, 147 "soc_hercules_mmu_init: unit %d\n"), unit)); 148 149 /* Initialize MMU in CMIC */ 150 rv = soc_hercules_port_mmu_init(unit, CMIC_PORT(unit)); 151 if (rv < 0) { 152 LOG_CLI((BSL_META_U(unit, 153 "soc_hercules_mmu_init: CMIC MMU init failed.\n"))); 154 } 155 156 /* Setup Hercules 10G Port Interface Controller Registers */ 157 PBMP_PORT_ITER(unit, port) { 158 /* Initialize MMU per-port, set test mode on PLI */ 159 rv = soc_hercules_port_mmu_init(unit, port); 160 161 if (rv < 0) { 162 LOG_CLI((BSL_META_U(unit, 163 "soc_hercules_mmu_init: " 164 "MMU init failed (port %s).\n"), 165 SOC_PORT_NAME(unit, port))); 166 } 167 168 /* Initialize PIE per-port */ 169 rv = soc_hercules_pie_init(unit, port, 170 PBMP_ALL(unit), SAL_BOOT_PLISIM); 171 if (rv < 0) { 172 LOG_CLI((BSL_META_U(unit, 173 "soc_hercules_mmu_init: " 174 "Ingress/Egress init failed (port %s).\n"), 175 SOC_PORT_NAME(unit, port))); 176 } 177 } 178 179 /* Wait for H/W to finish initializing itself 180 * NOTE: this is several microseconds, so you would need 181 * a really fast processor to ever see this error, but we 182 * do this to synchronize with the H/W to be safe. 183 */ 184 if (!SAL_BOOT_PLISIM) { 185 PBMP_PORT_ITER(unit, port) { 186 do { 187 SOC_IF_ERROR_RETURN( 188 READ_MMU_ERRSTATr(unit, port, &tmp)); 189 done = soc_reg_field_get(unit, MMU_ERRSTATr, tmp, HW_INITf); 190 if (!done) 191 LOG_CLI((BSL_META_U(unit, 192 "Notice: HW initializing (port %s)\n"), 193 SOC_PORT_NAME(unit, port))); 194 } while (!done); 195 } 196 } 197 198 /* 199 * Should ideally move to misc_init. Init below also genarates the correct 200 * parity bits for the following tables 201 * 202 * The following tables should be initialized with Valid parity 203 * before enabling parity error interrupts. 204 * MEM_UCm 205 * MEM_VIDm 206 * MEM_INGBUFm - initialized by packet store operations. 207 * MEM_MCm 208 * MEM_ING_MODMAPm 209 * MEM_EGR_MODMAPm 210 * MEM_IPMCm 211 * MEM_ING_SRCMODBLKm 212 * 213 * 214 * Zero Module ID table. 215 */ 216 SOC_PBMP_CLEAR(pbmp_tmp); 217 idx_min = soc_mem_index_min(unit, MEM_UCm); 218 idx_max = soc_mem_index_max(unit, MEM_UCm); 219 mod = 0; 220 221 if (!SAL_BOOT_SIMULATION) { 222 for (mod = idx_min; mod <= idx_max; mod++) { 223 rv = soc_hercules_uc_port_set_all(unit, mod, pbmp_tmp); 224 if (rv < 0) break; 225 } 226 } else { 227 rv = soc_hercules_uc_port_set_all(unit, mod, PBMP_CMIC(unit)); 228 } 229 230 if (rv < 0) { 231 LOG_CLI((BSL_META_U(unit, 232 "soc_hercules_mmu_init: " 233 "set UC[MH.MODID=%d] to %s failed.\n"), 234 mod, SOC_PBMP_FMT(PBMP_ALL(unit), pfmt))); 235 } 236 237 /* Flush VLAN table */ 238 if (!SAL_BOOT_SIMULATION) { /* Way too slow for sim */ 239 rv = soc_hercules_vlan_port_init_all(unit); 240 if (rv < 0) { 241 LOG_CLI((BSL_META_U(unit, 242 "ERROR: clearing VLAN tables failed.\n"))); 243 } 244 } 245 246 /* VLAN / DLF Packets (CPU) VID=0 */ 247 rv = soc_hercules_vlan_port_set_all(unit, 0, PBMP_CMIC(unit)); 248 if (rv < 0) { 249 LOG_CLI((BSL_META_U(unit, 250 "soc_hercules_mmu_init: " 251 "set VID[MH.MODID=%d] to %s failed.\n"), 252 VLAN_ID_DEFAULT, SOC_PBMP_FMT(PBMP_ALL(unit), pfmt))); 253 } 254 255 /* VLAN / DLF Packets (VID=1) */ 256 rv = soc_hercules_vlan_port_set_all(unit, VLAN_ID_DEFAULT, PBMP_ALL(unit)); 257 if (rv < 0) { 258 LOG_CLI((BSL_META_U(unit, 259 "soc_hercules_mmu_init: " 260 "set VID[MH.MODID=%d] to %s failed.\n"), 261 VLAN_ID_DEFAULT, SOC_PBMP_FMT(PBMP_ALL(unit), pfmt))); 262 } 263 264 /* MC / IPMC DLF Packets */ 265 if (!SAL_BOOT_SIMULATION) { /* Way too slow for sim */ 266 rv = soc_hercules_mc_port_init_all(unit); 267 if (rv < 0) { 268 LOG_CLI((BSL_META_U(unit, 269 "ERROR: clearing MC tables failed.\n"))); 270 } 271 } 272 273 /* MC / IPMC DLF Packets */ 274 rv = soc_hercules_mc_port_set_all(unit, SOC_HIGIG_DST_MOD_CPU, 275 PBMP_ALL(unit)); 276 if (rv < 0) { 277 LOG_CLI((BSL_META_U(unit, 278 "soc_hercules_mmu_init: " 279 "set MC[MH.MODID=%d] to %s failed.\n"), 280 SOC_HIGIG_DST_MOD_CPU, 281 SOC_PBMP_FMT(PBMP_ALL(unit), pfmt))); 282 } 283 284 rv = soc_mem_clear(unit, MEM_ING_MODMAPm, MEM_BLOCK_ALL, TRUE); 285 if (rv < 0) { 286 LOG_CLI((BSL_META_U(unit, 287 "soc_hercules_mmu_init: ING_MODMAP clear failed\n"))); 288 } 289 rv = soc_mem_clear(unit, MEM_EGR_MODMAPm, MEM_BLOCK_ALL, TRUE); 290 if (rv < 0) { 291 LOG_CLI((BSL_META_U(unit, 292 "soc_hercules_mmu_init: EGR_MODMAP clear failed\n"))); 293 } 294 rv = soc_mem_clear(unit, MEM_TRUNK_PORT_POOLm, MEM_BLOCK_ALL, TRUE); 295 if (rv < 0) { 296 LOG_CLI((BSL_META_U(unit, 297 "soc_hercules_mmu_init: TRUNK_PORT_POOL clear failed\n"))); 298 } 299 rv = soc_mem_clear(unit, MEM_IPMCm, MEM_BLOCK_ALL, TRUE); 300 if (rv < 0) { 301 LOG_CLI((BSL_META_U(unit, 302 "soc_hercules_mmu_init: IPMC clear failed\n"))); 303 } 304 305 sal_memset(&mod_blk, 0, sizeof(mod_blk)); 306 soc_mem_field32_set(unit, MEM_ING_SRCMODBLKm, &mod_blk, 307 BITMAPf, SOC_PBMP_WORD_GET(PBMP_ALL(unit), 0)); 308 309 idx_min = soc_mem_index_min(unit, MEM_ING_SRCMODBLKm); 310 idx_max = soc_mem_index_max(unit, MEM_ING_SRCMODBLKm); 311 for (mod = idx_min; mod <= idx_max; mod++) { 312 rv = soc_mem_write(unit, MEM_ING_SRCMODBLKm, MEM_BLOCK_ALL, 313 mod, &mod_blk); 314 if (rv < 0) { 315 LOG_CLI((BSL_META_U(unit, 316 "soc_hercules_mmu_init: ING_SRCMODBLK init failed\n"))); 317 break; 318 } 319 } 320 PBMP_ALL_ITER(unit, port) { 321 /* Clear any outstanding parity error notification */ 322 SOC_IF_ERROR_RETURN( 323 WRITE_MMU_INTCLRr(unit, port, SOC_ERR_HAND_MMU_ALL_H15)); 324 } 325 326 /* Prep MMU error handling */ 327 SOC_IF_ERROR_RETURN(soc_mmu_error_init(unit)); 328 329 return rv; 330 } 331 332 int 333 soc_hercules_age_timer_get(int unit, int *age_seconds, int *enabled) 334 { 335 COMPILER_REFERENCE(unit); 336 COMPILER_REFERENCE(age_seconds); 337 COMPILER_REFERENCE(enabled); 338 339 return SOC_E_NONE; 340 } 341 342 int 343 soc_hercules_age_timer_set(int unit, int age_seconds, int enabled) 344 { 345 COMPILER_REFERENCE(unit); 346 COMPILER_REFERENCE(age_seconds); 347 COMPILER_REFERENCE(enabled); 348 349 return SOC_E_NONE; 350 } 351 352 int 353 soc_hercules_age_timer_max_get(int unit, int *max_seconds) 354 { 355 COMPILER_REFERENCE(unit); 356 COMPILER_REFERENCE(max_seconds); 357 358 *max_seconds = 0x7fffffff; /* Use max int for BCMX purposes */ 359 360 return SOC_E_NONE; 361 } 362 363 364 /* 365 * Function: 366 * soc_hercules_mem_read 367 * Purpose: 368 * Read a Hercules word addressed memory internal to the SOC. 369 * Notes: 370 * This should only be used for hercules. 371 */ 372 373 int 374 soc_hercules_mem_read(int unit, 375 soc_mem_t mem, 376 int copyno, 377 int index, 378 void *entry_data) 379 { 380 uint32 entry_addr; 381 soc_mem_info_t *meminfo = &SOC_MEM_INFO(unit, mem); 382 int entry_words, word; 383 uint32 *data = (uint32 *)entry_data; 384 385 entry_words = soc_mem_entry_words(unit, mem); 386 387 entry_addr = soc_mem_addr(unit, mem, 0, copyno, 0); 388 entry_addr += index * meminfo->gran; 389 390 if (mem == MEM_PPm && !soc_feature(unit, soc_feature_fabric_debug)) { 391 /* Workaround for A0 problem */ 392 SOC_IF_ERROR_RETURN(soc_hercules_mem_read_word(unit, 393 entry_addr, &(data[0]))); 394 } 395 396 for (word = 0; word < entry_words; word++) { 397 SOC_IF_ERROR_RETURN(soc_hercules_mem_read_word(unit, 398 entry_addr + word, &(data[word]))); 399 } 400 401 if (NULL != meminfo->snoop_cb && 402 (SOC_MEM_SNOOP_READ & meminfo->snoop_flags)) { 403 meminfo->snoop_cb(unit, mem, SOC_MEM_SNOOP_READ, copyno, index, index, 404 entry_data, meminfo->snoop_user_data); 405 } 406 return SOC_E_NONE; 407 } 408 409 /* 410 * Function: 411 * soc_hercules_mem_read_word 412 * Purpose: 413 * Read a memory word internal to the SOC. 414 * Notes: 415 * This should only be used for hercules. 416 */ 417 418 int 419 soc_hercules_mem_read_word(int unit, uint32 addr, void *word_data) 420 { 421 schan_msg_t schan_msg; 422 int src_blk; 423 int opcode; 424 425 /* Setup S-Channel command packet */ 426 schan_msg_clear(&schan_msg); 427 src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit)); 428 soc_schan_header_cmd_set(unit, &schan_msg.header, READ_MEMORY_CMD_MSG, 429 0, src_blk, 0, 4, 0, 0); 430 431 schan_msg.readcmd.address = addr; 432 433 /* 434 * Write onto S-Channel "memory read" command packet consisting of header 435 * word + address word, and read back header word + entry_dw data words. 436 */ 437 SOC_IF_ERROR_RETURN(soc_schan_op(unit, &schan_msg, 2, 2, 0)); 438 439 /* Check result */ 440 soc_schan_header_status_get(unit, &schan_msg.header, &opcode, NULL, NULL, 441 NULL, NULL, NULL); 442 if (opcode != READ_MEMORY_ACK_MSG) { 443 LOG_ERROR(BSL_LS_SOC_COMMON, 444 (BSL_META_U(unit, 445 "soc_hercules_mem_read_word: " 446 "invalid S-Channel reply, expected READ_MEMORY_ACK:\n"))); 447 soc_schan_dump(unit, &schan_msg, 2); 448 return SOC_E_INTERNAL; 449 } 450 451 sal_memcpy(word_data, 452 schan_msg.readresp.data, 453 sizeof (uint32)); 454 455 if (bsl_check(bslLayerSoc, bslSourceMem, bslSeverityNormal, unit)) { 456 LOG_CLI((BSL_META_U(unit, 457 "soc_hercules_mem_read_word: u=%d: " 458 "addr=0x%08x: value=0x%08x\n"), 459 unit, addr, *(uint32 *)word_data)); 460 } 461 return SOC_E_NONE; 462 } 463 464 /* 465 * Function: 466 * soc_hercules_mem_write 467 * Purpose: 468 * Write a Hercules word addressed memory internal to the SOC. 469 * Notes: 470 * This should only be used for hercules. 471 */ 472 473 int 474 soc_hercules_mem_write(int unit, 475 soc_mem_t mem, 476 int copyno, 477 int index, 478 void *entry_data) 479 { 480 uint32 entry_addr; 481 int entry_words, word; 482 uint32 *data = (uint32 *)entry_data; 483 soc_mem_info_t *meminfo = &SOC_MEM_INFO(unit, mem); 484 int blk; 485 486 entry_words = soc_mem_entry_words(unit, mem); 487 488 if (copyno != COPYNO_ALL) { 489 if (!SOC_MEM_BLOCK_VALID(unit, mem, copyno)) { 490 LOG_WARN(BSL_LS_SOC_COMMON, 491 (BSL_META_U(unit, 492 "soc_hercules_mem_write: " 493 "invalid copy %d for table %s\n"), 494 copyno, SOC_MEM_NAME(unit, mem))); 495 return SOC_E_PARAM; 496 } 497 } 498 499 /* Write to one or all copies of the memory */ 500 SOC_MEM_BLOCK_ITER(unit, mem, blk) { 501 if (copyno != COPYNO_ALL && copyno != blk) { 502 continue; 503 } 504 505 entry_addr = soc_mem_addr(unit, mem, 0, blk, 0); 506 entry_addr += index * meminfo->gran; 507 508 for (word = 0; word < entry_words; word++) { 509 SOC_IF_ERROR_RETURN(soc_hercules_mem_write_word(unit, 510 entry_addr + word, &(data[word]))); 511 } 512 } 513 514 if (NULL != meminfo->snoop_cb && 515 (SOC_MEM_SNOOP_WRITE & meminfo->snoop_flags)) { 516 meminfo->snoop_cb(unit, mem, SOC_MEM_SNOOP_WRITE, copyno, index, index, 517 entry_data, meminfo->snoop_user_data); 518 } 519 520 return SOC_E_NONE; 521 } 522 523 /* 524 * Function: 525 * soc_hercules_mem_write_word 526 * Purpose: 527 * Write a memory word internal to the SOC. 528 * Notes: 529 */ 530 531 int 532 soc_hercules_mem_write_word(int unit, uint32 addr, void *word_data) 533 { 534 schan_msg_t schan_msg; 535 int src_blk; 536 537 /* 538 * Setup S-Channel command packet 539 * 540 * NOTE: the datalen field matters only for the Write Memory and 541 * Write Register commands, where it is used only by the CMIC to 542 * determine how much data to send, and is in units of bytes. 543 */ 544 545 schan_msg_clear(&schan_msg); 546 src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit)); 547 soc_schan_header_cmd_set(unit, &schan_msg.header, WRITE_MEMORY_CMD_MSG, 548 0, src_blk, 0, 4, 0, 0); 549 schan_msg.writecmd.address = addr; 550 551 sal_memcpy(schan_msg.writecmd.data, 552 word_data, 553 sizeof (uint32)); 554 555 if (bsl_check(bslLayerSoc, bslSourceMem, bslSeverityNormal, unit)) { 556 LOG_CLI((BSL_META_U(unit, 557 "soc_hercules_mem_write_word: u=%d: " 558 "addr=0x%08x: value=0x%08x\n"), 559 unit, addr, *(uint32 *)word_data)); 560 } 561 562 /* Write header + address + entry_dw data DWORDs */ 563 /* Note: The hardware does not send WRITE_MEMORY_ACK_MSG. */ 564 SOC_IF_ERROR_RETURN(soc_schan_op(unit, &schan_msg, 565 3, 0, 0)); 566 567 return SOC_E_NONE; 568 } 569 570 571 /* 572 * Setup all ingress ports for a UNICAST entry to flood to the given port 573 * bitmap 574 */ 575 int 576 soc_hercules_uc_port_set_all(int unit, int modid, pbmp_t pbmp) 577 { 578 int port; 579 580 PBMP_PORT_ITER(unit, port) { 581 SOC_IF_ERROR_RETURN(soc_hercules_uc_port_set(unit, port, modid, pbmp)); 582 } 583 return SOC_E_NONE; 584 } 585 586 /* 587 * Update all DLF/Broadcast (VID) table entries specifying the flood group 588 * bitmaps for the given VLAN ID (VID). 589 */ 590 int 591 soc_hercules_vlan_port_set_all(int unit, vlan_id_t vid, pbmp_t pbmp) 592 { 593 int port; 594 595 PBMP_PORT_ITER(unit, port) { 596 SOC_IF_ERROR_RETURN(soc_hercules_vlan_port_set(unit, port, vid, pbmp)); 597 } 598 return SOC_E_NONE; 599 } 600 601 /* 602 * Configure a Hercules port's packet and cell limits. 603 */ 604 605 int 606 soc_hercules15_mmu_limits_config(int unit, int port, int num_ports, 607 int num_cos, int lossless) 608 { 609 int cos, xq_entries, hysteresis; 610 soc_port_t other_port; 611 uint32 lla_cells; 612 uint32 lla_cells_good = SOC_CONTROL(unit)->lla_cells_good[port]; 613 614 assert(num_cos > 0 && num_cos <= NUM_COS(unit)); 615 616 /* 617 * Allowing for future decrease in the max XQ used. 618 * NB: Use one less than the total number of entries, as 619 * pktlmting is one bit too small to handle the full size of XQ. 620 */ 621 xq_entries = soc_mem_index_max(unit, MEM_XQm) - 622 soc_mem_index_min(unit, MEM_XQm); 623 624 LOG_VERBOSE(BSL_LS_SOC_COMMON, 625 (BSL_META_U(unit, 626 "soc_hercules15_mmu_limits_config: " 627 "unit=%d port=%s nports=%d ncos=%d loss%s\n"), 628 unit, SOC_PORT_NAME(unit, port), 629 num_ports, num_cos, lossless ? "y" : "less")); 630 631 /* Set up COS specific registers per port */ 632 633 hysteresis = soc_property_get(unit, spn_MMU_HOL_HYSTERESIS, 0); 634 635 for (cos = 0; cos < NUM_COS(unit); cos++) { 636 if (cos < num_cos) { 637 /* Packet Limit / COS */ 638 SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTCOS_UPPERr(unit, port, cos, 639 xq_entries / num_cos)); 640 SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTCOS_LOWERr(unit, port, cos, 641 hysteresis ? ((xq_entries / num_cos)- (xq_entries / num_cos / 50)) 642 : (xq_entries / num_cos))); 643 /* Cell Limit / COS */ 644 lla_cells = (hysteresis) ? 645 ((lla_cells_good / num_cos) - (lla_cells_good / num_cos / 50)) 646 : (lla_cells_good / num_cos); 647 SOC_IF_ERROR_RETURN(WRITE_MMU_CELLLMTCOS_UPPERr(unit, port, cos, 648 lossless ? lla_cells_good : (lla_cells_good / num_cos))); 649 SOC_IF_ERROR_RETURN(WRITE_MMU_CELLLMTCOS_LOWERr(unit, port, cos, 650 lossless ? lla_cells_good : lla_cells)); 651 } else { 652 /* Packet Limit / COS */ 653 SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTCOS_UPPERr(unit, port, cos, 0)); 654 SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTCOS_LOWERr(unit, port, cos, 0)); 655 /* Cell Limit / COS */ 656 SOC_IF_ERROR_RETURN(WRITE_MMU_CELLLMTCOS_UPPERr(unit, port, cos, 0)); 657 SOC_IF_ERROR_RETURN(WRITE_MMU_CELLLMTCOS_LOWERr(unit, port, cos, 0)); 658 } 659 } 660 661 if (lossless) { /* Lossless mode */ 662 assert(num_ports > 0); 663 664 PBMP_ALL_ITER(unit, other_port) { 665 /* Diagonals don't exist for these registers. */ 666 if (other_port != port) { 667 /* Per Ingress Packet Limit / Port / COS (less 2 packets margin) */ 668 SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTINGr(unit, port, 669 other_port, 670 xq_entries / num_ports / num_cos - 2)); 671 672 /* Per Ingress Cell Limit / Port (less 3 cells margin) */ 673 SOC_IF_ERROR_RETURN( 674 WRITE_MMU_CELLLMTINGr(unit, port, other_port, 675 lla_cells_good / num_ports - 3)); 676 /* Note: We've pulled a fast one here. NUM_PORT does not 677 * include the CMIC, so it is one short of all of the ports 678 * that we are studying here. However, since we want to skip 679 * the port itself, it works out. For now. -jwd 680 */ 681 } 682 } 683 } else { /* Throughput or "Lossy" mode */ 684 PBMP_ALL_ITER(unit, other_port) { 685 /* Diagonals don't exist for these registers. */ 686 if (other_port != port) { 687 /* All XQ entries */ 688 SOC_IF_ERROR_RETURN(WRITE_MMU_PKTLMTINGr(unit, port, 689 other_port, xq_entries)); 690 691 /* All good LLA/PP */ 692 SOC_IF_ERROR_RETURN( 693 WRITE_MMU_CELLLMTINGr(unit, port, other_port, 694 lla_cells_good)); 695 } 696 } 697 } 698 699 if (IS_HG_PORT(unit, port)) { /* CMIC has no ING_CTRLr */ 700 uint32 reg, oreg; 701 SOC_IF_ERROR_RETURN(READ_ING_CTRLr(unit, port, ®)); 702 oreg = reg; 703 /* Mark this lossless */ 704 soc_reg_field_set(unit, ING_CTRLr, ®, LOSSLESSENf, 705 (lossless ? 1 : 0)); 706 if (reg != oreg) { 707 SOC_IF_ERROR_RETURN(WRITE_ING_CTRLr(unit, port, reg)); 708 } 709 } 710 711 return SOC_E_NONE; 712 } 713 714 /* 715 * Set a Unicast(UC) table entry specifying the forwarding egress port 716 * bitmap for the ingress port and module ID. 717 * 718 * Note: Port zero is not the first port, but rather the CMIC port. 719 */ 720 STATIC int 721 soc_hercules_uc_port_set(int unit, soc_port_t ingress_port, int modid, 722 pbmp_t pbmp) 723 { 724 mem_uc_entry_t uc; 725 char pfmt[SOC_PBMP_FMT_LEN]; 726 727 MODID_RANGE_CHECK(unit); 728 LOG_VERBOSE(BSL_LS_SOC_COMMON, 729 (BSL_META_U(unit, 730 "soc_hercules_uc_port_set: unit=%d port=%s modid=%d pbmp=%s\n"), 731 unit, SOC_PORT_NAME(unit, ingress_port), modid, 732 SOC_PBMP_FMT(pbmp, pfmt))); 733 sal_memset(&uc, 0, sizeof(uc)); 734 soc_MEM_UCm_field32_set(unit, &uc, UCBITMAPf, SOC_PBMP_WORD_GET(pbmp, 0)); 735 return WRITE_MEM_UCm(unit, SOC_PORT_BLOCK(unit, ingress_port), 736 modid, &uc); 737 } 738 739 /* 740 * Flush out the VLAN table at inital startup 741 */ 742 STATIC int 743 soc_hercules_vlan_port_init(int unit, soc_port_t ingress_port) 744 { 745 mem_vid_entry_t vdata; 746 int vid, vid_min, vid_max, blk; 747 748 vid_min = soc_mem_index_min(unit, MEM_VIDm); 749 vid_max = soc_mem_index_max(unit, MEM_VIDm); 750 blk = SOC_PORT_BLOCK(unit, ingress_port); 751 752 LOG_VERBOSE(BSL_LS_SOC_COMMON, 753 (BSL_META_U(unit, 754 "soc_hercules_vlan_port_init: unit=%d port=%s\n"), 755 unit, SOC_PORT_NAME(unit, ingress_port))); 756 sal_memset(&vdata, 0, sizeof(mem_vid_entry_t)); 757 758 for (vid = vid_min; vid <= vid_max; vid++) { 759 SOC_IF_ERROR_RETURN(WRITE_MEM_VIDm(unit, blk, vid, &vdata)); 760 } 761 return SOC_E_NONE; 762 } 763 764 /* 765 * Same operation as above, applied to all ports. 766 */ 767 STATIC int 768 soc_hercules_vlan_port_init_all(int unit) 769 { 770 int port; 771 772 PBMP_PORT_ITER(unit, port) { 773 SOC_IF_ERROR_RETURN(soc_hercules_vlan_port_init(unit, port)); 774 } 775 return SOC_E_NONE; 776 } 777 778 /* 779 * Update a DLF/Broadcast (VID) table entry specifying the flood group 780 * bitmap for the given VLAN ID (VID). 781 */ 782 STATIC int 783 soc_hercules_vlan_port_set(int unit, 784 soc_port_t ingress_port, vlan_id_t vid, pbmp_t pbmp) 785 { 786 int blk; 787 mem_vid_entry_t vdata; 788 char pfmt[SOC_PBMP_FMT_LEN]; 789 790 VLAN_RANGE_CHECK(unit); 791 blk = SOC_PORT_BLOCK(unit, ingress_port); 792 LOG_VERBOSE(BSL_LS_SOC_COMMON, 793 (BSL_META_U(unit, 794 "soc_hercules_vlan_port_set: unit=%d port=%s vid=%d pbmp=%s\n"), 795 unit, SOC_PORT_NAME(unit, ingress_port), 796 vid, SOC_PBMP_FMT(pbmp, pfmt))); 797 sal_memset(&vdata, 0, sizeof(vdata)); 798 soc_MEM_VIDm_field32_set(unit, &vdata, VIDBITMAPf, 799 SOC_PBMP_WORD_GET(pbmp, 0)); 800 return WRITE_MEM_VIDm(unit, blk, vid, &vdata); 801 } 802 803 /* 804 * Init a Multicast/IP Multicast (MC) table entry specifying the flood group 805 * bitmap for the given Multicast index and port number. 806 * 807 * The MCBITMAP and IPMCBITMAP are both updated with the specified 808 * bitmap at the given index into the MC table. 809 */ 810 STATIC int 811 soc_hercules_mc_port_init(int unit, soc_port_t ingress_port) 812 { 813 mem_mc_entry_t mcdata; 814 int mcidx, mcidx_min, mcidx_max, blk; 815 816 mcidx_min = soc_mem_index_min(unit, MEM_MCm); 817 mcidx_max = soc_mem_index_max(unit, MEM_MCm); 818 blk = SOC_PORT_BLOCK(unit, ingress_port); 819 LOG_VERBOSE(BSL_LS_SOC_COMMON, 820 (BSL_META_U(unit, 821 "soc_hercules_mc_port_init: unit=%d port=%s\n"), 822 unit, SOC_PORT_NAME(unit, ingress_port))); 823 sal_memset(&mcdata, 0, sizeof(mem_mc_entry_t)); 824 for (mcidx = mcidx_min; mcidx <= mcidx_max; mcidx++) { 825 SOC_IF_ERROR_RETURN(WRITE_MEM_MCm(unit, blk, mcidx, &mcdata)); 826 } 827 return SOC_E_NONE; 828 } 829 830 STATIC int 831 soc_hercules_mc_port_init_all(int unit) 832 { 833 int port; 834 835 PBMP_HG_ITER(unit, port) { 836 SOC_IF_ERROR_RETURN(soc_hercules_mc_port_init(unit, port)); 837 } 838 return SOC_E_NONE; 839 } 840 841 /* 842 * Update a L2 Multicast (MC) table entry specifying the flood group 843 * bitmap for the given Multicast index and port number. 844 */ 845 STATIC int 846 soc_hercules_mc_port_set(int unit, soc_port_t ingress_port, int mcidx, 847 pbmp_t pbmp) 848 { 849 mem_mc_entry_t mcdata; 850 char pfmt[SOC_PBMP_FMT_LEN]; 851 int blk; 852 853 MCIDX_RANGE_CHECK(unit); 854 855 LOG_VERBOSE(BSL_LS_SOC_COMMON, 856 (BSL_META_U(unit, 857 "soc_hercules_mc_port_set: unit=%d port=%s mcidx=%d pbmp=%s\n"), 858 unit, SOC_PORT_NAME(unit, ingress_port), 859 mcidx, SOC_PBMP_FMT(pbmp, pfmt))); 860 861 blk = SOC_PORT_BLOCK(unit, ingress_port); 862 sal_memset(&mcdata, 0, sizeof(mcdata)); 863 SOC_IF_ERROR_RETURN(READ_MEM_MCm(unit, blk, mcidx, &mcdata)); 864 soc_MEM_MCm_field32_set(unit, &mcdata, 865 MCBITMAPf, SOC_PBMP_WORD_GET(pbmp, 0)); 866 SOC_IF_ERROR_RETURN(WRITE_MEM_MCm(unit, blk, mcidx, &mcdata)); 867 868 return SOC_E_NONE; 869 } 870 871 STATIC int 872 soc_hercules_mc_port_set_all(int unit, int mcidx, pbmp_t pbmp) 873 { 874 int port; 875 876 PBMP_HG_ITER(unit, port) { 877 SOC_IF_ERROR_RETURN(soc_hercules_mc_port_set(unit, port, mcidx, pbmp)); 878 } 879 return SOC_E_NONE; 880 } 881 882 /* 883 * Initialize an MMU (port0=CMIC, 1-8 = PIE) 884 * THIS IS FOR HERCULES ONLY 885 */ 886 STATIC int 887 soc_hercules_port_mmu_init(int unit, int port) 888 { 889 uint32 lla_cells_good = SOC_CONTROL(unit)->lla_cells_good[port]; 890 891 /* Enable MMU interrupts */ 892 SOC_IF_ERROR_RETURN(WRITE_MMU_INTCLRr(unit, port, SOC_MMU_ERR_CLEAR_ALL)); 893 894 SOC_IF_ERROR_RETURN 895 (WRITE_MMU_INTCLRr(unit, port, SOC_ERR_HAND_MMU_ALL_H15)); 896 if (SOC_CONTROL(unit)->sbe_disable[port]) { 897 SOC_IF_ERROR_RETURN(WRITE_MMU_INTCTRLr(unit, port, 898 (port == 0) ? 0 : 899 SOC_ERR_HAND_MMU_ALL_H15 ^ 900 SOC_ERR_HAND_MMU_PP_SBE)); 901 } else { 902 SOC_IF_ERROR_RETURN(WRITE_MMU_INTCTRLr(unit, port, 903 (port == 0) ? 0 : 904 SOC_ERR_HAND_MMU_ALL_H15)); 905 } 906 907 /* Total Cell Limit/Port */ 908 SOC_IF_ERROR_RETURN( 909 WRITE_MMU_CELLLMTTOTAL_UPPERr(unit, port, lla_cells_good)); 910 SOC_IF_ERROR_RETURN( 911 WRITE_MMU_CELLLMTTOTAL_LOWERr(unit, port, lla_cells_good)); 912 913 return SOC_E_NONE; 914 } 915 916 /* 917 * Initialize a Port Ingress/Egress (PIE) Module 918 */ 919 STATIC int 920 soc_hercules_pie_init(int unit, int port, pbmp_t pbmp, int testmode) 921 { 922 uint32 reg; 923 924 /* DEBUG/TEST/BRINGUP stuff */ 925 926 if (testmode) { 927 /* 928 * Set Ingress test mode. In this mode, the first entry 929 * in the UC table is always used as the final egress 930 * bitmap for the packet - no matter what. 931 */ 932 933 reg = 0; 934 soc_reg_field_set(unit, ING_CTRLr, ®, TSTMODEENf, 1); 935 SOC_IF_ERROR_RETURN(WRITE_ING_CTRLr(unit, port, reg)); 936 LOG_CLI((BSL_META_U(unit, 937 "NOTICE: port %s: INGRESS test mode enabled.\n"), 938 SOC_PORT_NAME(unit, port))); 939 } 940 941 /* 942 * Set EGRMSKBMAPr 943 * Initially, allow egressing to any of the ports. 944 */ 945 SOC_IF_ERROR_RETURN 946 (WRITE_ING_EGRMSKBMAPr(unit, port, SOC_PBMP_WORD_GET(pbmp, 0))); 947 948 /* 949 * Set ING_CPUTOBMAP 950 * This register defines the ports which CPU packets need to 951 * be forwarded to (always CPU port bitmap). 952 */ 953 SOC_IF_ERROR_RETURN 954 (WRITE_ING_CPUTOBMAPr(unit, port, 955 SOC_PBMP_WORD_GET(PBMP_CMIC(unit), 0))); 956 957 /* 958 * Set ING_EPC_LNKBMAPr register to cmic-only forwarding. 959 * Linkscan will add the rest. 960 */ 961 962 SOC_IF_ERROR_RETURN 963 (WRITE_ING_EPC_LNKBMAPr(unit, port, 964 SOC_PBMP_WORD_GET(PBMP_CMIC(unit), 0))); 965 966 return SOC_E_NONE; 967 } 968 969 #endif /* BCM_HERCULES_SUPPORT */