l3x.c (55139B)
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: l3x.c 8 * 9 * Provides: 10 * soc_internal_l3x_read 11 * soc_internal_l3x_write 12 * soc_internal_l3x_init 13 * soc_internal_l3x_del 14 * soc_internal_l3x_ins 15 * 16 * Requires: 17 */ 18 19 #include <shared/bsl.h> 20 21 #include <soc/mem.h> 22 #include <soc/hash.h> 23 #include <soc/drv.h> 24 #include <soc/l3x.h> 25 #ifdef BCM_TRIDENT2_SUPPORT 26 #include <soc/trident2.h> 27 #endif /* BCM_TRIDENT2_SUPPORT */ 28 #ifdef BCM_TOMAHAWK_SUPPORT 29 #include <soc/tomahawk.h> 30 #endif /* BCM_TOMAHAWK_SUPPORT */ 31 #ifdef BCM_MONTEREY_SUPPORT 32 #include <soc/monterey.h> 33 #endif /* BCM_MONTEREY_SUPPORT */ 34 #ifdef BCM_APACHE_SUPPORT 35 #include <soc/apache.h> 36 #endif /* BCM_APACHE_SUPPORT */ 37 #include "pcid.h" 38 #include "mem.h" 39 #include "cmicsim.h" 40 41 #ifdef BCM_XGS_SWITCH_SUPPORT 42 #ifdef BCM_FIREBOLT_SUPPORT 43 /* 44 * Firebolt L3 Table Simulation 45 * 46 * The L3 table is hashed. 47 * 48 * L3_ENTRY_IPV4_UNICAST,L3_ENTRY_IPV4_MULTICAST, 49 * L3_ENTRY_IPV6_UNICAST, L3_ENTRY_IPV6_MULTICAST 50 * are "virtual" table which aggregates the 51 * L3_ENTRY_HIT_ONLY | L3_ENTRY_ONLY 52 * tables. 53 */ 54 enum { 55 ENT3f, 56 ENT2f, 57 ENT1f, 58 ENT0f 59 } soc_L3_ENTRY_DUMMYm_ftype; 60 61 static soc_field_info_t soc_L3_ENTRY_DUMMYm_fields[] = { 62 { ENT3f, 96, 288, SOCF_LE }, 63 { ENT2f, 96, 192, SOCF_LE }, 64 { ENT1f, 96, 96, SOCF_LE }, 65 { ENT0f, 96, 0, SOCF_LE }, 66 }; 67 static soc_mem_info_t l3_minfo = { 68 /* mem L3_XXXm */ 69 /* flags */ 0, 70 /* cmp_fn */ _soc_mem_cmp_undef, 71 /* *null_entry */ _soc_mem_entry_null_zeroes, 72 /* index_min */ 0, 73 /* index_max */ 0, 74 /* minblock */ 0, 75 /* maxblock */ 0, 76 /* blocks */ 0, 77 /* blocks_hi */ 0, 78 /* base */ 0, 79 /* gran */ 1, 80 /* bytes */ 25, 81 /* nFields */ 4, /* Used */ 82 /* *fields */ soc_L3_ENTRY_DUMMYm_fields, /* Used */ 83 }; 84 85 #define L3_ENTRY_IS_ALIGNED(o, a) (((o) % (a)) == 0) 86 87 int 88 soc_internal_l3x2_read(pcid_info_t * pcid_info, soc_mem_t mem, uint32 addr, 89 uint32 *entry) 90 { 91 int unit; 92 int offset; 93 uint32 ent[SOC_MAX_MEM_WORDS]; 94 int bit; 95 int bucket; 96 int index; 97 int bucket_size; 98 int blk; 99 soc_block_t sblk; 100 uint8 at = 0; 101 102 unit = pcid_info->unit; 103 offset = (addr ^ SOC_MEM_INFO(unit, mem).base) & 0xfffff; 104 105 memset(entry, 0, 4 * soc_mem_entry_words(unit, mem)); 106 memset(ent, 0, 4 * soc_mem_entry_words(unit, mem)); 107 108 bucket_size = L3_BUCKET_SIZE(unit); 109 110 /* 111 * Fix l3_minfo using info from L3_ENTRY_ONLYm table 112 */ 113 soc_L3_ENTRY_DUMMYm_fields[3].len = soc_L3_ENTRY_DUMMYm_fields[2].len = 114 soc_L3_ENTRY_DUMMYm_fields[1].len = soc_L3_ENTRY_DUMMYm_fields[0].len = 115 soc_mem_entry_bits(unit, L3_ENTRY_ONLYm); 116 soc_L3_ENTRY_DUMMYm_fields[3].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 0; 117 soc_L3_ENTRY_DUMMYm_fields[2].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 1; 118 soc_L3_ENTRY_DUMMYm_fields[1].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 2; 119 soc_L3_ENTRY_DUMMYm_fields[0].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 3; 120 121 /* 122 * We could assert on V6 and IPMC bits depending which table 123 * is being read/written. But that won't be good for diags. 124 */ 125 switch(mem) { 126 case L3_ENTRY_IPV4_MULTICASTm: 127 #ifdef BCM_TRIUMPH_SUPPORT 128 if (SOC_IS_TR_VL(unit)) { 129 /* Uses two slots per entry */ 130 index = offset * 2; 131 bucket = index / bucket_size; 132 bit = (index % bucket_size); 133 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 134 sblk = SOC_BLOCK2SCH(unit, blk); 135 soc_internal_extended_read_mem(pcid_info, sblk, at, 136 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 137 blk, index + 0, &at), entry); 138 139 soc_internal_extended_read_mem(pcid_info, sblk, at, 140 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 141 blk, index + 1, &at), ent); 142 soc_meminfo_field_set(mem, &l3_minfo, entry, ENT1f, ent); 143 144 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm); 145 sblk = SOC_BLOCK2SCH(unit, blk); 146 soc_internal_extended_read_mem(pcid_info, sblk, at, 147 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 148 blk, bucket, &at), ent); 149 soc_mem_field32_set(unit, L3_ENTRY_IPV4_MULTICASTm, entry, 150 HIT_0f, (ent[0] >> (bit + 0)) & 1); 151 soc_mem_field32_set(unit, L3_ENTRY_IPV4_MULTICASTm, entry, 152 HIT_1f, (ent[0] >> (bit + 1)) & 1); 153 break; 154 } 155 #endif 156 /* fallthrough */ 157 case L3_ENTRY_IPV4_UNICASTm: 158 /* Uses one slot per entry */ 159 index = offset; 160 bucket = index / bucket_size; 161 bit = (index % bucket_size); 162 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 163 sblk = SOC_BLOCK2SCH(unit, blk); 164 soc_internal_extended_read_mem(pcid_info, sblk, at, 165 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 166 blk, index + 0, &at), entry); 167 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm); 168 sblk = SOC_BLOCK2SCH(unit, blk); 169 soc_internal_extended_read_mem(pcid_info, sblk, at, 170 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 171 blk, bucket, &at), ent); 172 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, entry, 173 HITf, (ent[0] >> bit) & 1); 174 175 break; 176 case L3_ENTRY_IPV6_UNICASTm: 177 /* Uses two slots per entry */ 178 index = offset * 2; 179 bucket = index / bucket_size; 180 bit = (index % bucket_size); 181 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 182 sblk = SOC_BLOCK2SCH(unit, blk); 183 soc_internal_extended_read_mem(pcid_info, sblk, at, 184 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 185 blk, index + 0, &at), entry); 186 187 soc_internal_extended_read_mem(pcid_info, sblk, at, 188 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 189 blk, index + 1, &at), ent); 190 soc_meminfo_field_set(mem, &l3_minfo, entry, ENT1f, ent); 191 192 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm); 193 sblk = SOC_BLOCK2SCH(unit, blk); 194 soc_internal_extended_read_mem(pcid_info, sblk, at, 195 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 196 blk, bucket, &at), ent); 197 soc_mem_field32_set(unit, L3_ENTRY_IPV6_UNICASTm, entry, 198 HIT_0f, (ent[0] >> (bit + 0)) & 1); 199 soc_mem_field32_set(unit, L3_ENTRY_IPV6_UNICASTm, entry, 200 HIT_1f, (ent[0] >> (bit + 1)) & 1); 201 break; 202 case L3_ENTRY_IPV6_MULTICASTm: 203 /* Uses four slots per entry */ 204 index = offset * 4; 205 bucket = index / bucket_size; 206 bit = (index % bucket_size); 207 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 208 sblk = SOC_BLOCK2SCH(unit, blk); 209 soc_internal_extended_read_mem(pcid_info, sblk, at, 210 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 211 blk, index + 0, &at), entry); 212 213 soc_internal_extended_read_mem(pcid_info, sblk, at, 214 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 215 blk, index + 1, &at), ent); 216 soc_meminfo_field_set(mem, &l3_minfo, entry, ENT1f, ent); 217 218 soc_internal_extended_read_mem(pcid_info, sblk, at, 219 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 220 blk, index + 2, &at), ent); 221 soc_meminfo_field_set(mem, &l3_minfo, entry, ENT2f, ent); 222 223 soc_internal_extended_read_mem(pcid_info, sblk, at, 224 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 225 blk, index + 3, &at), ent); 226 soc_meminfo_field_set(mem, &l3_minfo, entry, ENT3f, ent); 227 228 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm); 229 sblk = SOC_BLOCK2SCH(unit, blk); 230 soc_internal_extended_read_mem(pcid_info, sblk, at, 231 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 232 blk, bucket, &at), ent); 233 soc_mem_field32_set(unit, L3_ENTRY_IPV6_MULTICASTm, entry, 234 HIT_0f, (ent[0] >> (bit + 0)) & 1); 235 soc_mem_field32_set(unit, L3_ENTRY_IPV6_MULTICASTm, entry, 236 HIT_1f, (ent[0] >> (bit + 1)) & 1); 237 soc_mem_field32_set(unit, L3_ENTRY_IPV6_MULTICASTm, entry, 238 HIT_2f, (ent[0] >> (bit + 2)) & 1); 239 soc_mem_field32_set(unit, L3_ENTRY_IPV6_MULTICASTm, entry, 240 HIT_3f, (ent[0] >> (bit + 3)) & 1); 241 break; 242 default: return(-1); 243 } 244 return(0); 245 } 246 247 int 248 soc_internal_l3x2_write(pcid_info_t * pcid_info, soc_mem_t mem, uint32 addr, 249 uint32 *entry) 250 { 251 int unit; 252 int offset; 253 uint32 ent[SOC_MAX_MEM_WORDS]; 254 int bit; 255 int bucket; 256 int index; 257 int hit; 258 int bucket_size; 259 int blk; 260 soc_block_t sblk; 261 uint8 at = 0; 262 263 unit = pcid_info->unit; 264 offset = (addr ^ SOC_MEM_INFO(unit, mem).base) & 0xfffff; 265 memset(ent, 0, 4 * soc_mem_entry_words(unit, mem)); 266 267 bucket_size = L3_BUCKET_SIZE(unit); 268 269 /* 270 * Fix l3_minfo using info from L3_ENTRY_ONLYm table 271 */ 272 soc_L3_ENTRY_DUMMYm_fields[3].len = soc_L3_ENTRY_DUMMYm_fields[2].len = 273 soc_L3_ENTRY_DUMMYm_fields[1].len = soc_L3_ENTRY_DUMMYm_fields[0].len = 274 soc_mem_entry_bits(unit, L3_ENTRY_ONLYm); 275 soc_L3_ENTRY_DUMMYm_fields[3].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 0; 276 soc_L3_ENTRY_DUMMYm_fields[2].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 1; 277 soc_L3_ENTRY_DUMMYm_fields[1].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 2; 278 soc_L3_ENTRY_DUMMYm_fields[0].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 3; 279 280 /* 281 * We could assert on V6 and IPMC bits depending which table 282 * is being read/written. But that won't be good for diags. 283 */ 284 switch(mem) { 285 case L3_ENTRY_IPV4_MULTICASTm: 286 #ifdef BCM_TRIUMPH_SUPPORT 287 if (SOC_IS_TR_VL(unit)) { 288 /* Uses two slots per entry */ 289 index = offset * 2; 290 bucket = index / bucket_size; 291 bit = (index % bucket_size); 292 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 293 sblk = SOC_BLOCK2SCH(unit, blk); 294 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT0f, ent, SOC_MAX_MEM_WORDS); 295 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0); 296 soc_internal_extended_write_mem(pcid_info, sblk, at, 297 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 298 blk, index + 0, &at), ent); 299 300 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT1f, ent, SOC_MAX_MEM_WORDS); 301 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0); 302 soc_internal_extended_write_mem(pcid_info, sblk, at, 303 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 304 blk, index + 1, &at), ent); 305 306 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm); 307 sblk = SOC_BLOCK2SCH(unit, blk); 308 soc_internal_extended_read_mem(pcid_info, sblk, at, 309 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 310 blk, bucket, &at), ent); 311 ent[0] &= (~((0x3 << (bit)))); 312 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV4_MULTICASTm, 313 entry, HIT_0f); 314 ent[0] |= ((hit & 1) << (bit + 0)); 315 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV4_MULTICASTm, 316 entry, HIT_1f); 317 ent[0] |= ((hit & 1) << (bit + 1)); 318 soc_internal_extended_write_mem(pcid_info, sblk, at, 319 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 320 blk, bucket, &at), ent); 321 322 break; 323 } 324 #endif 325 /* fallthrough */ 326 case L3_ENTRY_IPV4_UNICASTm: 327 /* Uses one slot per entry */ 328 index = offset; 329 bucket = index / bucket_size; 330 bit = (index % bucket_size); 331 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm); 332 sblk = SOC_BLOCK2SCH(unit, blk); 333 soc_internal_extended_read_mem(pcid_info, sblk, at, 334 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 335 blk, bucket, &at), ent); 336 ent[0] &= (~((0x1 << (bit)))); 337 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV4_UNICASTm, 338 entry, HITf); 339 ent[0] |= ((hit & 1) << (bit)); 340 soc_internal_extended_write_mem(pcid_info, sblk, at, 341 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 342 blk, bucket, &at), ent); 343 344 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 345 sblk = SOC_BLOCK2SCH(unit, blk); 346 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, entry, HITf, 0); 347 soc_internal_extended_write_mem(pcid_info, sblk, at, 348 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 349 blk, index + 0, &at), entry); 350 break; 351 case L3_ENTRY_IPV6_UNICASTm: 352 /* Uses two slots per entry */ 353 index = offset * 2; 354 bucket = index / bucket_size; 355 bit = (index % bucket_size); 356 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 357 sblk = SOC_BLOCK2SCH(unit, blk); 358 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT0f, ent, SOC_MAX_MEM_WORDS); 359 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0); 360 soc_internal_extended_write_mem(pcid_info, sblk, at, 361 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 362 blk, index + 0, &at), ent); 363 364 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT1f, ent, SOC_MAX_MEM_WORDS); 365 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0); 366 soc_internal_extended_write_mem(pcid_info, sblk, at, 367 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 368 blk, index + 1, &at), ent); 369 370 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm); 371 sblk = SOC_BLOCK2SCH(unit, blk); 372 soc_internal_extended_read_mem(pcid_info, sblk, at, 373 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 374 blk, bucket, &at), ent); 375 ent[0] &= (~((0x3 << (bit)))); 376 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_UNICASTm, 377 entry, HIT_0f); 378 ent[0] |= ((hit & 1) << (bit + 0)); 379 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_UNICASTm, 380 entry, HIT_1f); 381 ent[0] |= ((hit & 1) << (bit + 1)); 382 soc_internal_extended_write_mem(pcid_info, sblk, at, 383 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 384 blk, bucket, &at), ent); 385 386 break; 387 case L3_ENTRY_IPV6_MULTICASTm: 388 /* Uses four slots per entry */ 389 index = offset * 4; 390 bucket = index / bucket_size; 391 bit = (index % bucket_size); 392 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 393 sblk = SOC_BLOCK2SCH(unit, blk); 394 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT0f, ent, SOC_MAX_MEM_WORDS); 395 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0); 396 soc_internal_extended_write_mem(pcid_info, sblk, at, 397 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 398 blk, index + 0, &at), ent); 399 400 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT1f, ent, SOC_MAX_MEM_WORDS); 401 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0); 402 soc_internal_extended_write_mem(pcid_info, sblk, at, 403 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 404 blk, index + 1, &at), ent); 405 406 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT2f, ent, SOC_MAX_MEM_WORDS); 407 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0); 408 soc_internal_extended_write_mem(pcid_info, sblk, at, 409 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 410 blk, index + 2, &at), ent); 411 412 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT3f, ent, SOC_MAX_MEM_WORDS); 413 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0); 414 soc_internal_extended_write_mem(pcid_info, sblk, at, 415 soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 416 blk, index + 3, &at), ent); 417 418 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm); 419 sblk = SOC_BLOCK2SCH(unit, blk); 420 soc_internal_extended_read_mem(pcid_info, sblk, at, 421 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 422 blk, bucket, &at), ent); 423 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_MULTICASTm, 424 entry, HIT_0f); 425 ent[0] &= (~((0xf << (bit)))); 426 ent[0] |= ((hit & 1) << (bit + 0)); 427 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_MULTICASTm, 428 entry, HIT_1f); 429 ent[0] |= ((hit & 1) << (bit + 1)); 430 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_MULTICASTm, 431 entry, HIT_2f); 432 ent[0] |= ((hit & 1) << (bit + 2)); 433 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_MULTICASTm, 434 entry, HIT_3f); 435 ent[0] |= ((hit & 1) << (bit + 3)); 436 soc_internal_extended_write_mem(pcid_info, sblk, at, 437 soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 438 blk, bucket, &at), ent); 439 break; 440 default: return(-1); 441 } 442 return(0); 443 } 444 445 int 446 soc_internal_l3x2_entry_size_get(pcid_info_t *pcid_info, void *entry, 447 soc_mem_t *mem, int *num_vbits) 448 { 449 int unit = pcid_info->unit; 450 451 #ifdef BCM_TRX_SUPPORT 452 if (SOC_MEM_FIELD_VALID(unit, L3_ENTRY_ONLYm, KEY_TYPEf)) { 453 int key_type; 454 455 key_type = soc_mem_field32_get(unit, L3_ENTRY_ONLYm, 456 entry, KEY_TYPEf); 457 #ifdef BCM_TOMAHAWK_SUPPORT 458 if (SOC_IS_TOMAHAWKX(unit)) { 459 switch (key_type) { 460 case TH_L3_HASH_KEY_TYPE_V4UC: 461 case TH_L3_HASH_KEY_TYPE_TRILL: 462 *num_vbits = 1; 463 *mem = L3_ENTRY_IPV4_UNICASTm; 464 break; 465 case TH_L3_HASH_KEY_TYPE_V4UC_EXT: 466 case TH_L3_HASH_KEY_TYPE_V4MC: 467 case TH_L3_HASH_KEY_TYPE_DST_NAT: 468 case TH_L3_HASH_KEY_TYPE_DST_NAPT: 469 *num_vbits = 2; 470 *mem = L3_ENTRY_IPV4_MULTICASTm; 471 break; 472 case TH_L3_HASH_KEY_TYPE_V6UC: 473 *num_vbits = 2; 474 *mem = L3_ENTRY_IPV6_UNICASTm; 475 break; 476 case TH_L3_HASH_KEY_TYPE_V6UC_EXT: 477 case TH_L3_HASH_KEY_TYPE_V6MC: 478 *num_vbits = 4; 479 *mem = L3_ENTRY_IPV6_MULTICASTm; 480 break; 481 default: 482 return -1; 483 } 484 } else 485 #endif /* BCM_TOMAHAWK_SUPPORT */ 486 #ifdef BCM_TRIDENT2_SUPPORT 487 if (SOC_IS_TD2_TT2(unit)) { 488 switch (key_type) { 489 case TD2_L3_HASH_KEY_TYPE_V4UC: 490 case TD2_L3_HASH_KEY_TYPE_TRILL: 491 case TD2_L3_HASH_KEY_TYPE_FCOE_DOMAIN: 492 case TD2_L3_HASH_KEY_TYPE_FCOE_HOST: 493 case TD2_L3_HASH_KEY_TYPE_FCOE_SRC_MAP: 494 *num_vbits = 1; 495 *mem = L3_ENTRY_IPV4_UNICASTm; 496 break; 497 case TD2_L3_HASH_KEY_TYPE_V4UC_EXT: 498 case TD2_L3_HASH_KEY_TYPE_V4MC: 499 case TD2_L3_HASH_KEY_TYPE_V4L2MC: 500 case TD2_L3_HASH_KEY_TYPE_V4L2VPMC: 501 case TD2_L3_HASH_KEY_TYPE_FCOE_DOMAIN_EXT: 502 case TD2_L3_HASH_KEY_TYPE_FCOE_HOST_EXT: 503 case TD2_L3_HASH_KEY_TYPE_FCOE_SRC_MAP_EXT: 504 case TD2_L3_HASH_KEY_TYPE_DST_NAT: 505 case TD2_L3_HASH_KEY_TYPE_DST_NAPT: 506 *num_vbits = 2; 507 *mem = L3_ENTRY_IPV4_MULTICASTm; 508 break; 509 case TD2_L3_HASH_KEY_TYPE_V6UC: 510 *num_vbits = 2; 511 *mem = L3_ENTRY_IPV6_UNICASTm; 512 break; 513 case TD2_L3_HASH_KEY_TYPE_V6UC_EXT: 514 case TD2_L3_HASH_KEY_TYPE_V6MC: 515 case TD2_L3_HASH_KEY_TYPE_V6L2MC: 516 case TD2_L3_HASH_KEY_TYPE_V6L2VPMC: 517 *num_vbits = 4; 518 *mem = L3_ENTRY_IPV6_MULTICASTm; 519 break; 520 default: 521 return -1; 522 } 523 } else 524 #endif /* BCM_TRIDENT2_SUPPORT */ 525 { 526 switch (key_type) { 527 case TR_L3_HASH_KEY_TYPE_V4UC: 528 *num_vbits = 1; 529 *mem = L3_ENTRY_IPV4_UNICASTm; 530 break; 531 case TR_L3_HASH_KEY_TYPE_V4MC: 532 *num_vbits = SOC_IS_TR_VL(unit) ? 2 : 1; 533 *mem = L3_ENTRY_IPV4_MULTICASTm; 534 break; 535 case TR_L3_HASH_KEY_TYPE_V6UC: 536 *num_vbits = 2; 537 *mem = L3_ENTRY_IPV6_UNICASTm; 538 break; 539 case TR_L3_HASH_KEY_TYPE_V6MC: 540 *num_vbits = 4; 541 *mem = L3_ENTRY_IPV6_MULTICASTm; 542 break; 543 case TR_L3_HASH_KEY_TYPE_LMEP: 544 *num_vbits = 1; 545 *mem = L3_ENTRY_IPV4_UNICASTm; 546 break; 547 case TR_L3_HASH_KEY_TYPE_RMEP: 548 *num_vbits = 1; 549 *mem = L3_ENTRY_IPV4_UNICASTm; 550 break; 551 case TR_L3_HASH_KEY_TYPE_TRILL: 552 *num_vbits = 1; 553 *mem = L3_ENTRY_ONLYm; 554 break; 555 default: 556 return -1; 557 } 558 } 559 } else 560 #endif /* BCM_TRX_SUPPORT */ 561 if (soc_mem_field32_get(unit, L3_ENTRY_IPV4_UNICASTm, entry, V6f)) { 562 if (soc_mem_field32_get(unit, L3_ENTRY_IPV4_UNICASTm, entry, IPMCf)) { 563 *mem = L3_ENTRY_IPV6_MULTICASTm; 564 *num_vbits = 4; 565 } else { 566 *mem = L3_ENTRY_IPV6_UNICASTm; 567 *num_vbits = 2; 568 } 569 } else { 570 *num_vbits = 1; 571 if (soc_mem_field32_get(unit, L3_ENTRY_IPV4_UNICASTm, entry, IPMCf)) { 572 *mem = L3_ENTRY_IPV4_MULTICASTm; 573 } else { 574 *mem = L3_ENTRY_IPV4_UNICASTm; 575 } 576 } 577 578 return 0; 579 } 580 581 STATIC int 582 soc_internal_l3x2_bucket_get(pcid_info_t *pcid_info, int bank, void *entry) 583 { 584 uint32 rval[SOC_MAX_MEM_WORDS]; 585 int bucket, hash_sel; 586 int unit = pcid_info->unit; 587 int blk; 588 uint8 acc_type; 589 uint32 addr; 590 591 #ifdef BCM_TRIDENT2_SUPPORT 592 if (SOC_IS_TD2_TT2(unit)) { 593 int hash_offset, use_lsb, index; 594 soc_reg_t reg; 595 static const soc_field_t fields[] = { 596 BANK2_HASH_OFFSETf, BANK3_HASH_OFFSETf, BANK4_HASH_OFFSETf, 597 BANK5_HASH_OFFSETf, BANK6_HASH_OFFSETf, BANK7_HASH_OFFSETf, 598 BANK8_HASH_OFFSETf, BANK9_HASH_OFFSETf 599 }; 600 int is_shared_bank; 601 uint32 (*entry_hash_proc)(int unit, int bank, int hash_offset, 602 int use_lsb, uint32 *entry); 603 604 #if defined(BCM_TOMAHAWK_SUPPORT) 605 if (SOC_IS_TOMAHAWKX(unit)) { 606 static const soc_field_t l3_fields[] = { 607 L3_ENTRY_BANK_4f, L3_ENTRY_BANK_5f, L3_ENTRY_BANK_6f, 608 L3_ENTRY_BANK_7f 609 }; 610 611 entry_hash_proc = soc_th_l3x_entry_hash; 612 if (bank < 4) { 613 is_shared_bank = FALSE; 614 index = bank + 4; 615 } else { 616 is_shared_bank = TRUE; 617 addr = soc_reg_addr_get(unit, ISS_LOG_TO_PHY_BANK_MAPr, 618 REG_PORT_ANY, 0, 619 SOC_REG_ADDR_OPTION_NONE, 620 &blk, &acc_type); 621 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, 622 rval); 623 index = soc_reg_field_get(unit, ISS_LOG_TO_PHY_BANK_MAPr, 624 rval[0], l3_fields[bank - 4]); 625 } 626 } else 627 #endif /*TOMAHAWK_SUPPORT */ 628 629 #if defined(BCM_APACHE_SUPPORT) 630 if (SOC_IS_APACHE(unit)) { 631 static const soc_field_t l3_fields[] = { 632 L3_ENTRY_BANK_4f, L3_ENTRY_BANK_5f, L3_ENTRY_BANK_6f, 633 L3_ENTRY_BANK_7f 634 }; 635 entry_hash_proc = soc_ap_l3x_entry_hash; 636 if (bank < 4) { 637 is_shared_bank = FALSE; 638 index = bank + 4; 639 } else { 640 is_shared_bank = TRUE; 641 addr = soc_reg_addr_get(unit, ISS_LOG_TO_PHY_BANK_MAPr, 642 REG_PORT_ANY, 0, 643 SOC_REG_ADDR_OPTION_NONE, 644 &blk, &acc_type); 645 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, 646 rval); 647 index = soc_reg_field_get(unit, ISS_LOG_TO_PHY_BANK_MAPr, 648 rval[0], l3_fields[bank - 4]); 649 } 650 } else 651 #endif /*BCM_APACHE_SUPPORT */ 652 653 { 654 entry_hash_proc = soc_td2_l3x_entry_hash; 655 is_shared_bank = bank < 6; 656 index = bank - 2; 657 } 658 659 reg = L3_TABLE_HASH_CONTROLr; 660 addr = soc_reg_addr_get(unit, reg, REG_PORT_ANY, 0, 661 SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type); 662 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval); 663 use_lsb = soc_reg_field_get(unit, reg, rval[0], HASH_ZERO_OR_LSBf); 664 665 if (is_shared_bank) { 666 reg = SHARED_TABLE_HASH_CONTROLr; 667 addr = soc_reg_addr_get(unit, reg, REG_PORT_ANY, 0, 668 SOC_REG_ADDR_OPTION_NONE, &blk, 669 &acc_type); 670 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, 671 rval); 672 } 673 hash_offset = soc_reg_field_get(unit, reg, rval[0], fields[index]); 674 bucket = entry_hash_proc(unit, bank, hash_offset, use_lsb, entry); 675 } else 676 #endif /* BCM_TRIDENT2_SUPPORT */ 677 { 678 hash_sel = -1; 679 if (bank == 1) { 680 addr = soc_reg_addr_get(unit, L3_AUX_HASH_CONTROLr, REG_PORT_ANY, 681 0, SOC_REG_ADDR_OPTION_NONE, 682 &blk, &acc_type); 683 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, 684 rval); 685 if (soc_reg_field_get(unit, L3_AUX_HASH_CONTROLr, rval[0], 686 ENABLEf)) { 687 hash_sel = soc_reg_field_get(unit, L3_AUX_HASH_CONTROLr, 688 rval[0], HASH_SELECTf); 689 } 690 } 691 if (hash_sel == -1) { 692 addr = soc_reg_addr_get(unit, HASH_CONTROLr, REG_PORT_ANY, 0, 693 SOC_REG_ADDR_OPTION_NONE, &blk, 694 &acc_type); 695 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, 696 rval); 697 hash_sel = soc_reg_field_get(unit, HASH_CONTROLr, rval[0], 698 L3_HASH_SELECTf); 699 } 700 701 bucket = soc_fb_l3x_entry_hash(unit, hash_sel, entry); 702 } 703 704 LOG_VERBOSE(BSL_LS_SOC_COMMON, 705 (BSL_META_U(unit, 706 "bank %d bucket %d\n"), bank, bucket)); 707 708 return bucket; 709 } 710 711 STATIC void 712 soc_internal_l3x2_bank_map_get(pcid_info_t *pcid_info, uint32 *bank_map, 713 int *bank_start, int *bank_inc, 714 int *do_first_fit) 715 { 716 uint32 rval[SOC_MAX_MEM_WORDS]; 717 int unit = pcid_info->unit; 718 int blk; 719 uint8 acc_type; 720 uint32 addr; 721 722 #ifdef BCM_MONTEREY_SUPPORT 723 if (SOC_IS_MONTEREY(pcid_info->unit)) { 724 *bank_map = 0x3c0; 725 *bank_start = 9; 726 *bank_inc = -1; 727 if (do_first_fit != NULL) { 728 *do_first_fit = FALSE; 729 } 730 } else 731 #endif 732 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 733 if (SOC_IS_TOMAHAWKX(pcid_info->unit) || SOC_IS_APACHE(unit)) { 734 uint32 shared_bank_map; 735 int bit_count; 736 737 #ifdef BCM_APACHE_SUPPORT 738 if (SOC_IS_APACHE(pcid_info->unit)) { 739 addr = soc_reg_addr_get(unit, L3_ISS_BANK_CONFIGr, REG_PORT_ANY, 0, 740 SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type); 741 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval); 742 shared_bank_map = soc_reg_field_get(unit, L3_ISS_BANK_CONFIGr, 743 rval[0], L3_ENTRY_BANK_CONFIGf); 744 } else 745 #endif 746 { 747 addr = soc_reg_addr_get(unit, ISS_BANK_CONFIGr, REG_PORT_ANY, 0, 748 SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type); 749 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval); 750 shared_bank_map = soc_reg_field_get(unit, ISS_BANK_CONFIGr, 751 rval[0], L3_ENTRY_BANK_CONFIGf); 752 } 753 /* calculate number of 1's in shared_bank_map */ 754 bit_count = shared_bank_map - ((shared_bank_map >> 1) & 0x5); 755 bit_count = ((bit_count & 0xc) >> 2) + (bit_count & 0x3); 756 757 *bank_map = (1 << (bit_count + 4)) - 1; 758 *bank_start = 0; 759 *bank_inc = 1; 760 if (do_first_fit != NULL) { 761 *do_first_fit = FALSE; 762 } 763 } else 764 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_APACHE_SUPPORT */ 765 #ifdef BCM_TRIDENT2_SUPPORT 766 if (SOC_IS_TD2_TT2(pcid_info->unit)) { 767 int mode; 768 769 addr = soc_reg_addr_get(unit, L3_TABLE_HASH_CONTROLr, REG_PORT_ANY, 0, 770 SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type); 771 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval); 772 mode = soc_reg_field_get(unit, L3_TABLE_HASH_CONTROLr, rval[0], MODEf); 773 switch (mode) { 774 case 1: 775 *bank_map = 0x3e0; 776 break; 777 case 2: 778 *bank_map = 0x3f0; 779 break; 780 case 3: 781 *bank_map = 0x3f8; 782 break; 783 default: 784 *bank_map = 0x3c0; 785 } 786 *bank_start = 9; 787 *bank_inc = -1; 788 if (do_first_fit != NULL) { 789 *do_first_fit = FALSE; 790 } 791 } else 792 #endif /* BCM_TRIDENT2_SUPPORT */ 793 { 794 *bank_map = 0x3; 795 *bank_start = 0; 796 *bank_inc = 1; 797 addr = soc_reg_addr_get(unit, L3_AUX_HASH_CONTROLr, REG_PORT_ANY, 0, 798 SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type); 799 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval); 800 if (do_first_fit != NULL) { 801 *do_first_fit = 802 soc_reg_field_get(unit, L3_AUX_HASH_CONTROLr, rval[0], 803 INSERT_LEAST_FULL_HALFf) ? FALSE : TRUE; 804 } 805 } 806 } 807 808 STATIC void 809 soc_internal_l3x2_bank_size_get(pcid_info_t *pcid_info, int bank, 810 int *entries_per_bank, int *entries_per_row, 811 int *entries_per_bucket, int *bank_base, 812 int *bucket_offset) 813 { 814 /* 815 * entry index = 816 * bank_base + bucket * entries_per_row + bucket_offset + slot; 817 */ 818 819 #ifdef BCM_APACHE_SUPPORT 820 if (SOC_IS_APACHE(pcid_info->unit)) { 821 (void)soc_apache_hash_bank_info_get(pcid_info->unit, L3_ENTRY_ONLYm, 822 bank, entries_per_bank, 823 entries_per_row, 824 entries_per_bucket, 825 bank_base, bucket_offset); 826 } else 827 #endif /* BCM_TOMAHAWK_SUPPORT */ 828 829 830 #ifdef BCM_TOMAHAWK_SUPPORT 831 if (SOC_IS_TOMAHAWKX(pcid_info->unit)) { 832 (void)soc_tomahawk_hash_bank_info_get(pcid_info->unit, L3_ENTRY_ONLYm, 833 bank, entries_per_bank, 834 entries_per_row, 835 entries_per_bucket, 836 bank_base, bucket_offset); 837 } else 838 #endif /* BCM_TOMAHAWK_SUPPORT */ 839 #ifdef BCM_TRIDENT2_SUPPORT 840 if (SOC_IS_TD2_TT2(pcid_info->unit)) { 841 (void)soc_trident2_hash_bank_info_get(pcid_info->unit, L3_ENTRY_ONLYm, 842 bank, entries_per_bank, 843 entries_per_row, 844 entries_per_bucket, 845 bank_base, bucket_offset); 846 } else 847 #endif /* BCM_TRIDENT2_SUPPORT */ 848 { 849 /* 850 * first half of entries (slot 0) in each bucket are for bank 0 851 * the other half of entries (slot 1) in each bucket are for bank 1 852 */ 853 if (entries_per_bank != NULL) { 854 *entries_per_bank = 855 soc_mem_index_count(pcid_info->unit, L3_ENTRY_ONLYm) / 2; 856 } 857 *entries_per_row = SOC_L3X_BUCKET_SIZE(pcid_info->unit); 858 *entries_per_bucket = *entries_per_row / 2; 859 *bank_base = 0; 860 *bucket_offset = bank * *entries_per_bucket; 861 } 862 } 863 864 int 865 soc_internal_l3x2_entry_ins(pcid_info_t *pcid_info, uint32 inv_bank_map, 866 void *entry, uint32 *result) 867 { 868 uint32 tmp[SOC_MAX_MEM_WORDS]; 869 uint32 ent[SOC_MAX_MEM_WORDS]; 870 int rv; 871 uint32 bank_map; 872 int bank, entries_per_bank, bank_start, bank_inc, free_bank; 873 int bucket, entries_per_row, bank_base, free_bucket; 874 int slot, entries_per_bucket, bucket_offset, free_slot; 875 int sub_slot; 876 int index, free_index; 877 int first_free_slot, free_slot_count, do_first_fit; 878 int best_free_slot_count, best_entries_per_bank; 879 int num_vbits; 880 int validslot_cnt; 881 soc_mem_t mem; 882 int ss_field[] = {ENT0f, ENT1f, ENT2f, ENT3f}; 883 int unit = pcid_info->unit; 884 schan_genresp_t *genresp = (schan_genresp_t *) result; 885 schan_genresp_v2_t *genresp_v2 = (schan_genresp_v2_t *) result; 886 int blk; 887 soc_block_t sblk; 888 uint8 acc_type; 889 uint32 addr; 890 891 LOG_VERBOSE(BSL_LS_SOC_COMMON, 892 (BSL_META_U(unit, 893 "L3_ENTRY Insert\n"))); 894 895 rv = soc_internal_l3x2_entry_size_get(pcid_info, entry, &mem, &num_vbits); 896 if (rv < 0) { 897 return rv; 898 } 899 900 sal_memset(ent, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 901 sal_memset(tmp, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 902 903 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 904 sblk = SOC_BLOCK2SCH(unit, blk); 905 906 free_index = -1; 907 908 soc_internal_l3x2_bank_map_get(pcid_info, &bank_map, &bank_start, 909 &bank_inc, &do_first_fit); 910 bank_map &= ~inv_bank_map; 911 912 best_free_slot_count = 0; 913 for (bank = bank_start; bank_map != 0; bank += bank_inc) { 914 if (!(bank_map & (1 << bank))) { 915 continue; 916 } 917 bank_map &= ~(1 << bank); 918 919 soc_internal_l3x2_bank_size_get(pcid_info, bank, &entries_per_bank, 920 &entries_per_row, &entries_per_bucket, 921 &bank_base, &bucket_offset); 922 bucket = soc_internal_l3x2_bucket_get(pcid_info, bank, entry); 923 free_slot_count = 0; 924 first_free_slot = -1; 925 for (slot = 0; slot < entries_per_bucket; slot += num_vbits) { 926 validslot_cnt = 0; 927 for (sub_slot = 0; sub_slot < num_vbits; sub_slot++) { 928 index = bank_base + bucket * entries_per_row + bucket_offset + 929 slot + sub_slot; 930 addr = soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, blk, index, 931 &acc_type); 932 soc_internal_extended_read_mem(pcid_info, sblk, acc_type, addr, 933 tmp); 934 if (soc_mem_field32_get(unit, L3_ENTRY_ONLYm, tmp, VALIDf)) { 935 soc_meminfo_field_set(mem, &l3_minfo, ent, 936 ss_field[sub_slot], tmp); 937 validslot_cnt++; 938 } 939 } 940 941 if (validslot_cnt == num_vbits) { 942 if (_soc_mem_cmp_l3x2(unit, entry, ent) == 0) { 943 if (num_vbits > 0) { 944 index /= num_vbits; 945 } 946 addr = soc_mem_addr_get(unit, mem, 0, blk, index, &acc_type); 947 948 LOG_VERBOSE(BSL_LS_SOC_COMMON, 949 (BSL_META_U(unit, 950 "write sblk %d acc_type %d bank %d " 951 "bucket %d, slot %d, index %d\n"), 952 sblk, acc_type, bank, bucket, slot, index)); 953 954 /* Overwrite the existing entry */ 955 soc_internal_extended_write_mem(pcid_info, sblk, acc_type, 956 addr, entry); 957 958 if (soc_feature(unit, soc_feature_generic_table_ops)) { 959 /* Copy old entry immediately after response word */ 960 memcpy(&result[1], ent, 961 soc_mem_entry_bytes(unit, mem)); 962 result[0] = 0; 963 if (soc_feature(unit, soc_feature_new_sbus_format) && 964 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) { 965 genresp_v2->type = SCHAN_GEN_RESP_TYPE_REPLACED; 966 genresp_v2->index = index; 967 } else { 968 genresp->type = SCHAN_GEN_RESP_TYPE_REPLACED; 969 genresp->index = index; 970 } 971 } 972 PCIM(pcid_info, CMIC_SCHAN_CTRL) &= ~SC_MSG_NAK_TST; 973 974 return 0; 975 } 976 } else if (validslot_cnt == 0) { 977 free_slot_count++; 978 if (first_free_slot == -1) { 979 first_free_slot = slot; 980 } 981 } 982 } 983 if (free_slot_count > 0) { 984 if (do_first_fit) { 985 if (free_index != -1) { 986 continue; 987 } 988 } else { 989 if (free_slot_count < best_free_slot_count) { 990 continue; 991 } else if (free_slot_count == best_free_slot_count) { 992 if (entries_per_bank < best_entries_per_bank) { 993 continue; 994 } else if (entries_per_bank == best_entries_per_bank) { 995 if (free_index != -1 && bank > free_bank) { 996 continue; 997 } 998 } 999 } 1000 best_free_slot_count = free_slot_count; 1001 best_entries_per_bank = entries_per_bank; 1002 } 1003 free_index = (index + 1 - entries_per_bucket + first_free_slot) / 1004 num_vbits; 1005 free_bank = bank; 1006 free_bucket = bucket; 1007 free_slot = first_free_slot; 1008 } 1009 } 1010 1011 /* Find first unused slot in bucket */ 1012 if (free_index != -1) { 1013 index = free_index; 1014 addr = soc_mem_addr_get(unit, mem, 0, blk, index, &acc_type); 1015 1016 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1017 (BSL_META_U(unit, 1018 "write sblk %d acc_type %d bank %d bucket %d, " 1019 "slot %d, index %d\n"), 1020 sblk, acc_type, free_bank, free_bucket, free_slot, index)); 1021 1022 /* Write the entry */ 1023 soc_internal_extended_write_mem(pcid_info, sblk, acc_type, addr, 1024 entry); 1025 1026 if (soc_feature(unit, soc_feature_generic_table_ops)) { 1027 result[0] = 0; 1028 if (soc_feature(unit, soc_feature_new_sbus_format) && 1029 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) { 1030 genresp_v2->type = SCHAN_GEN_RESP_TYPE_INSERTED; 1031 genresp_v2->index = index; 1032 } else { 1033 genresp->type = SCHAN_GEN_RESP_TYPE_INSERTED; 1034 genresp->index = index; 1035 } 1036 } 1037 PCIM(pcid_info, CMIC_SCHAN_CTRL) &= ~SC_MSG_NAK_TST; 1038 1039 return 0; 1040 } 1041 1042 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1043 (BSL_META_U(unit, 1044 "Bucket full\n"))); 1045 if (soc_feature(unit, soc_feature_generic_table_ops)) { 1046 result[0] = 0; 1047 if (soc_feature(unit, soc_feature_new_sbus_format) && 1048 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) { 1049 genresp_v2->type = SCHAN_GEN_RESP_TYPE_FULL; 1050 } else { 1051 genresp->type = SCHAN_GEN_RESP_TYPE_FULL; 1052 } 1053 } 1054 PCIM(pcid_info, CMIC_SCHAN_CTRL) |= SC_MSG_NAK_TST; 1055 1056 return 0; 1057 } 1058 1059 int 1060 soc_internal_l3x2_entry_del(pcid_info_t *pcid_info, uint32 inv_bank_map, 1061 void *entry, uint32 *result) 1062 { 1063 uint32 tmp[SOC_MAX_MEM_WORDS]; 1064 uint32 ent[SOC_MAX_MEM_WORDS]; 1065 int rv; 1066 uint32 bank_map; 1067 int bank, bank_start, bank_inc; 1068 int bucket, entries_per_row, bank_base; 1069 int slot, entries_per_bucket, bucket_offset; 1070 int sub_slot; 1071 int index; 1072 int num_vbits; 1073 int validslot_cnt; 1074 soc_mem_t mem; 1075 int ss_field[] = {ENT0f, ENT1f, ENT2f, ENT3f}; 1076 int unit = pcid_info->unit; 1077 schan_genresp_t *genresp = (schan_genresp_t *) result; 1078 schan_genresp_v2_t *genresp_v2 = (schan_genresp_v2_t *) result; 1079 int blk; 1080 soc_block_t sblk; 1081 uint8 acc_type; 1082 uint32 addr; 1083 1084 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1085 (BSL_META_U(unit, 1086 "L3_ENTRY Delete\n"))); 1087 1088 rv = soc_internal_l3x2_entry_size_get(pcid_info, entry, &mem, &num_vbits); 1089 if (rv < 0) { 1090 return rv; 1091 } 1092 1093 sal_memset(ent, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 1094 sal_memset(tmp, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 1095 1096 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 1097 sblk = SOC_BLOCK2SCH(unit, blk); 1098 1099 soc_internal_l3x2_bank_map_get(pcid_info, &bank_map, &bank_start, 1100 &bank_inc, NULL); 1101 bank_map &= ~inv_bank_map; 1102 1103 for (bank = bank_start; bank_map != 0; bank += bank_inc) { 1104 if (!(bank_map & (1 << bank))) { 1105 continue; 1106 } 1107 bank_map &= ~(1 << bank); 1108 1109 soc_internal_l3x2_bank_size_get(pcid_info, bank, NULL, 1110 &entries_per_row, &entries_per_bucket, 1111 &bank_base, &bucket_offset); 1112 bucket = soc_internal_l3x2_bucket_get(pcid_info, bank, entry); 1113 1114 for (slot = 0; slot < entries_per_bucket; slot += num_vbits) { 1115 validslot_cnt = 0; 1116 for (sub_slot = 0; sub_slot < num_vbits; sub_slot++) { 1117 index = bank_base + bucket * entries_per_row + bucket_offset + 1118 slot + sub_slot; 1119 addr = soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, blk, index, 1120 &acc_type); 1121 soc_internal_extended_read_mem(pcid_info, sblk, acc_type, addr, 1122 tmp); 1123 if (soc_mem_field32_get(unit, L3_ENTRY_ONLYm, tmp, VALIDf)) { 1124 soc_meminfo_field_set(mem, &l3_minfo, ent, 1125 ss_field[sub_slot], tmp); 1126 validslot_cnt++; 1127 } else { 1128 break; 1129 } 1130 } 1131 1132 if (validslot_cnt == num_vbits) { 1133 if (_soc_mem_cmp_l3x2(unit, entry, ent) == 0) { 1134 if (num_vbits > 0) { 1135 index /= num_vbits; 1136 } 1137 addr = soc_mem_addr_get(unit, mem, 0, blk, index, &acc_type); 1138 1139 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1140 (BSL_META_U(unit, 1141 "delete sblk %d acc_type %d bank %d " 1142 "bucket %d, slot %d, index %d\n"), 1143 sblk, acc_type, bank, bucket, slot, index)); 1144 1145 if (soc_feature(unit, soc_feature_generic_table_ops)) { 1146 /* Copy entry immediately after response word */ 1147 memcpy(&result[1], ent, 1148 soc_mem_entry_bytes(unit, mem)); 1149 } 1150 1151 /* Invalidate entry */ 1152 memset(tmp, 0, sizeof(tmp)); 1153 soc_internal_extended_write_mem(pcid_info, sblk, acc_type, 1154 addr, (uint32 *)tmp); 1155 1156 if (soc_feature(unit, soc_feature_generic_table_ops)) { 1157 result[0] = 0; 1158 if (soc_feature(unit, soc_feature_new_sbus_format) && 1159 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) { 1160 genresp_v2->type = SCHAN_GEN_RESP_TYPE_DELETED; 1161 genresp_v2->index = index; 1162 } else { 1163 genresp->type = SCHAN_GEN_RESP_TYPE_DELETED; 1164 genresp->index = index; 1165 } 1166 } 1167 PCIM(pcid_info, CMIC_SCHAN_CTRL) &= ~SC_MSG_NAK_TST; 1168 1169 return 0; 1170 } 1171 } 1172 } 1173 } 1174 1175 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1176 (BSL_META_U(unit, 1177 "soc_internal_l3x2_entry_del: Not found\n"))); 1178 1179 if (soc_feature(unit, soc_feature_generic_table_ops)) { 1180 result[0] = 0; 1181 if (soc_feature(unit, soc_feature_new_sbus_format) && 1182 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) { 1183 genresp_v2->type = SCHAN_GEN_RESP_TYPE_NOT_FOUND; 1184 } else { 1185 genresp->type = SCHAN_GEN_RESP_TYPE_NOT_FOUND; 1186 } 1187 } else { 1188 result[0] = 0xffffffff; 1189 } 1190 PCIM(pcid_info, CMIC_SCHAN_CTRL) |= SC_MSG_NAK_TST; 1191 1192 return 0; 1193 } 1194 int 1195 soc_internal_l3x2_entry_lkup(pcid_info_t * pcid_info, uint32 inv_bank_map, 1196 void *entry, uint32 *result) 1197 { 1198 uint32 tmp[SOC_MAX_MEM_WORDS]; 1199 uint32 ent[SOC_MAX_MEM_WORDS]; 1200 int rv; 1201 uint32 bank_map; 1202 int bank, bank_start, bank_inc; 1203 int bucket, entries_per_row, bank_base; 1204 int slot, entries_per_bucket, bucket_offset; 1205 int sub_slot; 1206 int index; 1207 int num_vbits; 1208 int validslot_cnt; 1209 int index_bit_offset; 1210 int entry_dw; 1211 soc_mem_t mem; 1212 int ss_field[] = {ENT0f, ENT1f, ENT2f, ENT3f}; 1213 int unit = pcid_info->unit; 1214 schan_genresp_t *genresp = (schan_genresp_t *) result; 1215 schan_genresp_v2_t *genresp_v2 = (schan_genresp_v2_t *) result; 1216 int blk; 1217 soc_block_t sblk; 1218 uint8 acc_type; 1219 uint32 addr; 1220 1221 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1222 (BSL_META_U(unit, 1223 "L3_ENTRY Lookup\n"))); 1224 1225 rv = soc_internal_l3x2_entry_size_get(pcid_info, entry, &mem, &num_vbits); 1226 if (rv < 0) { 1227 return rv; 1228 } 1229 1230 sal_memset(ent, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 1231 sal_memset(tmp, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 1232 1233 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm); 1234 sblk = SOC_BLOCK2SCH(unit, blk); 1235 1236 soc_internal_l3x2_bank_map_get(pcid_info, &bank_map, &bank_start, 1237 &bank_inc, NULL); 1238 bank_map &= ~inv_bank_map; 1239 1240 for (bank = bank_start; bank_map != 0; bank += bank_inc) { 1241 if (!(bank_map & (1 << bank))) { 1242 continue; 1243 } 1244 bank_map &= ~(1 << bank); 1245 1246 soc_internal_l3x2_bank_size_get(pcid_info, bank, NULL, 1247 &entries_per_row, &entries_per_bucket, 1248 &bank_base, &bucket_offset); 1249 bucket = soc_internal_l3x2_bucket_get(pcid_info, bank, entry); 1250 1251 for (slot = 0; slot < entries_per_bucket; slot += num_vbits) { 1252 validslot_cnt = 0; 1253 for (sub_slot = 0; sub_slot < num_vbits; sub_slot++) { 1254 index = bank_base + bucket * entries_per_row + bucket_offset + 1255 slot + sub_slot; 1256 addr = soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, blk, index, 1257 &acc_type); 1258 soc_internal_extended_read_mem(pcid_info, sblk, acc_type, addr, 1259 tmp); 1260 if (soc_mem_field32_get(unit, L3_ENTRY_ONLYm, tmp, VALIDf)) { 1261 soc_meminfo_field_set(mem, &l3_minfo, ent, 1262 ss_field[sub_slot], tmp); 1263 validslot_cnt++; 1264 } else { 1265 break; 1266 } 1267 } 1268 1269 if (validslot_cnt == num_vbits) { 1270 if (_soc_mem_cmp_l3x2(unit, entry, ent) == 0) { 1271 if (num_vbits > 0) { 1272 index /= num_vbits; 1273 } 1274 addr = soc_mem_addr_get(unit, mem, 0, blk, index, &acc_type); 1275 1276 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1277 (BSL_META_U(unit, 1278 "found sblk %d acc_type %d bank %d " 1279 "bucket %d, slot %d, index %d\n"), 1280 sblk, acc_type, bank, bucket, slot, index)); 1281 1282 if (soc_feature(unit, soc_feature_generic_table_ops)) { 1283 /* Copy entry immediately after response word */ 1284 memcpy(&result[1], ent, 1285 soc_mem_entry_bytes(unit, mem)); 1286 1287 result[0] = 0; 1288 if (soc_feature(unit, soc_feature_new_sbus_format) && 1289 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) { 1290 genresp_v2->type = SCHAN_GEN_RESP_TYPE_FOUND; 1291 genresp_v2->index = index; 1292 } else { 1293 genresp->type = SCHAN_GEN_RESP_TYPE_FOUND; 1294 genresp->index = index; 1295 } 1296 } else { 1297 entry_dw = soc_mem_entry_words(unit, mem); 1298 index_bit_offset = soc_mem_entry_bits(unit, mem) % 32; 1299 for(slot = 0; slot < entry_dw - 1; slot++) { 1300 result[slot] = ent[slot]; 1301 } 1302 if (index_bit_offset) { 1303 result[slot] = 1304 (ent[slot] & ((1 << index_bit_offset) - 1)) | 1305 ((index & ((1 << (32 - index_bit_offset)) - 1)) 1306 << index_bit_offset); 1307 result[slot + 1] = 1308 (index >> (32 - index_bit_offset)) & 1309 ((soc_mem_index_max(unit, mem)) >> 1310 (32 - index_bit_offset)); 1311 } else { 1312 result[slot] = index; 1313 result[slot + 1] = 0; 1314 } 1315 } 1316 PCIM(pcid_info, CMIC_SCHAN_CTRL) &= ~SC_MSG_NAK_TST; 1317 1318 return 0; 1319 } 1320 } 1321 } 1322 } 1323 1324 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1325 (BSL_META_U(unit, 1326 "soc_internal_l3x2_entry_lkup: Not found\n"))); 1327 1328 if (soc_feature(unit, soc_feature_generic_table_ops)) { 1329 result[0] = 0; 1330 if (soc_feature(unit, soc_feature_new_sbus_format) && 1331 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) { 1332 genresp_v2->type = SCHAN_GEN_RESP_TYPE_NOT_FOUND; 1333 } else { 1334 genresp->type = SCHAN_GEN_RESP_TYPE_NOT_FOUND; 1335 } 1336 } else { 1337 result[0] = 0xffffffff; 1338 } 1339 PCIM(pcid_info, CMIC_SCHAN_CTRL) |= SC_MSG_NAK_TST; 1340 1341 return 0; 1342 } 1343 #endif /* BCM_FIREBOLT_SUPPORT */ 1344 #endif