failover.c (12641B)
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: failover.c 8 * Purpose: Handle TH3 specific failover APIs 9 * with fixed next hop offset. 10 */ 11 12 13 #include <shared/bsl.h> 14 15 #include <soc/defs.h> 16 #include <sal/core/libc.h> 17 18 #if defined(INCLUDE_L3) 19 #if defined(BCM_TOMAHAWK3_SUPPORT) 20 21 #include <soc/drv.h> 22 #include <soc/mem.h> 23 #include <soc/util.h> 24 #include <soc/debug.h> 25 26 #include <bcm/types.h> 27 #include <bcm/error.h> 28 #include <bcm/module.h> 29 #include <bcm/failover.h> 30 31 #include <bcm_int/esw/tomahawk3.h> 32 #include <bcm_int/esw/failover.h> 33 34 #define REPLACE_ENABLE_BITMAP_SIZE 128 35 36 #define FAILOVER_LOCK(u) sal_mutex_take(FAILOVER_INFO(u)->failover_mutex, sal_sem_FOREVER) 37 #define FAILOVER_UNLOCK(u) sal_mutex_give(FAILOVER_INFO(u)->failover_mutex) 38 39 /* 40 * Function: 41 * bcm_th3_failover_hw_clear 42 * Purpose: 43 * Cleart Failover Hw memory 44 * Parameters: 45 * unit - Device Number 46 * Returns: 47 * BCM_E_XXX 48 */ 49 static int 50 bcm_th3_failover_hw_clear(int unit) 51 { 52 uint8 *mbuf; 53 int size, rv = BCM_E_NONE; 54 soc_mem_t mem; 55 56 mem = PROT_NHI_TABLE_1m; 57 size = SOC_MEM_TABLE_BYTES(unit, mem); 58 mbuf = soc_cm_salloc(unit, size, "failover_mem"); 59 if (mbuf != NULL) { 60 sal_memset(mbuf, 0, size); 61 FAILOVER_LOCK(unit); 62 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY, 63 soc_mem_index_min(unit, mem), 64 soc_mem_index_max(unit, mem), mbuf); 65 FAILOVER_UNLOCK(unit); 66 soc_cm_sfree(unit, mbuf); 67 68 } else { 69 rv = BCM_E_MEMORY; 70 LOG_ERROR(BSL_LS_SOC_L3, 71 (BSL_META_U(unit, "FAILOVER HW mem %s clear failed.\n"), 72 SOC_MEM_NAME(unit, mem))); 73 } 74 75 return rv; 76 } 77 78 /* 79 * Function: 80 * bcm_th3_failover_cleanup 81 * Purpose: 82 * DeInit the Failover software module 83 * Parameters: 84 * unit - Device Number 85 * Returns: 86 * BCM_E_XXX 87 */ 88 int 89 bcm_th3_failover_cleanup(int unit) 90 { 91 _bcm_failover_bookkeeping_t *failover_info = FAILOVER_INFO(unit); 92 int rv = BCM_E_UNAVAIL; 93 94 if (!failover_info->initialized) { 95 return (BCM_E_NONE); 96 } 97 98 if (!SOC_HW_ACCESS_DISABLE(unit)) { 99 rv = bcm_th3_failover_hw_clear(unit); 100 } 101 102 /* Destroy protection mutex. */ 103 sal_mutex_destroy(failover_info->failover_mutex); 104 105 /* Mark the state as uninitialized */ 106 failover_info->initialized = FALSE; 107 failover_info->prot_offset = 0; 108 109 return rv; 110 } 111 112 /* 113 * Function: 114 * bcm_th3_failover_init 115 * Purpose: 116 * Initialize the Failover software module 117 * Parameters: 118 * unit - (IN) Device Number 119 * Returns: 120 * BCM_E_XXX 121 */ 122 int 123 bcm_th3_failover_init(int unit) 124 { 125 int rv = BCM_E_NONE; 126 uint32 rval = 0; 127 int prot_offset; 128 _bcm_failover_bookkeeping_t *failover_info = FAILOVER_INFO(unit); 129 130 if (failover_info->initialized) { 131 BCM_IF_ERROR_RETURN(bcm_th3_failover_cleanup(unit)); 132 } 133 134 /* Create Failover protection mutex. */ 135 failover_info->failover_mutex = sal_mutex_create("failover_mutex"); 136 if (!failover_info->failover_mutex) { 137 return BCM_E_MEMORY; 138 } 139 140 if (soc_property_get(unit, spn_FAILOVER_FIXED_NH_OFFSET_ENABLE, 0)) { 141 142 /* Fixed protection NHI offset = half of egr_l3_next_hop size (16384) */ 143 prot_offset = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm) >> 1; 144 if (prot_offset == 0) { 145 return BCM_E_MEMORY; 146 } 147 148 /* Configure PROT_OFFSETf on PROT_NHI_CONFIGr */ 149 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, PROT_NHI_CONFIGr, 150 REG_PORT_ANY, 0, &rval)); 151 soc_reg_field_set(unit, PROT_NHI_CONFIGr, &rval, 152 PROT_OFFSETf, prot_offset); 153 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, PROT_NHI_CONFIGr, 154 REG_PORT_ANY, 0, rval)); 155 156 /* Clear failover Hw mem: PROT_NHI_TABLE_1m */ 157 if (!SOC_WARM_BOOT(unit)) { 158 rv = bcm_th3_failover_hw_clear(unit); 159 } 160 BCM_IF_ERROR_RETURN(rv); 161 162 failover_info->prot_offset = prot_offset; 163 cli_out("Failover enabled with fixed next hop offset %d\n", 164 prot_offset); 165 } else { 166 failover_info->prot_offset = 0; 167 } 168 169 failover_info->initialized = TRUE; 170 171 return rv; 172 } 173 174 /* 175 * Function: 176 * bcm_th3_failover_egress_set 177 * Purpose: 178 * This function can be used to set the protected NH for 179 * the specified primary nexthop (intf) 180 * Parameters: 181 * unit - (IN) Device Number 182 * intf - (IN) Primary NH interface 183 * failover_egr - (IN/OUT) Egress object to be used as the 184 * protection nexthop for primary NH. 185 * Returns: 186 * BCM_E_XXX 187 */ 188 int 189 bcm_th3_failover_egress_set(int unit, bcm_if_t intf, 190 bcm_l3_egress_t *failover_egr) 191 { 192 int rv = BCM_E_NONE; 193 uint32 flags; 194 bcm_if_t prot_intf; 195 196 if (!FAILOVER_INFO(unit)->initialized) { 197 return BCM_E_INIT; 198 } 199 200 if (FAILOVER_INFO(unit)->prot_offset == 0) { 201 return BCM_E_CONFIG; 202 } 203 204 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) && 205 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 206 return BCM_E_PARAM; 207 } 208 209 /* Set prot_intf with fixed offset from primary intf */ 210 prot_intf = intf + FAILOVER_INFO(unit)->prot_offset; 211 212 /* Create protected egress nh BCM_L3_WITH_ID flags */ 213 flags = (BCM_L3_WITH_ID | BCM_L3_REPLACE); 214 215 /* For TH3 failover_id shouldn't be used by user. It's used internally 216 only to distinguish between primary_intf and prot_intf egress creation. 217 This flag bit will be clear in bcm_xgs3_l3_egress_create. */ 218 failover_egr->failover_id |= _FAILOVER_FIXED_NH_OFFSET_ON; 219 rv = bcm_esw_l3_egress_create(unit, flags, failover_egr, &prot_intf); 220 221 return rv; 222 } 223 224 /* 225 * Function: 226 * bcm_th3_failover_egress_get 227 * Purpose: 228 * This function can be used to retrieve the protected NH for 229 * the specified primary nexthop (intf) 230 * Parameters: 231 * unit - (IN) Device Number 232 * intf - (IN) Primary NH interface 233 * failover_egr - (OUT) Egress object used as the 234 * protection nexthop for primary NH. 235 * Returns: 236 * BCM_E_XXX 237 */ 238 int 239 bcm_th3_failover_egress_get(int unit, bcm_if_t intf, 240 bcm_l3_egress_t *failover_egr) 241 { 242 int rv = BCM_E_NONE; 243 bcm_if_t prot_intf; 244 245 if (!FAILOVER_INFO(unit)->initialized) { 246 return BCM_E_INIT; 247 } 248 249 if (FAILOVER_INFO(unit)->prot_offset == 0) { 250 return BCM_E_CONFIG; 251 } 252 253 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) && 254 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 255 return BCM_E_PARAM; 256 } 257 258 /* Set prot_intf with fixed offset from primary intf */ 259 prot_intf = intf + FAILOVER_INFO(unit)->prot_offset; 260 261 bcm_l3_egress_t_init(failover_egr); 262 263 rv = bcm_esw_l3_egress_get(unit, prot_intf, failover_egr); 264 265 return rv; 266 } 267 268 /* 269 * Function: 270 * bcm_th3_failover_egress_clear 271 * Purpose: 272 * This function can be used to clear the protected NH set earlier 273 * for the specified primary nexthop (intf) 274 * Parameters: 275 * unit - (IN) Device Number 276 * intf - (IN) Primary NH interface 277 * Returns: 278 * BCM_E_XXX 279 */ 280 int 281 bcm_th3_failover_egress_clear(int unit, bcm_if_t intf) 282 { 283 int rv = BCM_E_NONE; 284 bcm_if_t prot_intf; 285 286 if (!FAILOVER_INFO(unit)->initialized) { 287 return BCM_E_INIT; 288 } 289 290 if (FAILOVER_INFO(unit)->prot_offset == 0) { 291 return BCM_E_CONFIG; 292 } 293 294 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) && 295 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 296 return BCM_E_PARAM; 297 } 298 299 /* Set prot_intf with fixed offset from primary intf */ 300 prot_intf = intf + FAILOVER_INFO(unit)->prot_offset; 301 302 /* First disable egress status for prot_intf (i.e., use primary intf) */ 303 rv = bcm_th3_failover_egress_status_set(unit, intf, FALSE); 304 305 if (BCM_SUCCESS(rv)) { 306 rv = bcm_esw_l3_egress_destroy(unit, prot_intf); 307 } 308 309 return rv; 310 } 311 312 /* 313 * Function: 314 * bcm_th3_failover_egress_status_set 315 * Purpose: 316 * This function controls (set/clear) the active state of use of 317 * primary NH or protected NH 318 * Parameters: 319 * unit - (IN) Device Number 320 * intf - (IN) Primary NH interface 321 * enable - (IN) Enable=True for use of protected NH, 322 * Enable=False for use of Primary NH (intf). 323 * Returns: 324 * BCM_E_XXX 325 */ 326 int 327 bcm_th3_failover_egress_status_set(int unit, bcm_if_t intf, int enable) 328 { 329 int rv = BCM_E_NONE; 330 int nh_idx, index, bit_pos; 331 uint32 entry[5], data[5]; 332 soc_mem_t mem = PROT_NHI_TABLE_1m; 333 334 /* Make sure module was initialized. */ 335 if (!BCM_XGS3_L3_INITIALIZED(unit) || 336 !FAILOVER_INFO(unit)->initialized) { 337 return (BCM_E_INIT); 338 } 339 340 if (FAILOVER_INFO(unit)->prot_offset == 0) { 341 return (BCM_E_CONFIG); 342 } 343 344 /* Check l3 switching mode. */ 345 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 346 return (BCM_E_DISABLED); 347 } 348 349 /* Input parameters check. */ 350 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) && 351 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 352 return (BCM_E_PARAM); 353 } 354 355 /* Calculate next hop index. */ 356 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 357 nh_idx = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 358 } else { 359 nh_idx = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 360 } 361 362 /* Validate primary nh_idx */ 363 if (nh_idx >= FAILOVER_INFO(unit)->prot_offset) { 364 return BCM_E_PARAM; 365 } 366 367 /* Calculate PROT_NHI_TABLE_1: index, and REPLACE_ENABLE_BITMAP: bit position */ 368 index = nh_idx / REPLACE_ENABLE_BITMAP_SIZE; 369 bit_pos = nh_idx % REPLACE_ENABLE_BITMAP_SIZE; 370 371 FAILOVER_LOCK(unit); 372 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, entry); 373 if (BCM_SUCCESS(rv)) { 374 soc_mem_field_get(unit, mem, entry, REPLACE_ENABLE_BITMAPf, data); 375 SHR_BITWRITE(data, bit_pos, enable); 376 soc_mem_field_set(unit, mem, entry, REPLACE_ENABLE_BITMAPf, data); 377 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, entry); 378 } 379 FAILOVER_UNLOCK(unit); 380 381 return rv; 382 } 383 384 /* 385 * Function: 386 * bcm_th3_failover_egress_status_get 387 * Purpose: 388 * This function retrieves the current status of use of 389 * primary NH or protected NH 390 * Parameters: 391 * unit - (IN) Device Number 392 * intf - (IN) Primary NH interface 393 * enable - (OUT) Enable=True for use of protected NH, 394 * Enable=False for use of Primary NH (intf). 395 * Returns: 396 * BCM_E_XXX 397 */ 398 int 399 bcm_th3_failover_egress_status_get(int unit, bcm_if_t intf, int *enable) 400 { 401 int rv = BCM_E_NONE; 402 int nh_idx, index, bit_pos; 403 uint32 entry[5], data[5]; 404 soc_mem_t mem = PROT_NHI_TABLE_1m; 405 406 /* Make sure module was initialized. */ 407 if (!BCM_XGS3_L3_INITIALIZED(unit) || 408 !FAILOVER_INFO(unit)->initialized) { 409 return (BCM_E_INIT); 410 } 411 412 if (FAILOVER_INFO(unit)->prot_offset == 0) { 413 return (BCM_E_CONFIG); 414 } 415 416 /* Check l3 switching mode. */ 417 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 418 return (BCM_E_DISABLED); 419 } 420 421 /* Input parameters check. */ 422 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) && 423 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 424 return (BCM_E_PARAM); 425 } 426 427 /* Calculate next hop index. */ 428 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 429 nh_idx = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 430 } else { 431 nh_idx = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 432 } 433 434 /* Validate primary nh_idx */ 435 if ((nh_idx >= FAILOVER_INFO(unit)->prot_offset) || (enable == NULL)) { 436 return BCM_E_PARAM; 437 } 438 439 /* Calculate PROT_NHI_TABLE_1: index, and REPLACE_ENABLE_BITMAP: bit position */ 440 index = nh_idx / REPLACE_ENABLE_BITMAP_SIZE; 441 bit_pos = nh_idx % REPLACE_ENABLE_BITMAP_SIZE; 442 443 FAILOVER_LOCK(unit); 444 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, entry); 445 if (BCM_SUCCESS(rv)) { 446 soc_mem_field_get(unit, mem, entry, REPLACE_ENABLE_BITMAPf, data); 447 *enable = (SHR_BITGET(data, bit_pos) ? 1 : 0); 448 } 449 FAILOVER_UNLOCK(unit); 450 451 return rv; 452 } 453 454 #endif /* defined(BCM_TOMAHAWK3_SUPPORT) */ 455 #endif /* defined(INCLUDE_L3) */