l2xmsg.c (11890B)
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: l2xmsg.c 8 * Purpose: Provide a reliable stream of L2 insert/delete messages. 9 * 10 * This module monitors the L2X table for changes and performs callbacks 11 * for each insert, delete, or port movement that is detected. 12 * 13 * There is a time lag from the actual table change to the callback 14 * because the l2xmsg task scans the L2X table only periodically. 15 */ 16 17 #include <sal/core/libc.h> 18 #include <shared/alloc.h> 19 #include <sal/core/spl.h> 20 #include <sal/core/time.h> 21 #include <shared/bsl.h> 22 #include <soc/mem.h> 23 #include <soc/debug.h> 24 #include <soc/cm.h> 25 #include <soc/drv.h> 26 #include <soc/l2x.h> 27 28 #ifdef BCM_HURRICANE3_SUPPORT 29 30 #define L2_OVERFLOW_ENTRY_EQL(unit, e1, e2, sz, bits) \ 31 (!_soc_mem_cmp_l2x_sync(unit, (void *) e1, (void *) e2, sz, bits)) 32 33 #define L2_OVERFLOW_IS_VALID_ENTRY(_u, _mem, _e, bitf) \ 34 soc_mem_field32_get((_u), (_mem), (_e), bitf) 35 36 37 /* L2 overflow structure */ 38 typedef struct l2x_overflow_data_s { 39 soc_mem_t mem; 40 int entry_words; 41 int entry_bytes; 42 int count; 43 uint32 *shadow_tab; 44 uint32 *buf; 45 } l2x_overflow_data_t; 46 47 STATIC l2x_overflow_data_t *l2x_ovf_data[SOC_MAX_NUM_DEVICES]; 48 49 /* 50 * Function: 51 * soc_hr3_l2_overflow_entry_get 52 * Purpose: 53 * Get the values of L2 non-learned entry. 54 * Parameters: 55 * unit - unit number. 56 * Returns: 57 * SOC_E_XXX. 58 */ 59 60 int 61 soc_hr3_l2_overflow_entry_get(int unit, l2x_entry_t *entry) 62 { 63 sal_mac_addr_t mac; 64 uint64 mac_field; 65 uint32 vlan_port, vlan, port; 66 67 SOC_IF_ERROR_RETURN 68 (READ_L2_NON_LEARNED_MESSAGE_MACSAr(unit, &mac_field)); 69 SOC_IF_ERROR_RETURN 70 (READ_L2_NON_LEARNED_MESSAGE_VLAN_PORTr(unit, &vlan_port)); 71 72 SAL_MAC_ADDR_FROM_UINT64(mac, mac_field); 73 soc_L2Xm_mac_addr_set(unit, entry, MAC_ADDRf, mac); 74 vlan = soc_reg_field_get(unit, L2_NON_LEARNED_MESSAGE_VLAN_PORTr, 75 vlan_port, VLANf); 76 soc_L2Xm_field_set(unit, entry, VLAN_IDf, &vlan); 77 port = soc_reg_field_get(unit, L2_NON_LEARNED_MESSAGE_VLAN_PORTr, 78 vlan_port, PORTf); 79 soc_L2Xm_field_set(unit, entry, PORT_NUMf, &port); 80 81 return SOC_E_NONE; 82 } 83 84 /* 85 * Function: 86 * soc_hr3_l2_overflow_intr_disable 87 * Purpose: 88 * Disable the interrupt of L2 non-learned event. 89 * Parameters: 90 * unit - unit number. 91 * Returns: 92 * SOC_E_XXX. 93 */ 94 95 int 96 soc_hr3_l2_overflow_intr_disable(int unit) 97 { 98 SOC_IF_ERROR_RETURN 99 (soc_reg_field32_modify(unit, IP1_INTR_ENABLEr, REG_PORT_ANY, 100 L2_ENTRY_OVF_NO_LEARN_INTRf, 0)); 101 SOC_IF_ERROR_RETURN 102 (soc_reg_field32_modify(unit, IP1_INTR_ENABLEr, REG_PORT_ANY, 103 L2_ENTRY_NO_LEARN_INTRf, 0)); 104 /* Mark as inactive */ 105 SOC_CONTROL_LOCK(unit); 106 SOC_CONTROL(unit)->l2_overflow_active = FALSE; 107 SOC_CONTROL_UNLOCK(unit); 108 /* But don't disable interrupt as its shared by various parity events */ 109 return SOC_E_NONE; 110 } 111 112 /* 113 * Function: 114 * soc_hr3_l2_overflow_intr_enable 115 * Purpose: 116 * Enable the interrupt of L2 non-learned event. 117 * Parameters: 118 * unit - unit number. 119 * Returns: 120 * SOC_E_XXX. 121 */ 122 123 int 124 soc_hr3_l2_overflow_intr_enable(int unit) 125 { 126 if (SOC_CONTROL(unit)->l2_overflow_bucket_enable) { 127 /* clear status */ 128 SOC_IF_ERROR_RETURN(soc_reg32_set( 129 unit, L2_ENTRY_OVF_NO_LEARN_STATUSr, REG_PORT_ANY, 0, 0)); 130 131 SOC_IF_ERROR_RETURN 132 (soc_reg_field32_modify(unit, IP1_INTR_ENABLEr, REG_PORT_ANY, 133 L2_ENTRY_OVF_NO_LEARN_INTRf, 1)); 134 } else { 135 /* clear status */ 136 SOC_IF_ERROR_RETURN(soc_reg32_set( 137 unit, L2_ENTRY_NO_LEARN_STATUSr, REG_PORT_ANY, 0, 0)); 138 139 SOC_IF_ERROR_RETURN 140 (soc_reg_field32_modify(unit, IP1_INTR_ENABLEr, REG_PORT_ANY, 141 L2_ENTRY_NO_LEARN_INTRf, 1)); 142 } 143 /* Mark as active */ 144 SOC_CONTROL_LOCK(unit); 145 SOC_CONTROL(unit)->l2_overflow_active = TRUE; 146 SOC_CONTROL_UNLOCK(unit); 147 return SOC_E_NONE; 148 } 149 150 151 /* 152 * Function: 153 * soc_hr3_l2_overflow_fill 154 * Purpose: 155 * Fill the values of L2 non-learned entry. 156 * Parameters: 157 * unit - unit number. 158 * zeros_or_ones - value to be filled 159 * Returns: 160 * SOC_E_XXX. 161 */ 162 163 int 164 soc_hr3_l2_overflow_fill(int unit, uint8 zeros_or_ones) 165 { 166 uint64 macsa; 167 uint32 vlan_port; 168 169 if (zeros_or_ones) { 170 COMPILER_64_SET(macsa, 0xffffffff, 0xffffffff); 171 vlan_port = 0xffffffff; 172 } else { 173 COMPILER_64_ZERO(macsa); 174 vlan_port = 0; 175 } 176 SOC_IF_ERROR_RETURN 177 (WRITE_L2_NON_LEARNED_MESSAGE_MACSAr(unit, macsa)); 178 SOC_IF_ERROR_RETURN 179 (WRITE_L2_NON_LEARNED_MESSAGE_VLAN_PORTr(unit, vlan_port)); 180 181 return SOC_E_NONE; 182 } 183 184 185 /* 186 * Function: 187 * soc_hr3_l2_overflow_interrupt_handler 188 * Purpose: 189 * The handler of l2 non-learned interrupts. 190 * Parameters: 191 * unit - unit number. 192 * Returns: 193 * SOC_E_XXX. 194 */ 195 196 void 197 soc_hr3_l2_overflow_interrupt_handler(int unit) 198 { 199 l2x_entry_t l2x_entry; 200 201 if (!SOC_CONTROL(unit)->l2_overflow_active) { 202 LOG_ERROR(BSL_LS_SOC_L2, 203 (BSL_META_U(unit, 204 "Received L2 overflow event with no app handler or" \ 205 " processing inactive !!\n"))); 206 } 207 if (soc_hr3_l2_overflow_intr_disable(unit)) { 208 return; 209 } 210 sal_memset(&l2x_entry, 0, sizeof(l2x_entry_t)); 211 if (soc_hr3_l2_overflow_entry_get(unit, &l2x_entry)) { 212 return; 213 } 214 /* Callback */ 215 soc_l2x_callback(unit, SOC_L2X_ENTRY_OVERFLOW, NULL, &l2x_entry); 216 } 217 218 /* 219 * Function: 220 * soc_hr3_l2_overflow_start 221 * Purpose: 222 * Start reporting the L2 overflow events. 223 * Parameters: 224 * unit - unit number. 225 * Returns: 226 * SOC_E_XXX. 227 */ 228 229 int 230 soc_hr3_l2_overflow_start(int unit) 231 { 232 if (!SOC_CONTROL(unit)->l2_overflow_enable) { 233 return SOC_E_NONE; 234 } 235 if (SOC_CONTROL(unit)->l2_overflow_active) { 236 return SOC_E_NONE; 237 } 238 239 SOC_IF_ERROR_RETURN(soc_hr3_l2_overflow_fill(unit, 0)); 240 SOC_IF_ERROR_RETURN(soc_hr3_l2_overflow_intr_enable(unit)); 241 242 return SOC_E_NONE; 243 } 244 245 /* 246 * Function: 247 * soc_hr3_l2_overflow_stop 248 * Purpose: 249 * Stop reporting the L2 overflow events. 250 * Parameters: 251 * unit - unit number. 252 * Returns: 253 * SOC_E_XXX. 254 */ 255 256 int 257 soc_hr3_l2_overflow_stop(int unit) 258 { 259 if (!SOC_CONTROL(unit)->l2_overflow_enable) { 260 return SOC_E_NONE; 261 } 262 263 SOC_IF_ERROR_RETURN(soc_hr3_l2_overflow_fill(unit, 0)); 264 SOC_IF_ERROR_RETURN(soc_hr3_l2_overflow_intr_disable(unit)); 265 266 return SOC_E_NONE; 267 } 268 269 270 /* 271 * Function: 272 * soc_hr3_l2_overflow_sync 273 * Purpose: 274 * Synchronize the L2 overflow table and make any ARL callbacks that are necessary. 275 * It is called from _soc_l2x_thread. 276 * Parameters: 277 * unit - unit number. 278 * Returns: 279 * SOC_E_XXX. 280 */ 281 282 void 283 soc_hr3_l2_overflow_sync(int unit) 284 { 285 uint32 new_valid, old_valid; 286 uint32 *new_p, *old_p; 287 int i, count, rv = SOC_E_NONE; 288 289 if (l2x_ovf_data[unit] == NULL) { 290 return; 291 } 292 293 new_p = l2x_ovf_data[unit]->buf; 294 if ((rv = soc_mem_read_range(unit, l2x_ovf_data[unit]->mem, 295 MEM_BLOCK_ANY, 0, 296 l2x_ovf_data[unit]->count - 1, 297 new_p)) < 0) { 298 299 LOG_ERROR(BSL_LS_SOC_L2, 300 (BSL_META_U(unit,"soc_hr3_l2_overflow_sync: DMA failed: %s\n"), 301 soc_errmsg(rv))); 302 303 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 304 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv); 305 306 } else { 307 308 /* 309 * Scan, compare, and sync the old and new chunks one bucket 310 * at a time. 311 */ 312 313 old_p = l2x_ovf_data[unit]->shadow_tab; 314 count = l2x_ovf_data[unit]->count; 315 for (i = 0; i < count; i++) { 316 /* Check the new added entries of L2_ENTRY_OVERFLOW table */ 317 new_valid = L2_OVERFLOW_IS_VALID_ENTRY(unit, 318 l2x_ovf_data[unit]->mem, 319 new_p, VALIDf); 320 old_valid = L2_OVERFLOW_IS_VALID_ENTRY(unit, 321 l2x_ovf_data[unit]->mem, 322 old_p, VALIDf); 323 324 if (new_valid && !old_valid) { 325 /* Add */ 326 soc_l2x_callback(unit, 0, 327 NULL, (l2x_entry_t *) new_p); 328 } else if (!new_valid && old_valid) { 329 /* Delete */ 330 soc_l2x_callback(unit, 0, 331 (l2x_entry_t *) old_p, NULL); 332 } else if (new_valid && old_valid) { 333 if (!L2_OVERFLOW_ENTRY_EQL(unit, old_p, new_p, 334 WORDS2BYTES(l2x_ovf_data[unit]->entry_words), 0)) { 335 /* Change */ 336 soc_l2x_callback(unit, 0, 337 (l2x_entry_t *) old_p, (l2x_entry_t *) new_p); 338 } 339 } 340 341 new_p += l2x_ovf_data[unit]->entry_words; 342 old_p += l2x_ovf_data[unit]->entry_words; 343 } 344 345 sal_memcpy(l2x_ovf_data[unit]->shadow_tab, l2x_ovf_data[unit]->buf, 346 count * l2x_ovf_data[unit]->entry_words * 4); 347 } 348 349 return; 350 } 351 352 353 /* 354 * Function: 355 * soc_hr3_l2_overflow_sync_cleanup 356 * Purpose: 357 * Cleanup shadow table of L2 overflow table synchronization. 358 * Parameters: 359 * unit - unit number. 360 * Returns: 361 * SOC_E_XXX. 362 */ 363 364 void 365 soc_hr3_l2_overflow_sync_cleanup(int unit) 366 { 367 if (l2x_ovf_data[unit]->shadow_tab) { 368 sal_free(l2x_ovf_data[unit]->shadow_tab); 369 } 370 371 if (l2x_ovf_data[unit]->buf) { 372 soc_cm_sfree(unit, l2x_ovf_data[unit]->buf); 373 } 374 375 if (l2x_ovf_data[unit]) { 376 sal_free(l2x_ovf_data[unit]); 377 } 378 379 return; 380 } 381 382 /* 383 * Function: 384 * soc_hr3_l2_overflow_sync_init 385 * Purpose: 386 * Initialize shadow table and prepare for L2 overflow table synchronization. 387 * Parameters: 388 * unit - unit number. 389 * Returns: 390 * SOC_E_XXX. 391 */ 392 393 int 394 soc_hr3_l2_overflow_sync_init(int unit) 395 { 396 int index_count; 397 398 /* soc_mem_clear(unit, L2_ENTRY_OVERFLOWm, MEM_BLOCK_ALL, FALSE); */ 399 l2x_ovf_data[unit] = sal_alloc(sizeof(l2x_overflow_data_t), "l2x_ovf_data"); 400 if (l2x_ovf_data[unit] == NULL) { 401 return SOC_E_MEMORY; 402 } 403 404 l2x_ovf_data[unit]->mem = L2_ENTRY_OVERFLOWm; 405 l2x_ovf_data[unit]->entry_words = soc_mem_entry_words(unit, 406 l2x_ovf_data[unit]->mem); 407 l2x_ovf_data[unit]->entry_bytes = soc_mem_entry_bytes(unit, 408 l2x_ovf_data[unit]->mem); 409 410 index_count = soc_mem_index_count(unit, 411 l2x_ovf_data[unit]->mem); 412 413 l2x_ovf_data[unit]->count = index_count; 414 415 if (l2x_ovf_data[unit]->count == 0) { 416 return SOC_E_EMPTY; 417 } 418 419 l2x_ovf_data[unit]->shadow_tab = 420 sal_alloc(index_count * l2x_ovf_data[unit]->entry_words * 4, 421 "l2x_ovf_old"); 422 423 l2x_ovf_data[unit]->buf = soc_cm_salloc(unit, 424 index_count * l2x_ovf_data[unit]->entry_words * 4, 425 "l2x_ovf_new"); 426 427 if ((l2x_ovf_data[unit]->shadow_tab == NULL) || 428 (l2x_ovf_data[unit]->buf == NULL)) { 429 return SOC_E_MEMORY; 430 } 431 432 sal_memset(l2x_ovf_data[unit]->shadow_tab, 0, 433 index_count * l2x_ovf_data[unit]->entry_words * 4); 434 435 return SOC_E_NONE; 436 } 437 438 #endif /* BCM_HURRICANE3_SUPPORT */