profile_mem.c (112424B)
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 * Provides generic routines for managing HW profile tables. 8 */ 9 10 #include <soc/profile_mem.h> 11 #include <soc/error.h> 12 #include <soc/drv.h> 13 14 #ifdef BCM_TOMAHAWK3_SUPPORT 15 #include <soc/tomahawk3.h> 16 #endif 17 18 /* 19 * Function: 20 * soc_profile_mem_t_init 21 * Purpose: 22 * Initialize a soc_profile_mem_t structure. 23 * 24 * Parameters: 25 * profile_mem - (IN) Pointer to profile memory structure 26 * Returns: 27 * void 28 */ 29 void 30 soc_profile_mem_t_init(soc_profile_mem_t *profile) 31 { 32 if (NULL != profile) { 33 profile->tables = NULL; 34 profile->table_count = 0; 35 profile->flags = 0; 36 } 37 } 38 39 STATIC void 40 _soc_profile_mem_free(soc_profile_mem_t *profile) 41 { 42 soc_profile_mem_table_t *table; 43 int table_index; 44 45 if (profile->tables == NULL) { 46 return; 47 } 48 49 for (table_index = 0; table_index < profile->table_count; table_index++) { 50 table = &profile->tables[table_index]; 51 if (table->data_mask != NULL) { 52 sal_free(table->data_mask); 53 table->data_mask = NULL; 54 } 55 if (table->entries != NULL) { 56 sal_free(table->entries); 57 table->entries = NULL; 58 } 59 if (table->cache_p != NULL) { 60 sal_free(table->cache_p); 61 table->cache_p = NULL; 62 } 63 } 64 sal_free(profile->tables); 65 profile->tables = NULL; 66 } 67 68 /* 69 * Function: 70 * soc_profile_mem_index_create 71 * Purpose: 72 * Create a shadow copy and refcounts of a profile table. 73 * If called during WARM BOOT, the shadow copy is populated with 74 * the HW contents, otherwise, both the shadow copy and the 75 * HW entries are cleared. 76 * 77 * Parameters: 78 * unit - (IN) Unit 79 * mem_array - (IN) Pointer to memory id array 80 * entry_words_array - (IN) Pointer to entry size array 81 * index_min_array - (IN) (optional) Pointer to index min array 82 * default is soc_mem_index_min 83 * index_max_array - (IN) (optional) Pointer to index max array 84 * default is soc_mem_index_max 85 * data_mask_array - (IN) (optional) Pointer to data mask array 86 * default is to compare the entire entry 87 * (include padding) 88 * table_count - (IN) Number of entries in memory id array 89 * profile - (IN) Pointer to profile memory structure 90 * Returns: 91 * SOC_E_XXX 92 */ 93 int 94 soc_profile_mem_index_create(int unit, 95 soc_mem_t *mem_array, 96 int *entry_words_array, 97 int *index_min_array, 98 int *index_max_array, 99 void **data_mask_array, 100 int table_count, 101 soc_profile_mem_t *profile) 102 { 103 soc_profile_mem_table_t *table; 104 int rv; 105 int alloc_size; 106 int num_entries, table_index, i; 107 #ifdef BCM_TOMAHAWK3_SUPPORT 108 int pipe, mem_per_pipe; 109 uint32 pipe_map; 110 #endif 111 soc_mem_t mem; 112 uint32 *data_mask_p, *cache_p; 113 void *null_entry = NULL; 114 115 if (profile == NULL) { 116 return SOC_E_INIT; 117 } 118 119 if (mem_array == NULL || entry_words_array == NULL || 120 table_count == 0) { 121 return SOC_E_PARAM; 122 } 123 124 if (profile->tables != NULL) { 125 _soc_profile_mem_free(profile); 126 } 127 128 alloc_size = table_count * sizeof(soc_profile_mem_table_t); 129 profile->tables = sal_alloc(alloc_size, "Profile Mem Tables"); 130 if (profile->tables == NULL) { 131 return SOC_E_MEMORY; 132 } 133 sal_memset(profile->tables, 0, alloc_size); 134 profile->table_count = table_count; 135 136 for (table_index = 0; table_index < table_count; table_index++) { 137 table = &profile->tables[table_index]; 138 table->mem = mem_array[table_index]; 139 if (index_min_array == NULL) { 140 table->index_min = soc_mem_index_min(unit, table->mem); 141 } else { 142 table->index_min = index_min_array[table_index]; 143 } 144 if (index_max_array == NULL) { 145 table->index_max = soc_mem_index_max(unit, table->mem); 146 } else { 147 table->index_max = index_max_array[table_index]; 148 } 149 if (table->index_max < table->index_min) { 150 _soc_profile_mem_free(profile); 151 return SOC_E_PARAM; 152 } 153 table->entry_words = entry_words_array[table_index]; 154 155 if (data_mask_array != NULL && data_mask_array[table_index] != NULL) { 156 alloc_size = table->entry_words * sizeof(uint32); 157 table->data_mask = sal_alloc(alloc_size, "Profile Mem Data Mask"); 158 if (table->data_mask == NULL) { 159 _soc_profile_mem_free(profile); 160 return SOC_E_MEMORY; 161 } 162 sal_memset(table->data_mask, 0, alloc_size); 163 data_mask_p = data_mask_array[table_index]; 164 for (i = 0; i < table->entry_words; i++) { 165 table->data_mask[i] = data_mask_p[i]; 166 } 167 } 168 169 num_entries = table->index_max - table->index_min + 1; 170 alloc_size = num_entries * sizeof(soc_profile_mem_entry_t); 171 table->entries = sal_alloc(alloc_size, "Profile Mem Entries"); 172 if (table->entries == NULL) { 173 _soc_profile_mem_free(profile); 174 return SOC_E_MEMORY; 175 } 176 sal_memset(table->entries, 0, alloc_size); 177 178 alloc_size = num_entries * table->entry_words * sizeof(uint32); 179 table->cache_p = sal_alloc(alloc_size, "Profile Mem Cache"); 180 if (table->cache_p == NULL) { 181 _soc_profile_mem_free(profile); 182 return SOC_E_MEMORY; 183 } 184 sal_memset(table->cache_p, 0, alloc_size); 185 } 186 187 if (SOC_WARM_BOOT(unit)) { 188 for (table_index = 0; table_index < profile->table_count; 189 table_index++) { 190 table = &profile->tables[table_index]; 191 num_entries = table->index_max - table->index_min + 1; 192 for (i = 0; i < num_entries; i++) { 193 cache_p = &table->cache_p[table->entry_words * i]; 194 #ifdef BCM_TOMAHAWK3_SUPPORT 195 if (SOC_IS_TOMAHAWK3(unit) && 196 SOC_MEM_UNIQUE_ACC(unit, table->mem)) { 197 198 mem_per_pipe = 199 (table->index_max + 1) / _TH3_PIPES_PER_DEV; 200 pipe = i / mem_per_pipe; 201 202 soc_tomahawk3_pipe_map_get(unit, &pipe_map); 203 /* skip if the pipe isn't valid (half chip) */ 204 if ((pipe_map & (1 << pipe)) == 0) { 205 continue; 206 } 207 208 mem = SOC_MEM_UNIQUE_ACC(unit, table->mem)[pipe]; 209 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, 210 table->index_min + i%mem_per_pipe, cache_p); 211 } else 212 #endif 213 { 214 mem = table->mem; 215 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, 216 table->index_min + i, cache_p); 217 } 218 if (rv < 0) { 219 _soc_profile_mem_free(profile); 220 return rv; 221 } 222 } 223 } 224 } else { 225 /* Clear HW memory */ 226 for (table_index = 0; table_index < profile->table_count; 227 table_index++) { 228 table = &profile->tables[table_index]; 229 #ifdef BCM_RCPU_SUPPORT 230 if (SOC_IS_RCPU_ONLY(unit)) { 231 /* 232 * Avoid clearing below profile tables to make remote switch 233 * able to tx/rx RCPU packets. 234 */ 235 if (ING_VLAN_TAG_ACTION_PROFILEm == table->mem || 236 EGR_VLAN_TAG_ACTION_PROFILEm == table->mem) { 237 return SOC_E_NONE; 238 } 239 } 240 #endif /* BCM_RCPU_SUPPORT */ 241 242 if (SOC_HW_RESET(unit) && 243 soc_mem_clearable_on_reset(unit, table->mem, COPYNO_ALL)){ 244 continue; 245 } 246 247 /* If the profile is setup as a non-default index_min/max, we will 248 call 'soc_mem_array_fill_range' to clear the memory, else 249 call the generic 'soc_mem_clear', this is done so that the 250 additional capabilities provided within the generic call like 251 'h/w acceleration' can be utilized in most cases. */ 252 if((table->index_min != soc_mem_index_min(unit, table->mem)) || 253 (table->index_max != soc_mem_index_max(unit, table->mem))) { 254 255 /* Allocate a null-entry to use below */ 256 null_entry = soc_cm_salloc(unit, 257 WORDS2BYTES(table->entry_words), 258 "profile create mem clear"); 259 260 /* Bail on out of memory */ 261 if(null_entry == NULL) { 262 _soc_profile_mem_free(profile); 263 return SOC_E_MEMORY; 264 } 265 266 sal_memcpy(null_entry, 267 soc_mem_entry_null(unit, table->mem), 268 soc_mem_entry_words(unit, table->mem) * 269 sizeof(uint32)); 270 271 rv = soc_mem_array_fill_range(unit, 272 0, /* Flags - unused */ 273 table->mem, 274 0, /* min_ar_index - unused */ 275 0, /* max_ar_index - unused */ 276 COPYNO_ALL, 277 table->index_min, 278 table->index_max, 279 null_entry); 280 281 /* Free the allocated null_ptr memory */ 282 soc_cm_sfree(unit, null_entry); 283 null_entry = NULL; 284 } else { 285 rv = soc_mem_clear(unit, table->mem, COPYNO_ALL, TRUE); 286 } 287 288 if (rv < 0) { 289 _soc_profile_mem_free(profile); 290 return rv; 291 } 292 } 293 } 294 295 return SOC_E_NONE; 296 } 297 298 int 299 soc_profile_mem_create(int unit, 300 soc_mem_t *mem_array, 301 int *entry_words_array, 302 int table_count, 303 soc_profile_mem_t *profile) 304 { 305 return soc_profile_mem_index_create(unit, mem_array, entry_words_array, 306 NULL, NULL, NULL, table_count, 307 profile); 308 } 309 310 /* 311 * Function: 312 * soc_profile_mem_destroy 313 * Purpose: 314 * Destroy the shadow copy and refcounts of a profile table. 315 * 316 * Parameters: 317 * unit - (IN) Unit 318 * profile_mem - (IN) Pointer to profile memory structure 319 * Returns: 320 * SOC_E_XXX 321 */ 322 int 323 soc_profile_mem_destroy(int unit, 324 soc_profile_mem_t *profile) 325 { 326 if (profile == NULL) { 327 return SOC_E_PARAM; 328 } 329 330 _soc_profile_mem_free(profile); 331 return SOC_E_NONE; 332 } 333 334 STATIC int 335 _soc_profile_mem_check(int unit, soc_profile_mem_t *profile, 336 int base0) 337 { 338 soc_profile_mem_table_t *table; 339 int num_entries, num_sets, entries_per_set, ref_count; 340 int set, table_index, i, base; 341 342 table = &profile->tables[0]; 343 entries_per_set = table->entries[base0].entries_per_set; 344 345 if (profile->table_count == 1 && entries_per_set == 1) { 346 return SOC_E_NONE; 347 } 348 349 num_entries = table->index_max - table->index_min + 1; 350 num_sets = num_entries / entries_per_set; 351 set = base0 / entries_per_set; 352 353 ref_count = table->entries[base0].ref_count; 354 for (table_index = 0; table_index < profile->table_count; table_index++) { 355 table = &profile->tables[table_index]; 356 num_entries = table->index_max - table->index_min + 1; 357 entries_per_set = num_entries / num_sets; 358 base = set * entries_per_set; 359 for (i = 0; i < entries_per_set; i++) { 360 if (table->entries[base + i].entries_per_set != entries_per_set || 361 table->entries[base + i].ref_count != ref_count) { 362 return SOC_E_INTERNAL; 363 } 364 } 365 } 366 367 return SOC_E_NONE; 368 } 369 370 /* 371 * Function: 372 * soc_profile_mem_sw_state_set 373 * Purpose: 374 * Add a set of entries (one or more entries) to a profile table. This 375 * routine searches for a matching set in the profile table. If a matching 376 * set is found, the ref count for that entry is incremented and 377 * its base index is returned. If a matching set is not found then then 378 * entry is updated at the incoming index (index0). 379 * No write to HW is done in this routine as this sets only SW state. 380 * 381 * Parameters: 382 * unit - (IN) Unit 383 * profile - (IN) Pointer to profile memory structure 384 * entries_array - (IN) Array of pointer to table entries set 385 * entries_per_set0 - (IN) Number of entries in the set for table 0 386 * index0 - (IN) Base index to the entries in HW for table 0 387 * 388 * Returns: 389 * SOC_E_XXX 390 */ 391 int 392 soc_profile_mem_sw_state_set(int unit, 393 soc_profile_mem_t *profile, 394 void **entries_array, 395 int entries_per_set0, 396 uint32 index0) 397 { 398 soc_profile_mem_table_t *table; 399 int index_min, num_entries, num_sets, entries_per_set; 400 int set, table_index, i, j, base, base0, free_set; 401 int entry_words, data_words; 402 int alloc_size, rv = SOC_E_NONE; 403 uint32 entry[SOC_MAX_MEM_WORDS]; 404 uint32 mask[SOC_MAX_MEM_WORDS]; 405 uint32 *cache_p, *entry_p, *mask_p, *range_p, *ent_p; 406 407 if (profile == NULL || entries_array == NULL || entries_per_set0 <= 0) { 408 return SOC_E_PARAM; 409 } 410 411 if (profile->tables == NULL || profile->table_count == 0) { 412 return SOC_E_INIT; 413 } 414 415 table = &profile->tables[0]; 416 num_entries = table->index_max - table->index_min + 1; 417 418 if (num_entries % entries_per_set0) { 419 return SOC_E_PARAM; 420 } 421 422 num_sets = num_entries / entries_per_set0; 423 424 for (table_index = 0; table_index < profile->table_count; table_index++) { 425 table = &profile->tables[table_index]; 426 num_entries = table->index_max - table->index_min + 1; 427 if (entries_array[table_index] == NULL) { 428 return SOC_E_PARAM; 429 } 430 431 if (num_entries % num_sets) { 432 return SOC_E_PARAM; 433 } 434 } 435 436 sal_memset(mask, 0xff, sizeof(mask)); 437 438 /* 439 * Search for an existing set that has the same configuration. 440 */ 441 free_set = -1; 442 for (set = 0; set < num_sets; set++) { 443 base0 = set * entries_per_set0; 444 445 /* Skip unused entries. */ 446 if (profile->tables[0].entries[base0].ref_count == 0) { 447 if (free_set != -1) { 448 continue; 449 } 450 451 /* Preserve location of free slot. */ 452 free_set = set; 453 if (profile->table_count == 1 && entries_per_set0 == 1) { 454 continue; 455 } 456 457 for (table_index = 0; table_index < profile->table_count; 458 table_index++) { 459 table = &profile->tables[table_index]; 460 num_entries = table->index_max - table->index_min + 1; 461 entries_per_set = num_entries / num_sets; 462 base = set * entries_per_set; 463 for (i = 0; i < entries_per_set; i++) { 464 if (table->entries[base + i].ref_count) { 465 free_set = -1; 466 break; 467 } 468 } 469 if (free_set == -1) { 470 break; 471 } 472 } 473 /* If non-shared, break out of main loop on first empty entry */ 474 if ((profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) && 475 free_set >= 0) { 476 break; 477 } 478 continue; 479 } 480 481 /* If non-shared, continue looking for empty entry */ 482 if (profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) { 483 continue; 484 } 485 486 /* Skip set of different size */ 487 if (profile->tables[0].entries[base0].entries_per_set != 488 entries_per_set0) { 489 continue; 490 } 491 492 /* Compare the new set of entries against the cache */ 493 for (table_index = 0; table_index < profile->table_count; 494 table_index++) { 495 table = &profile->tables[table_index]; 496 num_entries = table->index_max - table->index_min + 1; 497 entries_per_set = num_entries / num_sets; 498 base = set * entries_per_set; 499 entry_words = table->entry_words; 500 data_words = soc_mem_entry_words(unit, table->mem); 501 entry_p = entries_array[table_index]; 502 cache_p = &table->cache_p[base * entry_words]; 503 mask_p = table->data_mask == NULL ? mask : table->data_mask; 504 for (i = 0; i < entries_per_set; i++) { 505 for (j = 0; j < data_words; j++) { 506 if ((cache_p[j] ^ entry_p[j]) & mask_p[j]) { 507 break; 508 } 509 } 510 if (j < data_words) { 511 break; 512 } 513 entry_p += entry_words; 514 cache_p += entry_words; 515 } 516 if (i != entries_per_set) { 517 break; 518 } 519 } 520 if (table_index != profile->table_count) { 521 continue; 522 } 523 524 /* Do optional data integrity check */ 525 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 526 527 /* Matched set found */ 528 for (table_index = 0; table_index < profile->table_count; 529 table_index++) { 530 table = &profile->tables[table_index]; 531 num_entries = table->index_max - table->index_min + 1; 532 entries_per_set = num_entries / num_sets; 533 base = set * entries_per_set; 534 for (i = 0; i < entries_per_set; i++) { 535 table->entries[base + i].ref_count++; 536 } 537 } 538 return SOC_E_NONE; 539 } 540 541 /* set the incoming index as free index so that entry is added at same place */ 542 free_set = index0; 543 544 for (table_index = 0; table_index < profile->table_count; table_index++) { 545 table = &profile->tables[table_index]; 546 index_min = table->index_min; 547 num_entries = table->index_max - table->index_min + 1; 548 entries_per_set = num_entries / num_sets; 549 base = free_set * entries_per_set; 550 entry_words = table->entry_words; 551 data_words = soc_mem_entry_words(unit, table->mem); 552 entry_p = entries_array[table_index]; 553 cache_p = &table->cache_p[base * entry_words]; 554 555 if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) { 556 alloc_size = WORDS2BYTES(entry_words) * entries_per_set; 557 range_p = soc_cm_salloc(unit, alloc_size, "profile update"); 558 if (NULL == range_p) { 559 return SOC_E_MEMORY; 560 } 561 sal_memset((void *)range_p, 0, alloc_size); 562 563 if (table->data_mask != NULL) { 564 /* Read full entry from HW when profile only covers 565 * part of the table. */ 566 rv = soc_mem_read_range(unit, table->mem, MEM_BLOCK_ANY, 567 index_min + base, 568 index_min + base + entries_per_set - 1, 569 range_p); 570 } 571 572 if (SOC_SUCCESS(rv)) { 573 for (i = 0; i < entries_per_set; i++) { 574 ent_p = 575 soc_mem_table_idx_to_pointer(unit, table->mem, 576 uint32 *, range_p, i); 577 578 if (table->data_mask != NULL) { 579 /* Replace partial entry with new content */ 580 for (j = 0; j < data_words; j++) { 581 ent_p[j] &= ~table->data_mask[j]; 582 ent_p[j] |= entry_p[j] & table->data_mask[j]; 583 } 584 } else { 585 /* Write entire new entry */ 586 sal_memcpy(ent_p, entry_p, 587 data_words * sizeof(uint32)); 588 } 589 entry_p += entry_words; 590 } 591 } 592 593 if (SOC_SUCCESS(rv)) { 594 /* Copy entry into the software cache. */ 595 entry_p = entries_array[table_index]; 596 597 for (i = 0; i < entries_per_set; i++) { 598 sal_memcpy(cache_p, entry_p, 599 data_words * sizeof(uint32)); 600 entry_p += entry_words; 601 cache_p += entry_words; 602 603 table->entries[base + i].ref_count++; 604 table->entries[base + i].entries_per_set = 605 entries_per_set; 606 } 607 } 608 609 soc_cm_sfree(unit, range_p); 610 if (SOC_FAILURE(rv)) { 611 return rv; 612 } 613 } else { 614 for (i = 0; i < entries_per_set; i++) { 615 if (table->data_mask != NULL) { 616 /* Read original entry from hardware profile table */ 617 SOC_IF_ERROR_RETURN 618 (soc_mem_read(unit, table->mem, MEM_BLOCK_ANY, 619 index_min + base + i, entry)); 620 621 /* Replace partial entry with new content */ 622 for (j = 0; j < data_words; j++) { 623 entry[j] &= ~table->data_mask[j]; 624 entry[j] |= entry_p[j] & table->data_mask[j]; 625 } 626 627 } 628 629 /* Copy entry into the software cache. */ 630 sal_memcpy(cache_p, entry_p, data_words * sizeof(uint32)); 631 entry_p += entry_words; 632 cache_p += entry_words; 633 634 table->entries[base + i].ref_count++; 635 table->entries[base + i].entries_per_set = entries_per_set; 636 } 637 } 638 } 639 640 return SOC_E_NONE; 641 } 642 643 /* 644 * Function: 645 * soc_profile_mem_add_unique 646 * Purpose: 647 * Add a set of entries (one or more entries) to a profile table. This 648 * routine searches for a matching set in the profile table. If a matching 649 * set is found, the ref count for that entry is incremented and 650 * its base index is returned. If a matching set is not found and a free 651 * set is found, the HW table is updated, the ref count is incremented, 652 * and the base index of the set is returned. If no free set is found, an 653 * error is returned. 654 * 655 * This is for when memory is split and UNIQUE per pipe 656 * 657 * 658 * Parameters: 659 * unit - (IN) Unit 660 * profile - (IN) Pointer to profile memory structure 661 * entries_array - (IN) Array of pointer to table entries set 662 * entries_per_set0 - (IN) Number of entries in the set for table 0 663 * pipe - (IN) Pipe to affect 664 * index0 - (OUT) Base index to the entries in HW for table 0 665 * 666 * Returns: 667 * SOC_E_XXX 668 * 669 * Notes: 670 * For example 671 * Usually a profile structure is formed by single memory table. However if a 672 * profile structure is formed by the combination of 2 tables (table1 and 673 * table2 in this example). Each entry in table1 is 2 words long, and each 674 * entry in table2 is 3 words long. Argument entries_per_set is uniform on all 675 * tables (4 in this example). 676 * +------------------+ +--------------------------+ 677 * | entries_array[0] |---> | table1[0], 2 words long | 678 * +------------------+ +--------------------------+ 679 * | entries_array[1] |-+ | table1[1] | 680 * +------------------+ | +--------------------------+ 681 * | | table1[2] | 682 * | +--------------------------+ 683 * | | table1[3] | 684 * | +--------------------------+ 685 * | +---------------------------------+ 686 * +-> | table2[0], 3 words long | 687 * +---------------------------------+ 688 * | table2[1] | 689 * +---------------------------------+ 690 * | table2[2] | 691 * +---------------------------------+ 692 * | table2[3] | 693 * +---------------------------------+ 694 * 695 * The code for above example may look like: 696 * { 697 * void *entries[2]; 698 * table1_entry_t table1[4]; 699 * table2_entry_t table2[4]; 700 * int entries_per_set0; 701 * uint32 index[2]; 702 * 703 * fill table1[0], table1[1], table1[2], table1[3] 704 * fill table2[0], table2[1], table2[2], table2[3] 705 * entries[0] = &table1; 706 * entries[1] = &table2; 707 * entries_per_set0 = 4; 708 * soc_profile_mem_add_unique(unit, profile_mem, &entries, entries_per_set0, 709 * pipe, index); 710 * } 711 */ 712 int 713 soc_profile_mem_add_unique(int unit, 714 soc_profile_mem_t *profile, 715 void **entries_array, 716 int entries_per_set0, 717 int pipe, 718 uint32 *index0) 719 { 720 soc_profile_mem_table_t *table; 721 int index_min, num_entries, num_sets, entries_per_set; 722 int set, table_index, i, j, base, base0, free_set; 723 int entry_words, data_words; 724 int alloc_size, rv = SOC_E_NONE; 725 uint32 entry[SOC_MAX_MEM_WORDS]; 726 uint32 mask[SOC_MAX_MEM_WORDS]; 727 uint32 *cache_p, *entry_p, *mask_p, *range_p, *ent_p; 728 soc_mem_t mem = INVALIDm; 729 int mod, entries_per_pipe; 730 731 int set_start, set_end; 732 733 /* COVERITY: Intentional, stack use of 5192 bytes */ 734 /* coverity[stack_use_callee_max : FALSE] */ 735 /* coverity[stack_use_overflow : FALSE] */ 736 /* coverity[stack_use_return : FALSE] */ 737 738 if (profile == NULL || entries_array == NULL || entries_per_set0 <= 0 || 739 index0 == NULL) { 740 return SOC_E_PARAM; 741 } 742 743 if (profile->tables == NULL || profile->table_count == 0) { 744 return SOC_E_INIT; 745 } 746 747 table = &profile->tables[0]; 748 num_entries = table->index_max - table->index_min + 1; 749 750 if (NULL == SOC_MEM_UNIQUE_ACC(unit, table->mem)) { 751 return SOC_E_PARAM; 752 } 753 754 if (num_entries % entries_per_set0) { 755 return SOC_E_PARAM; 756 } 757 758 num_sets = num_entries / entries_per_set0; 759 760 for (table_index = 0; table_index < profile->table_count; table_index++) { 761 table = &profile->tables[table_index]; 762 num_entries = table->index_max - table->index_min + 1; 763 if (entries_array[table_index] == NULL) { 764 return SOC_E_PARAM; 765 } 766 767 if (num_entries % num_sets) { 768 return SOC_E_PARAM; 769 } 770 } 771 772 sal_memset(mask, 0xff, sizeof(mask)); 773 774 /* 775 * Search for an existing set that has the same configuration. 776 */ 777 778 /* Start searching at the entries at the start of the pipe. 779 * Example: If pipe 1 was passed in, start the search at the 780 * the pipe 1 section of the profile table, which follows 781 * the pipe 0 section of the profile table. 782 * 783 * UNIQUE MEM DUPLICATE MEM 784 * ----------- ---------- 785 * 0|PIPE0 MEM| 0|MEM | 786 * |PIPE1 MEM| | | 787 * |PIPE2 MEM| | | 788 * |... | |... | 789 * 159|PIPE7 MEM| 159| | 790 * ----------- ---------- 791 */ 792 entries_per_pipe = SOC_MEM_SIZE(unit, profile->tables[0].mem); 793 set_start = pipe * entries_per_pipe; 794 set_end = (pipe + 1) * entries_per_pipe; 795 796 free_set = -1; 797 for (set = set_start; set < set_end; set++) { 798 base0 = set * entries_per_set0; 799 800 /* Skip unused entries. */ 801 if (profile->tables[0].entries[base0].ref_count == 0) { 802 if (free_set != -1) { 803 continue; 804 } 805 806 /* Preserve location of free slot. */ 807 free_set = set; 808 if (profile->table_count == 1 && entries_per_set0 == 1) { 809 continue; 810 } 811 812 for (table_index = 0; table_index < profile->table_count; 813 table_index++) { 814 table = &profile->tables[table_index]; 815 num_entries = table->index_max - table->index_min + 1; 816 entries_per_set = num_entries / num_sets; 817 base = set * entries_per_set; 818 for (i = 0; i < entries_per_set; i++) { 819 if (table->entries[base + i].ref_count) { 820 free_set = -1; 821 break; 822 } 823 } 824 if (free_set == -1) { 825 break; 826 } 827 } 828 /* If non-shared, break out of main loop on first empty entry */ 829 if ((profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) && 830 free_set >= 0) { 831 break; 832 } 833 continue; 834 } 835 836 /* If non-shared, continue looking for empty entry */ 837 if (profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) { 838 continue; 839 } 840 841 /* Skip set of different size */ 842 if (profile->tables[0].entries[base0].entries_per_set != 843 entries_per_set0) { 844 continue; 845 } 846 847 /* Compare the new set of entries against the cache */ 848 for (table_index = 0; table_index < profile->table_count; 849 table_index++) { 850 table = &profile->tables[table_index]; 851 num_entries = table->index_max - table->index_min + 1; 852 entries_per_set = num_entries / num_sets; 853 base = set * entries_per_set; 854 entry_words = table->entry_words; 855 data_words = soc_mem_entry_words(unit, table->mem); 856 entry_p = entries_array[table_index]; 857 cache_p = &table->cache_p[base * entry_words]; 858 mask_p = table->data_mask == NULL ? mask : table->data_mask; 859 for (i = 0; i < entries_per_set; i++) { 860 for (j = 0; j < data_words; j++) { 861 if ((cache_p[j] ^ entry_p[j]) & mask_p[j]) { 862 break; 863 } 864 } 865 if (j < data_words) { 866 break; 867 } 868 entry_p += entry_words; 869 cache_p += entry_words; 870 } 871 if (i != entries_per_set) { 872 break; 873 } 874 } 875 if (table_index != profile->table_count) { 876 continue; 877 } 878 879 /* Do optional data integrity check */ 880 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 881 882 /* Matched set found */ 883 for (table_index = 0; table_index < profile->table_count; 884 table_index++) { 885 table = &profile->tables[table_index]; 886 num_entries = table->index_max - table->index_min + 1; 887 entries_per_set = num_entries / num_sets; 888 base = set * entries_per_set; 889 for (i = 0; i < entries_per_set; i++) { 890 table->entries[base + i].ref_count++; 891 } 892 } 893 894 /* Return the index based on the pipe, not on the profile table */ 895 *index0 = (base0%entries_per_pipe) + profile->tables[0].index_min; 896 897 return SOC_E_NONE; 898 } 899 900 if (free_set == -1) { 901 return SOC_E_RESOURCE; 902 } 903 904 for (table_index = 0; table_index < profile->table_count; table_index++) { 905 table = &profile->tables[table_index]; 906 index_min = table->index_min; 907 num_entries = table->index_max - table->index_min + 1; 908 entries_per_set = num_entries / num_sets; 909 base = free_set * entries_per_set; 910 entry_words = table->entry_words; 911 data_words = soc_mem_entry_words(unit, table->mem); 912 entry_p = entries_array[table_index]; 913 cache_p = &table->cache_p[base * entry_words]; 914 915 if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) { 916 alloc_size = WORDS2BYTES(entry_words) * entries_per_set; 917 range_p = soc_cm_salloc(unit, alloc_size, "profile update"); 918 if (NULL == range_p) { 919 return SOC_E_MEMORY; 920 } 921 922 sal_memset((void *)range_p, 0, alloc_size); 923 924 mem = table->mem; 925 entries_per_set = num_entries / num_sets; 926 base = free_set * entries_per_set; 927 928 /* Unique Memories in the profile memory table need to 929 * be written to hardware per pipe, while non 930 * unique memories do not */ 931 if (SOC_MEM_UNIQUE_ACC(unit, mem)) { 932 mem = SOC_MEM_UNIQUE_ACC(unit, mem)[pipe]; 933 mod = entries_per_pipe; 934 } else { 935 mod = 1; 936 } 937 938 if (table->data_mask != NULL) { 939 /* Read full entry from HW when profile only covers 940 * part of the table. */ 941 942 /* This reads from one pipe at a time */ 943 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 944 index_min + base%mod, 945 index_min + base%mod + entries_per_set - 1, 946 range_p); 947 } 948 949 if (SOC_SUCCESS(rv)) { 950 for (i = 0; i < entries_per_set; i++) { 951 ent_p = 952 soc_mem_table_idx_to_pointer(unit, mem, 953 uint32 *, range_p, i); 954 955 if (table->data_mask != NULL) { 956 /* Replace partial entry with new content */ 957 for (j = 0; j < data_words; j++) { 958 ent_p[j] &= ~table->data_mask[j]; 959 ent_p[j] |= entry_p[j] & table->data_mask[j]; 960 } 961 } else { 962 /* Write entire new entry */ 963 sal_memcpy(ent_p, entry_p, 964 data_words * sizeof(uint32)); 965 } 966 entry_p += entry_words; 967 } 968 } 969 970 if (SOC_SUCCESS(rv)) { 971 /* Write back the modified entries */ 972 /* This writes to one pipe at a time */ 973 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 974 index_min + base%mod, 975 index_min + base%mod + entries_per_set - 1, 976 range_p); 977 } 978 979 if (SOC_SUCCESS(rv)) { 980 /* Copy entry into the software cache. */ 981 entry_p = entries_array[table_index]; 982 983 /* Restore base for writing into contiguous mem */ 984 base = free_set * entries_per_set; 985 986 for (i = 0; i < entries_per_set; i++) { 987 sal_memcpy(cache_p, entry_p, 988 data_words * sizeof(uint32)); 989 entry_p += entry_words; 990 cache_p += entry_words; 991 992 table->entries[base + i].ref_count++; 993 table->entries[base + i].entries_per_set = 994 entries_per_set; 995 } 996 } 997 998 soc_cm_sfree(unit, range_p); 999 if (SOC_FAILURE(rv)) { 1000 return rv; 1001 } 1002 } else { 1003 for (i = 0; i < entries_per_set; i++) { 1004 mem = table->mem; 1005 base = free_set * entries_per_set; 1006 if (SOC_MEM_UNIQUE_ACC(unit, mem)) { 1007 mem = SOC_MEM_UNIQUE_ACC(unit, mem)[pipe]; 1008 mod = entries_per_pipe; 1009 } else { 1010 mod = 1; 1011 } 1012 if (table->data_mask != NULL) { 1013 /* Read original entry from hardware profile table */ 1014 SOC_IF_ERROR_RETURN 1015 (soc_mem_read(unit, mem, MEM_BLOCK_ANY, 1016 index_min + base%mod + i, entry)); 1017 1018 /* Replace partial entry with new content */ 1019 for (j = 0; j < data_words; j++) { 1020 entry[j] &= ~table->data_mask[j]; 1021 entry[j] |= entry_p[j] & table->data_mask[j]; 1022 } 1023 1024 /* Write modified entry into hardware profile table */ 1025 SOC_IF_ERROR_RETURN 1026 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, 1027 index_min + base%mod + i, entry)); 1028 } else { 1029 /* Write entire new entry into hardware profile table */ 1030 SOC_IF_ERROR_RETURN 1031 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, 1032 index_min + base%mod + i, entry_p)); 1033 } 1034 1035 /* Copy entry into the software cache. */ 1036 sal_memcpy(cache_p, entry_p, data_words * sizeof(uint32)); 1037 entry_p += entry_words; 1038 cache_p += entry_words; 1039 1040 table->entries[base + i].ref_count++; 1041 table->entries[base + i].entries_per_set = entries_per_set; 1042 } 1043 } 1044 } 1045 1046 /* Return the index based on the pipe, not on the profile table */ 1047 *index0 = (free_set%entries_per_pipe) * entries_per_set0 + profile->tables[0].index_min; 1048 1049 return SOC_E_NONE; 1050 } 1051 1052 /* 1053 * Function: 1054 * soc_profile_mem_add 1055 * Purpose: 1056 * Add a set of entries (one or more entries) to a profile table. This 1057 * routine searches for a matching set in the profile table. If a matching 1058 * set is found, the ref count for that entry is incremented and 1059 * its base index is returned. If a matching set is not found and a free 1060 * set is found, the HW table is updated, the ref count is incremented, 1061 * and the base index of the set is returned. If no free set is found, an 1062 * error is returned 1063 * 1064 * Parameters: 1065 * unit - (IN) Unit 1066 * profile - (IN) Pointer to profile memory structure 1067 * entries_array - (IN) Array of pointer to table entries set 1068 * entries_per_set0 - (IN) Number of entries in the set for table 0 1069 * index0 - (OUT) Base index to the entries in HW for table 0 1070 * 1071 * Returns: 1072 * SOC_E_XXX 1073 * 1074 * Notes: 1075 * For example 1076 * Usually a profile structure is formed by single memory table. However if a 1077 * profile structure is formed by the combination of 2 tables (table1 and 1078 * table2 in this example). Each entry in table1 is 2 words long, and each 1079 * entry in table2 is 3 words long. Argument entries_per_set is uniform on all 1080 * tables (4 in this example). 1081 * +------------------+ +--------------------------+ 1082 * | entries_array[0] |---> | table1[0], 2 words long | 1083 * +------------------+ +--------------------------+ 1084 * | entries_array[1] |-+ | table1[1] | 1085 * +------------------+ | +--------------------------+ 1086 * | | table1[2] | 1087 * | +--------------------------+ 1088 * | | table1[3] | 1089 * | +--------------------------+ 1090 * | +---------------------------------+ 1091 * +-> | table2[0], 3 words long | 1092 * +---------------------------------+ 1093 * | table2[1] | 1094 * +---------------------------------+ 1095 * | table2[2] | 1096 * +---------------------------------+ 1097 * | table2[3] | 1098 * +---------------------------------+ 1099 * 1100 * The code for above example may look like: 1101 * { 1102 * void *entries[2]; 1103 * table1_entry_t table1[4]; 1104 * table2_entry_t table2[4]; 1105 * int entries_per_set0; 1106 * uint32 index[2]; 1107 * 1108 * fill table1[0], table1[1], table1[2], table1[3] 1109 * fill table2[0], table2[1], table2[2], table2[3] 1110 * entries[0] = &table1; 1111 * entries[1] = &table2; 1112 * entries_per_set0 = 4; 1113 * soc_profile_mem_add(unit, profile_mem, &entries, entries_per_set0, 1114 * index); 1115 * } 1116 */ 1117 int 1118 soc_profile_mem_add(int unit, 1119 soc_profile_mem_t *profile, 1120 void **entries_array, 1121 int entries_per_set0, 1122 uint32 *index0) 1123 { 1124 soc_profile_mem_table_t *table; 1125 int index_min, num_entries, num_sets, entries_per_set; 1126 int set, table_index, i, j, base, base0, free_set; 1127 int entry_words, data_words; 1128 int alloc_size, rv = SOC_E_NONE; 1129 uint32 entry[SOC_MAX_MEM_WORDS]; 1130 uint32 mask[SOC_MAX_MEM_WORDS]; 1131 uint32 *cache_p, *entry_p, *mask_p, *range_p, *ent_p; 1132 1133 /* COVERITY: Intentional, stack use of 5192 bytes */ 1134 /* coverity[stack_use_callee_max : FALSE] */ 1135 /* coverity[stack_use_overflow : FALSE] */ 1136 /* coverity[stack_use_return : FALSE] */ 1137 1138 if (profile == NULL || entries_array == NULL || entries_per_set0 <= 0 || 1139 index0 == NULL) { 1140 return SOC_E_PARAM; 1141 } 1142 1143 if (profile->tables == NULL || profile->table_count == 0) { 1144 return SOC_E_INIT; 1145 } 1146 1147 table = &profile->tables[0]; 1148 num_entries = table->index_max - table->index_min + 1; 1149 1150 if (num_entries % entries_per_set0) { 1151 return SOC_E_PARAM; 1152 } 1153 1154 num_sets = num_entries / entries_per_set0; 1155 1156 for (table_index = 0; table_index < profile->table_count; table_index++) { 1157 table = &profile->tables[table_index]; 1158 num_entries = table->index_max - table->index_min + 1; 1159 if (entries_array[table_index] == NULL) { 1160 return SOC_E_PARAM; 1161 } 1162 1163 if (num_entries % num_sets) { 1164 return SOC_E_PARAM; 1165 } 1166 } 1167 1168 sal_memset(mask, 0xff, sizeof(mask)); 1169 1170 /* 1171 * Search for an existing set that has the same configuration. 1172 */ 1173 free_set = -1; 1174 for (set = 0; set < num_sets; set++) { 1175 base0 = set * entries_per_set0; 1176 1177 /* Skip unused entries. */ 1178 if (profile->tables[0].entries[base0].ref_count == 0) { 1179 if (free_set != -1) { 1180 continue; 1181 } 1182 1183 /* Preserve location of free slot. */ 1184 free_set = set; 1185 if (profile->table_count == 1 && entries_per_set0 == 1) { 1186 continue; 1187 } 1188 1189 for (table_index = 0; table_index < profile->table_count; 1190 table_index++) { 1191 table = &profile->tables[table_index]; 1192 num_entries = table->index_max - table->index_min + 1; 1193 entries_per_set = num_entries / num_sets; 1194 base = set * entries_per_set; 1195 for (i = 0; i < entries_per_set; i++) { 1196 if (table->entries[base + i].ref_count) { 1197 free_set = -1; 1198 break; 1199 } 1200 } 1201 if (free_set == -1) { 1202 break; 1203 } 1204 } 1205 /* If non-shared, break out of main loop on first empty entry */ 1206 if ((profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) && 1207 free_set >= 0) { 1208 break; 1209 } 1210 continue; 1211 } 1212 1213 /* If non-shared, continue looking for empty entry */ 1214 if (profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) { 1215 continue; 1216 } 1217 1218 /* Skip set of different size */ 1219 if (profile->tables[0].entries[base0].entries_per_set != 1220 entries_per_set0) { 1221 continue; 1222 } 1223 1224 /* Compare the new set of entries against the cache */ 1225 for (table_index = 0; table_index < profile->table_count; 1226 table_index++) { 1227 table = &profile->tables[table_index]; 1228 num_entries = table->index_max - table->index_min + 1; 1229 entries_per_set = num_entries / num_sets; 1230 base = set * entries_per_set; 1231 entry_words = table->entry_words; 1232 data_words = soc_mem_entry_words(unit, table->mem); 1233 entry_p = entries_array[table_index]; 1234 cache_p = &table->cache_p[base * entry_words]; 1235 mask_p = table->data_mask == NULL ? mask : table->data_mask; 1236 for (i = 0; i < entries_per_set; i++) { 1237 for (j = 0; j < data_words; j++) { 1238 if ((cache_p[j] ^ entry_p[j]) & mask_p[j]) { 1239 break; 1240 } 1241 } 1242 if (j < data_words) { 1243 break; 1244 } 1245 entry_p += entry_words; 1246 cache_p += entry_words; 1247 } 1248 if (i != entries_per_set) { 1249 break; 1250 } 1251 } 1252 if (table_index != profile->table_count) { 1253 continue; 1254 } 1255 1256 /* Do optional data integrity check */ 1257 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 1258 1259 /* Matched set found */ 1260 for (table_index = 0; table_index < profile->table_count; 1261 table_index++) { 1262 table = &profile->tables[table_index]; 1263 num_entries = table->index_max - table->index_min + 1; 1264 entries_per_set = num_entries / num_sets; 1265 base = set * entries_per_set; 1266 for (i = 0; i < entries_per_set; i++) { 1267 table->entries[base + i].ref_count++; 1268 } 1269 } 1270 *index0 = base0 + profile->tables[0].index_min; 1271 1272 return SOC_E_NONE; 1273 } 1274 1275 if (free_set == -1) { 1276 return SOC_E_RESOURCE; 1277 } 1278 1279 for (table_index = 0; table_index < profile->table_count; table_index++) { 1280 table = &profile->tables[table_index]; 1281 index_min = table->index_min; 1282 num_entries = table->index_max - table->index_min + 1; 1283 entries_per_set = num_entries / num_sets; 1284 base = free_set * entries_per_set; 1285 entry_words = table->entry_words; 1286 data_words = soc_mem_entry_words(unit, table->mem); 1287 entry_p = entries_array[table_index]; 1288 cache_p = &table->cache_p[base * entry_words]; 1289 1290 if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) { 1291 alloc_size = WORDS2BYTES(entry_words) * entries_per_set; 1292 range_p = soc_cm_salloc(unit, alloc_size, "profile update"); 1293 if (NULL == range_p) { 1294 return SOC_E_MEMORY; 1295 } 1296 sal_memset((void *)range_p, 0, alloc_size); 1297 1298 if (table->data_mask != NULL) { 1299 /* Read full entry from HW when profile only covers 1300 * part of the table. */ 1301 rv = soc_mem_read_range(unit, table->mem, MEM_BLOCK_ANY, 1302 index_min + base, 1303 index_min + base + entries_per_set - 1, 1304 range_p); 1305 } 1306 1307 if (SOC_SUCCESS(rv)) { 1308 for (i = 0; i < entries_per_set; i++) { 1309 ent_p = 1310 soc_mem_table_idx_to_pointer(unit, table->mem, 1311 uint32 *, range_p, i); 1312 1313 if (table->data_mask != NULL) { 1314 /* Replace partial entry with new content */ 1315 for (j = 0; j < data_words; j++) { 1316 ent_p[j] &= ~table->data_mask[j]; 1317 ent_p[j] |= entry_p[j] & table->data_mask[j]; 1318 } 1319 } else { 1320 /* Write entire new entry */ 1321 sal_memcpy(ent_p, entry_p, 1322 data_words * sizeof(uint32)); 1323 } 1324 entry_p += entry_words; 1325 } 1326 } 1327 1328 if (SOC_SUCCESS(rv)) { 1329 /* Write back the modified entries */ 1330 rv = soc_mem_write_range(unit, table->mem, MEM_BLOCK_ALL, 1331 index_min + base, 1332 index_min + base + entries_per_set - 1, 1333 range_p); 1334 } 1335 1336 if (SOC_SUCCESS(rv)) { 1337 /* Copy entry into the software cache. */ 1338 entry_p = entries_array[table_index]; 1339 1340 for (i = 0; i < entries_per_set; i++) { 1341 sal_memcpy(cache_p, entry_p, 1342 data_words * sizeof(uint32)); 1343 entry_p += entry_words; 1344 cache_p += entry_words; 1345 1346 table->entries[base + i].ref_count++; 1347 table->entries[base + i].entries_per_set = 1348 entries_per_set; 1349 } 1350 } 1351 1352 soc_cm_sfree(unit, range_p); 1353 if (SOC_FAILURE(rv)) { 1354 return rv; 1355 } 1356 } else { 1357 for (i = 0; i < entries_per_set; i++) { 1358 if (table->data_mask != NULL) { 1359 /* Read original entry from hardware profile table */ 1360 SOC_IF_ERROR_RETURN 1361 (soc_mem_read(unit, table->mem, MEM_BLOCK_ANY, 1362 index_min + base + i, entry)); 1363 1364 /* Replace partial entry with new content */ 1365 for (j = 0; j < data_words; j++) { 1366 entry[j] &= ~table->data_mask[j]; 1367 entry[j] |= entry_p[j] & table->data_mask[j]; 1368 } 1369 1370 /* Write modified entry into hardware profile table */ 1371 SOC_IF_ERROR_RETURN 1372 (soc_mem_write(unit, table->mem, MEM_BLOCK_ALL, 1373 index_min + base + i, entry)); 1374 } else { 1375 /* Write entire new entry into hardware profile table */ 1376 SOC_IF_ERROR_RETURN 1377 (soc_mem_write(unit, table->mem, MEM_BLOCK_ALL, 1378 index_min + base + i, entry_p)); 1379 } 1380 1381 /* Copy entry into the software cache. */ 1382 sal_memcpy(cache_p, entry_p, data_words * sizeof(uint32)); 1383 entry_p += entry_words; 1384 cache_p += entry_words; 1385 1386 table->entries[base + i].ref_count++; 1387 table->entries[base + i].entries_per_set = entries_per_set; 1388 } 1389 } 1390 } 1391 *index0 = free_set * entries_per_set0 + profile->tables[0].index_min; 1392 1393 return SOC_E_NONE; 1394 } 1395 1396 int 1397 soc_profile_mem_search (int unit, 1398 soc_profile_mem_t *profile, 1399 void ** entries_array, 1400 int entries_per_set0, 1401 uint32 *index0) 1402 { 1403 soc_profile_mem_table_t *table; 1404 int num_entries, num_sets, entries_per_set; 1405 int set, table_index, i, j, base, base0; 1406 int entry_words, data_words; 1407 int rv = SOC_E_NONE; 1408 uint32 mask[SOC_MAX_MEM_WORDS]; 1409 uint32 *cache_p, *entry_p, *mask_p; 1410 1411 if (profile == NULL || entries_array == NULL || entries_per_set0 <= 0 || 1412 index0 == NULL) { 1413 return SOC_E_PARAM; 1414 } 1415 1416 if (profile->tables == NULL || profile->table_count == 0) { 1417 return SOC_E_INIT; 1418 } 1419 1420 sal_memset(mask, 0xff, sizeof(mask)); 1421 table = &profile->tables[0]; 1422 num_entries = table->index_max - table->index_min + 1; 1423 1424 if (num_entries % entries_per_set0) { 1425 return SOC_E_PARAM; 1426 } 1427 1428 num_sets = num_entries / entries_per_set0; 1429 for (set = 0; set < num_sets; set++) { 1430 base0 = set * entries_per_set0; 1431 1432 if (profile->tables[0].entries[base0].ref_count == 0) { 1433 continue; 1434 } 1435 for (table_index = 0; table_index < profile->table_count; 1436 table_index++) { 1437 table = &profile->tables[table_index]; 1438 num_entries = table->index_max - table->index_min + 1; 1439 entries_per_set = num_entries / num_sets; 1440 base = set * entries_per_set; 1441 entry_words = table->entry_words; 1442 data_words = soc_mem_entry_words(unit, table->mem); 1443 entry_p = entries_array[table_index]; 1444 cache_p = &table->cache_p[base * entry_words]; 1445 mask_p = table->data_mask == NULL ? mask : table->data_mask; 1446 for (i = 0; i < entries_per_set; i++) { 1447 for (j = 0; j < data_words; j++) { 1448 if ((cache_p[j] ^ entry_p[j]) & mask_p[j]) { 1449 break; 1450 } 1451 } 1452 if (j < data_words) { 1453 break; 1454 } 1455 entry_p += entry_words; 1456 cache_p += entry_words; 1457 } 1458 if (i != entries_per_set) { 1459 break; 1460 } 1461 1462 } 1463 if (table_index != profile->table_count) { 1464 continue; 1465 } 1466 1467 *index0 = (base0 + profile->tables[0].index_min)/entries_per_set0; 1468 return SOC_E_EXISTS; 1469 } 1470 return rv; 1471 } 1472 1473 int 1474 soc_profile_mem_single_table_add(int unit, 1475 soc_profile_mem_t *profile, 1476 void *entries, 1477 int entries_per_set, 1478 int *index) 1479 { 1480 void *entries_array[1]; 1481 1482 entries_array[0] = entries; 1483 return soc_profile_mem_add(unit, profile, entries_array, 1484 entries_per_set, (uint32 *)index); 1485 } 1486 1487 /* 1488 * Function: 1489 * soc_profile_mem_delete_unique 1490 * Purpose: 1491 * Delete the reference to the set of entries (one or more entries) at 1492 * the specified base index of the specified pipe 1493 * 1494 * This is for when memory is split and UNIQUE per pipe 1495 * 1496 * Parameters: 1497 * unit - (IN) Unit 1498 * profile - (IN) Pointer to profile memory structure 1499 * index0 - (IN) Base index to the entries in HW for table 0 1500 * pipe - (IN) Pipe to affect 1501 * Returns: 1502 * SOC_E_XXX 1503 */ 1504 int 1505 soc_profile_mem_delete_unique(int unit, 1506 soc_profile_mem_t *profile, 1507 uint32 index0, int pipe) 1508 { 1509 soc_profile_mem_table_t *table; 1510 int index_min, num_entries, num_sets, entries_per_set; 1511 int set, table_index, i, j, base, base0; 1512 int alloc_size, rv = SOC_E_NONE; 1513 int entry_words, data_words; 1514 uint32 *range_p, *ent_p; 1515 void *null_entry; 1516 soc_mem_t mem = INVALIDm; 1517 int mod, entries_per_pipe; 1518 1519 if (profile == NULL) { 1520 return SOC_E_PARAM; 1521 } 1522 1523 if (profile->tables == NULL || profile->table_count == 0) { 1524 return SOC_E_INIT; 1525 } 1526 1527 table = &profile->tables[0]; 1528 num_entries = table->index_max - table->index_min + 1; 1529 if (index0 < table->index_min || index0 > table->index_max) { 1530 return SOC_E_PARAM; 1531 } 1532 1533 if (NULL == SOC_MEM_UNIQUE_ACC(unit, table->mem)) { 1534 return SOC_E_PARAM; 1535 } 1536 1537 entries_per_pipe = SOC_MEM_SIZE(unit, table->mem); 1538 1539 base0 = index0 - table->index_min; 1540 /* Offset the base to the appropriate pipe */ 1541 base0 += pipe*entries_per_pipe; 1542 1543 if (table->entries[base0].ref_count == 0) { 1544 return SOC_E_NOT_FOUND; 1545 } 1546 1547 entries_per_set = table->entries[base0].entries_per_set; 1548 1549 if (base0 % entries_per_set) { 1550 return SOC_E_PARAM; 1551 } 1552 1553 num_sets = num_entries / entries_per_set; 1554 set = base0 / entries_per_set; 1555 1556 /* Do optional data integrity check */ 1557 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 1558 1559 for (table_index = 0; table_index < profile->table_count; table_index++) { 1560 table = &profile->tables[table_index]; 1561 num_entries = table->index_max - table->index_min + 1; 1562 entries_per_set = num_entries / num_sets; 1563 base = set * entries_per_set; 1564 for (i = 0; i < entries_per_set; i++) { 1565 table->entries[base + i].ref_count--; 1566 } 1567 } 1568 1569 if (profile->tables[0].entries[base0].ref_count != 0) { 1570 return SOC_E_NONE; 1571 } 1572 1573 for (table_index = 0; table_index < profile->table_count; table_index++) { 1574 table = &profile->tables[table_index]; 1575 index_min = table->index_min; 1576 num_entries = table->index_max - table->index_min + 1; 1577 entries_per_set = num_entries / num_sets; 1578 base = set * entries_per_set; 1579 1580 if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) { 1581 entry_words = table->entry_words; 1582 alloc_size = WORDS2BYTES(entry_words) * entries_per_set; 1583 range_p = soc_cm_salloc(unit, alloc_size, "profile update"); 1584 if (NULL == range_p) { 1585 return SOC_E_MEMORY; 1586 } 1587 1588 sal_memset((void *)range_p, 0, alloc_size); 1589 mem = table->mem; 1590 entries_per_set = num_entries / num_sets; 1591 base = set * entries_per_set; 1592 1593 /* If the memory is unique, need to write to its proper index 1594 * by removing the pipe offset */ 1595 if (SOC_MEM_UNIQUE_ACC(unit, mem)) { 1596 mem = SOC_MEM_UNIQUE_ACC(unit, mem)[pipe]; 1597 mod = entries_per_pipe; 1598 } else { 1599 mod = 1; 1600 } 1601 1602 if (table->data_mask != NULL) { 1603 /* Read full entry from HW when profile only covers 1604 * part of the table. */ 1605 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 1606 index_min + base%mod, 1607 index_min + base%mod + entries_per_set - 1, 1608 range_p); 1609 } 1610 1611 if (SOC_SUCCESS(rv)) { 1612 null_entry = soc_mem_entry_null(unit, mem); 1613 data_words = soc_mem_entry_words(unit, mem); 1614 for (i = 0; i < entries_per_set; i++) { 1615 ent_p = 1616 soc_mem_table_idx_to_pointer(unit, mem, 1617 uint32 *, range_p, i); 1618 1619 if (table->data_mask != NULL) { 1620 /* Clear partial entry */ 1621 for (j = 0; j < data_words; j++) { 1622 ent_p[j] &= ~table->data_mask[j]; 1623 } 1624 } else { 1625 /* Write entire new entry */ 1626 sal_memcpy(ent_p, null_entry, 1627 data_words * sizeof(uint32)); 1628 } 1629 } 1630 } 1631 1632 if (SOC_SUCCESS(rv)) { 1633 /* Write back the modified entries */ 1634 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY, 1635 index_min + base%mod, 1636 index_min + base%mod + entries_per_set - 1, 1637 range_p); 1638 } 1639 1640 soc_cm_sfree(unit, range_p); 1641 if (SOC_FAILURE(rv)) { 1642 return rv; 1643 } 1644 } else { 1645 1646 mem = table->mem; 1647 if (SOC_MEM_UNIQUE_ACC(unit, mem)) { 1648 mem = SOC_MEM_UNIQUE_ACC(unit, mem)[pipe]; 1649 mod = entries_per_pipe; 1650 } else { 1651 mod = 1; 1652 } 1653 1654 for (i = 0; i < entries_per_set; i++) { 1655 /* Insert the new entries into profile table */ 1656 SOC_IF_ERROR_RETURN 1657 (soc_mem_write(unit, table->mem, MEM_BLOCK_ANY, 1658 index_min + base%mod + i, 1659 soc_mem_entry_null(unit, table->mem))); 1660 } 1661 } 1662 } 1663 1664 return SOC_E_NONE; 1665 } 1666 /* 1667 * Function: 1668 * soc_profile_mem_delete 1669 * Purpose: 1670 * Delete the reference to the set of entries (one or more entries) at 1671 * the specified base index. 1672 * 1673 * Parameters: 1674 * unit - (IN) Unit 1675 * profile - (IN) Pointer to profile memory structure 1676 * index0 - (IN) Base index to the entries in HW for table 0 1677 * Returns: 1678 * SOC_E_XXX 1679 */ 1680 int 1681 soc_profile_mem_delete(int unit, 1682 soc_profile_mem_t *profile, 1683 uint32 index0) 1684 { 1685 soc_profile_mem_table_t *table; 1686 int index_min, num_entries, num_sets, entries_per_set; 1687 int set, table_index, i, j, base, base0; 1688 int alloc_size, rv = SOC_E_NONE; 1689 int entry_words, data_words; 1690 uint32 *range_p, *ent_p; 1691 void *null_entry; 1692 1693 if (profile == NULL) { 1694 return SOC_E_PARAM; 1695 } 1696 1697 if (profile->tables == NULL || profile->table_count == 0) { 1698 return SOC_E_INIT; 1699 } 1700 1701 table = &profile->tables[0]; 1702 num_entries = table->index_max - table->index_min + 1; 1703 if (index0 < table->index_min || index0 > table->index_max) { 1704 return SOC_E_PARAM; 1705 } 1706 1707 base0 = index0 - table->index_min; 1708 1709 if (table->entries[base0].ref_count == 0) { 1710 return SOC_E_NOT_FOUND; 1711 } 1712 1713 entries_per_set = table->entries[base0].entries_per_set; 1714 1715 if (base0 % entries_per_set) { 1716 return SOC_E_PARAM; 1717 } 1718 1719 num_sets = num_entries / entries_per_set; 1720 set = base0 / entries_per_set; 1721 1722 /* Do optional data integrity check */ 1723 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 1724 1725 for (table_index = 0; table_index < profile->table_count; table_index++) { 1726 table = &profile->tables[table_index]; 1727 num_entries = table->index_max - table->index_min + 1; 1728 entries_per_set = num_entries / num_sets; 1729 base = set * entries_per_set; 1730 for (i = 0; i < entries_per_set; i++) { 1731 table->entries[base + i].ref_count--; 1732 } 1733 } 1734 1735 if (profile->tables[0].entries[base0].ref_count != 0) { 1736 return SOC_E_NONE; 1737 } 1738 1739 for (table_index = 0; table_index < profile->table_count; table_index++) { 1740 table = &profile->tables[table_index]; 1741 index_min = table->index_min; 1742 num_entries = table->index_max - table->index_min + 1; 1743 entries_per_set = num_entries / num_sets; 1744 base = set * entries_per_set; 1745 1746 if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) { 1747 entry_words = table->entry_words; 1748 alloc_size = WORDS2BYTES(entry_words) * entries_per_set; 1749 range_p = soc_cm_salloc(unit, alloc_size, "profile update"); 1750 if (NULL == range_p) { 1751 return SOC_E_MEMORY; 1752 } 1753 sal_memset((void *)range_p, 0, alloc_size); 1754 1755 if (table->data_mask != NULL) { 1756 /* Read full entry from HW when profile only covers 1757 * part of the table. */ 1758 rv = soc_mem_read_range(unit, table->mem, MEM_BLOCK_ANY, 1759 index_min + base, 1760 index_min + base + entries_per_set - 1, 1761 range_p); 1762 } 1763 1764 if (SOC_SUCCESS(rv)) { 1765 null_entry = soc_mem_entry_null(unit, table->mem); 1766 data_words = soc_mem_entry_words(unit, table->mem); 1767 for (i = 0; i < entries_per_set; i++) { 1768 ent_p = 1769 soc_mem_table_idx_to_pointer(unit, table->mem, 1770 uint32 *, range_p, i); 1771 1772 if (table->data_mask != NULL) { 1773 /* Clear partial entry */ 1774 for (j = 0; j < data_words; j++) { 1775 ent_p[j] &= ~table->data_mask[j]; 1776 } 1777 } else { 1778 /* Write entire new entry */ 1779 sal_memcpy(ent_p, null_entry, 1780 data_words * sizeof(uint32)); 1781 } 1782 } 1783 } 1784 1785 if (SOC_SUCCESS(rv)) { 1786 /* Write back the modified entries */ 1787 rv = soc_mem_write_range(unit, table->mem, MEM_BLOCK_ANY, 1788 index_min + base, 1789 index_min + base + entries_per_set - 1, 1790 range_p); 1791 } 1792 1793 soc_cm_sfree(unit, range_p); 1794 if (SOC_FAILURE(rv)) { 1795 return rv; 1796 } 1797 } else { 1798 1799 for (i = 0; i < entries_per_set; i++) { 1800 /* Insert the new entries into profile table */ 1801 SOC_IF_ERROR_RETURN 1802 (soc_mem_write(unit, table->mem, MEM_BLOCK_ANY, 1803 index_min + base + i, 1804 soc_mem_entry_null(unit, table->mem))); 1805 } 1806 } 1807 } 1808 1809 return SOC_E_NONE; 1810 } 1811 1812 /* 1813 * Function: 1814 * soc_profile_mem_set 1815 * Purpose: 1816 * Update existing non-shared entry. 1817 * 1818 * Parameters: 1819 * unit - (IN) Unit 1820 * profile - (IN) Pointer to profile memory structure 1821 * entries_array - (IN) Array of pointer to table entries set 1822 * index0 - (IN) Base index to update 1823 * Returns: 1824 * SOC_E_XXX 1825 */ 1826 int 1827 soc_profile_mem_set(int unit, 1828 soc_profile_mem_t *profile, 1829 void **entries_array, 1830 uint32 index0) 1831 { 1832 soc_profile_mem_table_t *table; 1833 int index_min, num_entries, num_sets, entries_per_set; 1834 int set, table_index, i, base, base0; 1835 int entry_words, data_words; 1836 int alloc_size, rv = SOC_E_NONE; 1837 uint32 *cache_p, *entry_p, *range_p, *ent_p; 1838 1839 if (profile == NULL) { 1840 return SOC_E_PARAM; 1841 } 1842 1843 if (profile->tables == NULL || profile->table_count == 0) { 1844 return SOC_E_INIT; 1845 } 1846 1847 table = &profile->tables[0]; 1848 num_entries = table->index_max - table->index_min + 1; 1849 if (index0 < table->index_min || index0 > table->index_max) { 1850 return SOC_E_PARAM; 1851 } 1852 1853 base0 = index0 - table->index_min; 1854 1855 if (table->entries[base0].ref_count == 0) { 1856 return SOC_E_NOT_FOUND; 1857 } 1858 1859 entries_per_set = table->entries[base0].entries_per_set; 1860 1861 if (base0 % entries_per_set) { 1862 return SOC_E_PARAM; 1863 } 1864 1865 num_sets = num_entries / entries_per_set; 1866 set = base0 / entries_per_set; 1867 1868 /* Do optional data integrity check */ 1869 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 1870 1871 for (table_index = 0; table_index < profile->table_count; table_index++) { 1872 table = &profile->tables[table_index]; 1873 index_min = table->index_min; 1874 num_entries = table->index_max - table->index_min + 1; 1875 entries_per_set = num_entries / num_sets; 1876 base = set * entries_per_set; 1877 entry_words = table->entry_words; 1878 data_words = soc_mem_entry_words(unit, table->mem); 1879 entry_p = entries_array[table_index]; 1880 cache_p = &table->cache_p[base * entry_words]; 1881 1882 if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) { 1883 alloc_size = WORDS2BYTES(entry_words) * entries_per_set; 1884 range_p = soc_cm_salloc(unit, alloc_size, "profile update"); 1885 1886 1887 1888 if (NULL == range_p) { 1889 return SOC_E_MEMORY; 1890 } 1891 sal_memset((void *)range_p, 0, alloc_size); 1892 1893 if (SOC_SUCCESS(rv)) { 1894 for (i = 0; i < entries_per_set; i++) { 1895 ent_p = 1896 soc_mem_table_idx_to_pointer(unit, table->mem, 1897 uint32 *, range_p, i); 1898 /* Write entire new entry */ 1899 sal_memcpy(ent_p, entry_p, 1900 data_words * sizeof(uint32)); 1901 entry_p += entry_words; 1902 } 1903 } 1904 1905 if (SOC_SUCCESS(rv)) { 1906 /* Write back the modified entries */ 1907 rv = soc_mem_write_range(unit, table->mem, MEM_BLOCK_ANY, 1908 index_min + base, 1909 index_min + base + entries_per_set - 1, 1910 range_p); 1911 1912 if (SOC_SUCCESS(rv)) { 1913 /* Copy entry into the software cache. */ 1914 entry_p = entries_array[table_index]; 1915 1916 for (i = 0; i < entries_per_set; i++) { 1917 sal_memcpy(cache_p, entry_p, 1918 data_words * sizeof(uint32)); 1919 entry_p += entry_words; 1920 cache_p += entry_words; 1921 1922 table->entries[base + i].ref_count++; 1923 table->entries[base + i].entries_per_set = 1924 entries_per_set; 1925 } 1926 } 1927 } 1928 1929 soc_cm_sfree(unit, range_p); 1930 if (SOC_FAILURE(rv)) { 1931 return rv; 1932 } 1933 } else { 1934 for (i = 0; i < entries_per_set; i++) { 1935 /* Write the new entries into profile table */ 1936 SOC_IF_ERROR_RETURN(soc_mem_write(unit, table->mem, MEM_BLOCK_ANY, 1937 index_min + base + i, entry_p)); 1938 1939 /* Copy entry into the software cache. */ 1940 sal_memcpy(cache_p, entry_p, data_words * sizeof(uint32)); 1941 entry_p += entry_words; 1942 cache_p += entry_words; 1943 1944 } 1945 } 1946 } 1947 1948 return SOC_E_NONE; 1949 } 1950 1951 int 1952 soc_profile_mem_index_get(int unit, 1953 soc_profile_mem_t *profile, 1954 soc_mem_t mem, 1955 int *index) 1956 { 1957 int i; 1958 soc_profile_mem_table_t *table; 1959 if (profile == NULL) { 1960 return SOC_E_PARAM; 1961 } 1962 if (profile->tables == NULL || profile->table_count == 0) { 1963 return SOC_E_INIT; 1964 } 1965 1966 for (i = 0; i < profile->table_count; i++) { 1967 table = &profile->tables[i]; 1968 if (table->mem == mem) { 1969 *index = i; 1970 return SOC_E_NONE; 1971 } 1972 } 1973 1974 return SOC_E_NOT_FOUND; 1975 } 1976 1977 /* 1978 * Function: 1979 * soc_profile_mem_get 1980 * Purpose: 1981 * Get a set of entries (one or more entries) at the specified index. 1982 * 1983 * Parameters: 1984 * unit - (IN) Unit 1985 * profile - (IN) Pointer to profile memory structure 1986 * index0 - (IN) Base index to the entries in HW for table 0 1987 * count - (IN) Array of number of entries to retrieve 1988 * entries_array - (OUT) Array of pointer to table entries set 1989 * Returns: 1990 * SOC_E_XXX 1991 */ 1992 int 1993 soc_profile_mem_get(int unit, 1994 soc_profile_mem_t *profile, 1995 int index0, 1996 int count, 1997 void **entries_array) 1998 { 1999 soc_profile_mem_table_t *table; 2000 int num_entries, num_sets, entries_per_set; 2001 int set, table_index, i, j, base, base0; 2002 int entry_words, data_words; 2003 uint32 *cache_p, *entry_p; 2004 2005 if (profile == NULL || count <= 0) { 2006 return SOC_E_PARAM; 2007 } 2008 2009 if (profile->tables == NULL || profile->table_count == 0) { 2010 return SOC_E_INIT; 2011 } 2012 2013 table = &profile->tables[0]; 2014 num_entries = table->index_max - table->index_min + 1; 2015 if (index0 < table->index_min || index0 > table->index_max) { 2016 return SOC_E_PARAM; 2017 } 2018 2019 base0 = index0 - table->index_min; 2020 2021 if (table->entries[base0].ref_count == 0) { 2022 return SOC_E_NOT_FOUND; 2023 } 2024 2025 entries_per_set = table->entries[base0].entries_per_set; 2026 2027 if (base0 % entries_per_set) { 2028 return SOC_E_PARAM; 2029 } 2030 2031 num_sets = num_entries / entries_per_set; 2032 set = base0 / entries_per_set; 2033 2034 /* Do optional data integrity check */ 2035 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 2036 2037 for (table_index = 0; table_index < profile->table_count; table_index++) { 2038 table = &profile->tables[table_index]; 2039 num_entries = table->index_max - table->index_min + 1; 2040 entries_per_set = num_entries / num_sets; 2041 base = set * entries_per_set; 2042 entry_words = table->entry_words; 2043 data_words = soc_mem_entry_words(unit, table->mem); 2044 entry_p = entries_array[table_index]; 2045 cache_p = &table->cache_p[base * entry_words]; 2046 2047 for (i = 0; i < entries_per_set; i++) { 2048 if (i >= count) { 2049 break; 2050 } 2051 /* Copy entry from the software cache. (include pad) */ 2052 if (table->data_mask != NULL) { 2053 for (j = 0; j < data_words; j++) { 2054 entry_p[j] = cache_p[j] & table->data_mask[j]; 2055 } 2056 } else { 2057 sal_memcpy(entry_p, cache_p, entry_words * sizeof(uint32)); 2058 } 2059 entry_p += entry_words; 2060 cache_p += entry_words; 2061 } 2062 } 2063 2064 return SOC_E_NONE; 2065 } 2066 2067 int 2068 soc_profile_mem_single_table_get(int unit, 2069 soc_profile_mem_t *profile, 2070 int index, 2071 int count, 2072 void *entries) 2073 { 2074 void *entries_array[1]; 2075 2076 entries_array[0] = entries; 2077 return soc_profile_mem_get(unit, profile, index, count, entries_array); 2078 } 2079 2080 /* 2081 * Function: 2082 * soc_profile_mem_reference_unique 2083 * Purpose: 2084 * Add the reference to the set of entries (one or more entries) at 2085 * the specified base index. 2086 * 2087 * Parameters: 2088 * unit - (IN) Unit 2089 * profile - (IN) Pointer to profile memory structure 2090 * index0 - (IN) Base index to the entries in HW for table 0 2091 * entries_per_set0 - (IN) Number of entries in the set for table 0 2092 * (for WARM BOOT only) 2093 * pipe - (IN) Pipe to affect 2094 * Returns: 2095 * SOC_E_XXX 2096 */ 2097 int 2098 soc_profile_mem_reference_unique(int unit, 2099 soc_profile_mem_t *profile, 2100 int index0, 2101 int entries_per_set0, 2102 int pipe) 2103 { 2104 soc_profile_mem_table_t *table; 2105 int num_entries, num_sets, entries_per_set; 2106 int set, table_index, i, base, base0, entries_per_pipe; 2107 2108 if (profile == NULL) { 2109 return SOC_E_PARAM; 2110 } 2111 2112 if (SOC_WARM_BOOT(unit)) { 2113 if (entries_per_set0 <= 0) { 2114 return SOC_E_PARAM; 2115 } 2116 } 2117 2118 if (profile->tables == NULL || profile->table_count == 0) { 2119 return SOC_E_INIT; 2120 } 2121 2122 table = &profile->tables[0]; 2123 num_entries = table->index_max - table->index_min + 1; 2124 if (index0 < table->index_min || index0 > table->index_max) { 2125 return SOC_E_PARAM; 2126 } 2127 2128 if (NULL == SOC_MEM_UNIQUE_ACC(unit, table->mem)) { 2129 return SOC_E_PARAM; 2130 } 2131 2132 entries_per_pipe = SOC_MEM_SIZE(unit, table->mem); 2133 2134 base0 = index0 - table->index_min; 2135 /* Offset the base to the appropriate pipe */ 2136 base0 += pipe*entries_per_pipe; 2137 2138 if (SOC_WARM_BOOT(unit)) { 2139 if (num_entries % entries_per_set0) { 2140 return SOC_E_PARAM; 2141 } 2142 entries_per_set = entries_per_set0; 2143 } else { 2144 if (table->entries[base0].ref_count == 0) { 2145 return SOC_E_NOT_FOUND; 2146 } 2147 2148 entries_per_set = table->entries[base0].entries_per_set; 2149 } 2150 2151 if (base0 % entries_per_set) { 2152 return SOC_E_PARAM; 2153 } 2154 2155 num_sets = num_entries / entries_per_set; 2156 set = base0 / entries_per_set; 2157 2158 #if 0 2159 /* Do optional data integrity check */ 2160 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 2161 #endif 2162 2163 for (table_index = 0; table_index < profile->table_count; table_index++) { 2164 table = &profile->tables[table_index]; 2165 num_entries = table->index_max - table->index_min + 1; 2166 entries_per_set = num_entries / num_sets; 2167 base = set * entries_per_set; 2168 for (i = 0; i < entries_per_set; i++) { 2169 table->entries[base + i].ref_count++; 2170 table->entries[base + i].entries_per_set = entries_per_set; 2171 } 2172 } 2173 2174 return SOC_E_NONE; 2175 } 2176 2177 2178 /* 2179 * Function: 2180 * soc_profile_mem_reference 2181 * Purpose: 2182 * Add the reference to the set of entries (one or more entries) at 2183 * the specified base index. 2184 * 2185 * Parameters: 2186 * unit - (IN) Unit 2187 * profile - (IN) Pointer to profile memory structure 2188 * index0 - (IN) Base index to the entries in HW for table 0 2189 * entries_per_set0 - (IN) Number of entries in the set for table 0 2190 * (for WARM BOOT only) 2191 * Returns: 2192 * SOC_E_XXX 2193 */ 2194 int 2195 soc_profile_mem_reference(int unit, 2196 soc_profile_mem_t *profile, 2197 int index0, 2198 int entries_per_set0) 2199 { 2200 soc_profile_mem_table_t *table; 2201 int num_entries, num_sets, entries_per_set; 2202 int set, table_index, i, base, base0; 2203 2204 if (profile == NULL) { 2205 return SOC_E_PARAM; 2206 } 2207 2208 if (SOC_WARM_BOOT(unit)) { 2209 if (entries_per_set0 <= 0) { 2210 return SOC_E_PARAM; 2211 } 2212 } 2213 2214 if (profile->tables == NULL || profile->table_count == 0) { 2215 return SOC_E_INIT; 2216 } 2217 2218 table = &profile->tables[0]; 2219 num_entries = table->index_max - table->index_min + 1; 2220 if (index0 < table->index_min || index0 > table->index_max) { 2221 return SOC_E_PARAM; 2222 } 2223 2224 base0 = index0 - table->index_min; 2225 2226 if (SOC_WARM_BOOT(unit)) { 2227 if (num_entries % entries_per_set0) { 2228 return SOC_E_PARAM; 2229 } 2230 entries_per_set = entries_per_set0; 2231 } else { 2232 if (table->entries[base0].ref_count == 0) { 2233 return SOC_E_NOT_FOUND; 2234 } 2235 2236 entries_per_set = table->entries[base0].entries_per_set; 2237 } 2238 2239 if (base0 % entries_per_set) { 2240 return SOC_E_PARAM; 2241 } 2242 2243 num_sets = num_entries / entries_per_set; 2244 set = base0 / entries_per_set; 2245 2246 #if 0 2247 /* Do optional data integrity check */ 2248 SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0)); 2249 #endif 2250 2251 for (table_index = 0; table_index < profile->table_count; table_index++) { 2252 table = &profile->tables[table_index]; 2253 num_entries = table->index_max - table->index_min + 1; 2254 entries_per_set = num_entries / num_sets; 2255 base = set * entries_per_set; 2256 for (i = 0; i < entries_per_set; i++) { 2257 table->entries[base + i].ref_count++; 2258 table->entries[base + i].entries_per_set = entries_per_set; 2259 } 2260 } 2261 2262 return SOC_E_NONE; 2263 } 2264 2265 /* 2266 * Function: 2267 * soc_profile_mem_ref_count_get 2268 * Purpose: 2269 * Get the reference count of the cached entry at the specified index. 2270 * 2271 * Parameters: 2272 * unit - (IN) Unit 2273 * profile - (IN) Pointer to profile memory structure 2274 * index0 - (IN) Base index to the entries in HW for table 0 2275 * ref_count - (OUT) Reference count 2276 * Returns: 2277 * SOC_E_XXX 2278 */ 2279 int 2280 soc_profile_mem_ref_count_get(int unit, 2281 soc_profile_mem_t *profile, 2282 int index0, 2283 int *ref_count) 2284 { 2285 soc_profile_mem_table_t *table; 2286 int base0; 2287 2288 if (profile == NULL || ref_count == NULL) { 2289 return SOC_E_PARAM; 2290 } 2291 2292 if (profile->tables == NULL || profile->table_count == 0) { 2293 return SOC_E_INIT; 2294 } 2295 2296 table = &profile->tables[0]; 2297 if (index0 < table->index_min || index0 > table->index_max) { 2298 return SOC_E_PARAM; 2299 } 2300 2301 base0 = index0 - table->index_min; 2302 2303 *ref_count = table->entries[base0].ref_count; 2304 2305 return SOC_E_NONE; 2306 } 2307 2308 /* 2309 * Function: 2310 * soc_profile_mem_fields32_modify_unique 2311 * Purpose: 2312 * Modify the specified fields (of maximum size 32-bits) 2313 * for all valid (non-zero reference count) entries of a 2314 * profile table in the profile set. 2315 * For simplicity, only one table in a profile 2316 * set may be modified at a time. 2317 * 2318 * This is for when memory is split and UNIQUE per pipe. It will 2319 * modify ALL memories, not just a single pipe 2320 * 2321 * Parameters: 2322 * unit - (IN) Unit 2323 * profile - (IN) Pointer to profile memory structure 2324 * table_id - (IN) Profile set index of table to modify 2325 * field_count - (IN) Number of field/value pairs to modify 2326 * fields - (IN) Array of table fields to modify 2327 * values - (IN) Array of table values to modify 2328 * 2329 * Returns: 2330 * SOC_E_XXX 2331 */ 2332 int 2333 soc_profile_mem_fields32_modify_unique(int unit, 2334 soc_profile_mem_t *profile, 2335 int table_id, 2336 int field_count, 2337 soc_field_t *fields, 2338 uint32 *values) 2339 { 2340 soc_profile_mem_table_t *table; 2341 int index_min, modify_entries; 2342 int offset, fix; 2343 int index, start_index, end_index; 2344 int entry_words, data_words, word; 2345 int alloc_size, rv = SOC_E_NONE; 2346 uint32 entry[SOC_MAX_MEM_WORDS]; 2347 uint32 *cache_p, *mask_p, *range_p, *ent_p; 2348 int i, entries_per_pipe; 2349 soc_mem_t mem; 2350 2351 /* COVERITY: Intentional, stack use of 5192 bytes */ 2352 /* coverity[stack_use_callee_max : FALSE] */ 2353 /* coverity[stack_use_overflow : FALSE] */ 2354 /* coverity[stack_use_return : FALSE] */ 2355 2356 if ((profile == NULL) || 2357 (field_count <= 0) || (fields == NULL) || (values == 0)){ 2358 return SOC_E_PARAM; 2359 } 2360 2361 if (profile->tables == NULL || profile->table_count == 0) { 2362 return SOC_E_INIT; 2363 } 2364 2365 if ((table_id < 0) || (table_id >= profile->table_count)) { 2366 return SOC_E_PARAM; 2367 } 2368 2369 2370 table = &profile->tables[table_id]; 2371 2372 if (NULL == (SOC_MEM_UNIQUE_ACC(unit, table->mem))) { 2373 return SOC_E_PARAM; 2374 } 2375 2376 entries_per_pipe = SOC_MEM_SIZE(unit, table->mem); 2377 2378 index_min = table->index_min; 2379 2380 for (i = 0; i < SOC_INFO(unit).num_pipe; i++) { 2381 /* Record range of modified entries in table */ 2382 start_index = end_index = -1; 2383 for (index = i*entries_per_pipe; 2384 index < (i+1)*entries_per_pipe; index++) { 2385 /* Skip unused entries. */ 2386 if (table->entries[index].ref_count == 0) { 2387 continue; 2388 } 2389 2390 /* Update range of modified entries */ 2391 if (start_index < 0) { 2392 start_index = index; 2393 } 2394 end_index = index; 2395 } 2396 2397 mem = SOC_MEM_UNIQUE_ACC(unit, table->mem)[i]; 2398 2399 /* Knowing the range, we can create the modification buffer */ 2400 modify_entries = end_index - start_index + 1; 2401 entry_words = table->entry_words; 2402 data_words = soc_mem_entry_words(unit, mem); 2403 cache_p = &table->cache_p[start_index * entry_words]; 2404 2405 /* Verify fields fit within data_mask of table, if any */ 2406 if (table->data_mask != NULL) { 2407 mask_p = table->data_mask; 2408 sal_memset(entry, 0, sizeof(entry)); 2409 for (fix = 0; fix < field_count; fix++) { 2410 soc_mem_field32_set(unit, mem, entry, 2411 fields[fix], values[fix]); 2412 } 2413 for (word = 0; word < data_words; word++) { 2414 if ((entry[word] & mask_p[word]) != entry[word]) { 2415 break; 2416 } 2417 /* coverity[dead_error_condition] */ 2418 if (word < data_words) { 2419 return SOC_E_PARAM; 2420 } 2421 } 2422 } 2423 2424 /* 2425 * Use DMA to update regardless of range since this is expected 2426 * to be a bulk operation. 2427 */ 2428 alloc_size = WORDS2BYTES(entry_words) * modify_entries; 2429 range_p = soc_cm_salloc(unit, alloc_size, "profile update"); 2430 if (NULL == range_p) { 2431 return SOC_E_MEMORY; 2432 } 2433 sal_memset((void *)range_p, 0, alloc_size); 2434 2435 /* Read full entry from "HW" */ 2436 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 2437 index_min + start_index%entries_per_pipe, 2438 index_min + end_index%entries_per_pipe, 2439 range_p); 2440 2441 if (SOC_SUCCESS(rv)) { 2442 for (offset = 0; offset < modify_entries; offset++) { 2443 ent_p = 2444 soc_mem_table_idx_to_pointer(unit, mem, 2445 uint32 *, range_p, offset); 2446 2447 /* Update entries in working buffer */ 2448 for (fix = 0; fix < field_count; fix++) { 2449 soc_mem_field32_set(unit, mem, ent_p, 2450 fields[fix], values[fix]); 2451 } 2452 } 2453 } 2454 2455 if (SOC_SUCCESS(rv)) { 2456 /* Write back the modified entries */ 2457 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 2458 index_min + start_index%entries_per_pipe, 2459 index_min + end_index%entries_per_pipe, 2460 range_p); 2461 } 2462 2463 if (SOC_SUCCESS(rv)) { 2464 /* Now that the write to HW succeeded, commit changes to 2465 * profile cache */ 2466 for (offset = 0; offset < modify_entries; offset++) { 2467 ent_p = 2468 soc_mem_table_idx_to_pointer(unit, mem, 2469 uint32 *, range_p, offset); 2470 2471 /* Update cache */ 2472 sal_memcpy(cache_p, ent_p, 2473 data_words * sizeof(uint32)); 2474 cache_p += entry_words; 2475 } 2476 } 2477 soc_cm_sfree(unit, range_p); 2478 } 2479 2480 return rv; 2481 } 2482 2483 2484 /* 2485 * Function: 2486 * soc_profile_mem_fields32_modify 2487 * Purpose: 2488 * Modify the specified fields (of maximum size 32-bits) 2489 * for all valid (non-zero reference count) entries of a 2490 * profile table in the profile set. 2491 * For simplicity, only one table in a profile 2492 * set may be modified at a time. 2493 * 2494 * Parameters: 2495 * unit - (IN) Unit 2496 * profile - (IN) Pointer to profile memory structure 2497 * table_id - (IN) Profile set index of table to modify 2498 * field_count - (IN) Number of field/value pairs to modify 2499 * fields - (IN) Array of table fields to modify 2500 * values - (IN) Array of table values to modify 2501 * 2502 * Returns: 2503 * SOC_E_XXX 2504 */ 2505 int 2506 soc_profile_mem_fields32_modify(int unit, 2507 soc_profile_mem_t *profile, 2508 int table_id, 2509 int field_count, 2510 soc_field_t *fields, 2511 uint32 *values) 2512 { 2513 soc_profile_mem_table_t *table; 2514 int index_min, num_entries, modify_entries; 2515 int offset, fix; 2516 int index, start_index, end_index; 2517 int entry_words, data_words, word; 2518 int alloc_size, rv = SOC_E_NONE; 2519 uint32 entry[SOC_MAX_MEM_WORDS]; 2520 uint32 *cache_p, *mask_p, *range_p, *ent_p; 2521 2522 /* COVERITY: Intentional, stack use of 5192 bytes */ 2523 /* coverity[stack_use_callee_max : FALSE] */ 2524 /* coverity[stack_use_overflow : FALSE] */ 2525 /* coverity[stack_use_return : FALSE] */ 2526 2527 if ((profile == NULL) || 2528 (field_count <= 0) || (fields == NULL) || (values == 0)){ 2529 return SOC_E_PARAM; 2530 } 2531 2532 if (profile->tables == NULL || profile->table_count == 0) { 2533 return SOC_E_INIT; 2534 } 2535 2536 if ((table_id < 0) || (table_id >= profile->table_count)) { 2537 return SOC_E_PARAM; 2538 } 2539 2540 table = &profile->tables[table_id]; 2541 num_entries = table->index_max - table->index_min + 1; 2542 index_min = table->index_min; 2543 2544 /* Record range of modified entries in table */ 2545 start_index = end_index = -1; 2546 for (index = 0; index < num_entries; index++) { 2547 /* Skip unused entries. */ 2548 if (table->entries[index].ref_count == 0) { 2549 continue; 2550 } 2551 2552 /* Update range of modified entries */ 2553 if (start_index < 0) { 2554 start_index = index; 2555 } 2556 end_index = index; 2557 } 2558 2559 /* Knowing the range, we can create the modification buffer */ 2560 modify_entries = end_index - start_index + 1; 2561 entry_words = table->entry_words; 2562 data_words = soc_mem_entry_words(unit, table->mem); 2563 cache_p = &table->cache_p[start_index * entry_words]; 2564 2565 /* Verify fields fit within data_mask of table, if any */ 2566 if (table->data_mask != NULL) { 2567 mask_p = table->data_mask; 2568 sal_memset(entry, 0, sizeof(entry)); 2569 for (fix = 0; fix < field_count; fix++) { 2570 soc_mem_field32_set(unit, table->mem, entry, 2571 fields[fix], values[fix]); 2572 } 2573 for (word = 0; word < data_words; word++) { 2574 if ((entry[word] & mask_p[word]) != entry[word]) { 2575 break; 2576 } 2577 /* coverity[dead_error_condition] */ 2578 if (word < data_words) { 2579 return SOC_E_PARAM; 2580 } 2581 } 2582 } 2583 2584 /* 2585 * Use DMA to update regardless of range since this is expected 2586 * to be a bulk operation. 2587 */ 2588 alloc_size = WORDS2BYTES(entry_words) * modify_entries; 2589 range_p = soc_cm_salloc(unit, alloc_size, "profile update"); 2590 if (NULL == range_p) { 2591 return SOC_E_MEMORY; 2592 } 2593 sal_memset((void *)range_p, 0, alloc_size); 2594 2595 /* Read full entry from "HW" */ 2596 rv = soc_mem_read_range(unit, table->mem, MEM_BLOCK_ANY, 2597 index_min + start_index, 2598 index_min + end_index, 2599 range_p); 2600 2601 if (SOC_SUCCESS(rv)) { 2602 for (offset = 0; offset < modify_entries; offset++) { 2603 ent_p = 2604 soc_mem_table_idx_to_pointer(unit, table->mem, 2605 uint32 *, range_p, offset); 2606 2607 /* Update entries in working buffer */ 2608 for (fix = 0; fix < field_count; fix++) { 2609 soc_mem_field32_set(unit, table->mem, ent_p, 2610 fields[fix], values[fix]); 2611 } 2612 } 2613 } 2614 2615 if (SOC_SUCCESS(rv)) { 2616 /* Write back the modified entries */ 2617 rv = soc_mem_write_range(unit, table->mem, MEM_BLOCK_ALL, 2618 index_min + start_index, 2619 index_min + end_index, 2620 range_p); 2621 } 2622 2623 if (SOC_SUCCESS(rv)) { 2624 /* Now that the write to HW succeeded, commit changes to 2625 * profile cache */ 2626 for (offset = 0; offset < modify_entries; offset++) { 2627 ent_p = 2628 soc_mem_table_idx_to_pointer(unit, table->mem, 2629 uint32 *, range_p, offset); 2630 2631 /* Update cache */ 2632 sal_memcpy(cache_p, ent_p, 2633 data_words * sizeof(uint32)); 2634 cache_p += entry_words; 2635 } 2636 } 2637 2638 soc_cm_sfree(unit, range_p); 2639 2640 return rv; 2641 } 2642 2643 /* 2644 * Function: 2645 * soc_profile_mem_fields32_modify 2646 * Purpose: 2647 * Modify the specified field (of maximum size 32-bits) 2648 * for all valid (non-zero reference count) entries of the 2649 * indicated profile table of the profile set. 2650 * 2651 * Parameters: 2652 * unit - (IN) Unit 2653 * profile - (IN) Pointer to profile memory structure 2654 * table_id - (IN) Profile set index of table to modify 2655 * field - (IN) Table field to modify 2656 * value - (IN) Table value to modify 2657 * 2658 * Returns: 2659 * SOC_E_XXX 2660 */ 2661 int 2662 soc_profile_mem_field32_modify(int unit, 2663 soc_profile_mem_t *profile, 2664 int table_id, 2665 soc_field_t field, 2666 uint32 value) 2667 { 2668 return soc_profile_mem_fields32_modify(unit, profile, table_id, 2669 1, &field, &value); 2670 } 2671 2672 /* 2673 * Function: 2674 * soc_profile_reg_t_init 2675 * Purpose: 2676 * Initialize a soc_profile_reg_t structure. 2677 * 2678 * Parameters: 2679 * profile_reg - (IN) Pointer to profile register structure 2680 * Returns: 2681 * void 2682 */ 2683 void 2684 soc_profile_reg_t_init(soc_profile_reg_t *profile_reg) 2685 { 2686 if (NULL != profile_reg) { 2687 sal_memset(profile_reg, 0, sizeof(soc_profile_reg_t)); 2688 } 2689 } 2690 2691 /* 2692 * Function: 2693 * soc_profile_reg_create 2694 * Purpose: 2695 * Create a shadow copy and refcounts of a profile table. 2696 * If called during WARM BOOT, the shadow copy is populated with 2697 * the HW contents, otherwise, both the shadow copy and the 2698 * HW entries are cleared. 2699 * 2700 * Parameters: 2701 * unit - (IN) Unit 2702 * regs - (IN) Pointer to register id array 2703 * regs_count - (IN) Number of entries in register id array 2704 * profile_reg - (IN) Pointer to profile register structure 2705 * Returns: 2706 * SOC_E_XXX 2707 */ 2708 int 2709 soc_profile_reg_create(int unit, 2710 soc_reg_t *regs, 2711 int regs_count, 2712 soc_profile_reg_t *profile_reg) 2713 { 2714 soc_reg_t reg; 2715 int rv; 2716 int num_entries, reg_idx, i; 2717 int alloc_size; 2718 uint64 *cache_p; 2719 uint64 rval; 2720 2721 if (profile_reg == NULL) { 2722 return SOC_E_INIT; 2723 } 2724 2725 if (regs == NULL || !regs_count) { 2726 return SOC_E_PARAM; 2727 } 2728 2729 num_entries = SOC_REG_NUMELS(unit, regs[0]); 2730 if (num_entries <= 0) { 2731 return SOC_E_BADID; 2732 } 2733 for (reg_idx = 1; reg_idx < regs_count; reg_idx++) { 2734 /* Not needed, as is overwritten later. Coverity complains also. 2735 reg = regs[reg_idx]; 2736 */ 2737 /* Make sure index mechanism is consistent across all registers */ 2738 if (SOC_REG_NUMELS(unit, regs[0]) != num_entries) { 2739 return SOC_E_PARAM; 2740 } 2741 } 2742 2743 alloc_size = num_entries * \ 2744 (sizeof(soc_profile_reg_entry_t) + regs_count * sizeof(uint64)) + 2745 regs_count * sizeof(soc_reg_t); 2746 2747 /* If profile_reg->regs is NULL, init the profile_reg for the first 2748 * time, otherwise simply check for null pointers */ 2749 if (profile_reg->regs != NULL) { 2750 if (profile_reg->entries == NULL) { 2751 return SOC_E_INTERNAL; 2752 } 2753 } else { 2754 profile_reg->entries = sal_alloc(alloc_size, "Profile Reg Entries"); 2755 if (profile_reg->entries == NULL) { 2756 return SOC_E_MEMORY; 2757 } 2758 } 2759 sal_memset(profile_reg->entries, 0, alloc_size); 2760 2761 cache_p = (uint64 *)&profile_reg->entries[num_entries]; 2762 for (i = 0; i < num_entries; i++) { 2763 profile_reg->entries[i].cache_p = cache_p; 2764 cache_p += regs_count; 2765 } 2766 profile_reg->regs = (soc_reg_t *)cache_p; 2767 for (reg_idx = 0; reg_idx < regs_count; reg_idx++) { 2768 profile_reg->regs[reg_idx] = regs[reg_idx]; 2769 } 2770 profile_reg->regs_count = regs_count; 2771 2772 if (SOC_WARM_BOOT(unit)) { 2773 for (i = 0; i < num_entries; i++) { 2774 cache_p = profile_reg->entries[i].cache_p; 2775 for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) { 2776 reg = profile_reg->regs[reg_idx]; 2777 rv = soc_reg_get(unit, reg, REG_PORT_ANY, i, cache_p); 2778 if (rv < 0) { 2779 sal_free(profile_reg->entries); 2780 profile_reg->regs = NULL; 2781 profile_reg->entries = NULL; 2782 return rv; 2783 } 2784 cache_p++; 2785 } 2786 } 2787 } else { 2788 /* Clear HW memory */ 2789 COMPILER_64_ZERO(rval); 2790 for (i = 0; i < num_entries; i++) { 2791 for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) { 2792 reg = profile_reg->regs[reg_idx]; 2793 rv = soc_reg_set(unit, reg, REG_PORT_ANY, i, rval); 2794 if (rv < 0) { 2795 sal_free(profile_reg->entries); 2796 profile_reg->regs = NULL; 2797 profile_reg->entries = NULL; 2798 return rv; 2799 } 2800 } 2801 } 2802 } 2803 2804 return SOC_E_NONE; 2805 } 2806 2807 int 2808 soc_profile_reg_single_reg_create(int unit, 2809 soc_reg_t reg, 2810 soc_profile_reg_t *profile_reg) 2811 { 2812 return soc_profile_reg_create(unit, ®, 1, profile_reg); 2813 } 2814 2815 /* 2816 * Function: 2817 * soc_profile_reg_destroy 2818 * Purpose: 2819 * Destroy the shadow copy and refcounts of a profile table. 2820 * 2821 * Parameters: 2822 * unit - (IN) Unit 2823 * profile_reg - (IN) Pointer to profile register structure 2824 * Returns: 2825 * SOC_E_XXX 2826 */ 2827 int 2828 soc_profile_reg_destroy(int unit, 2829 soc_profile_reg_t *profile_reg) 2830 { 2831 if (profile_reg != NULL) { 2832 if (profile_reg->entries != NULL) { 2833 sal_free(profile_reg->entries); 2834 } 2835 profile_reg->regs = NULL; 2836 profile_reg->entries = NULL; 2837 return SOC_E_NONE; 2838 } 2839 return SOC_E_PARAM; 2840 } 2841 2842 /* 2843 * Function: 2844 * soc_profile_reg_add 2845 * Purpose: 2846 * Add a set of entries (one or more entries) to a profile table. This 2847 * routine searches for a matching set in the profile table. If a matching 2848 * set is found, the ref count for that entry is incremented and 2849 * its base index is returned. If a matching set is not found and a free 2850 * set is found, the HW table is updated, the ref count is incremented, 2851 * and the base index of the set is returned. If no free set is found, an 2852 * error is returned 2853 * 2854 * Parameters: 2855 * unit - (IN) Unit 2856 * profile_reg - (IN) Pointer to profile register structure 2857 * entries - (IN) Array of pointer to register entries set 2858 * entries_per_set - (IN) Number of entries in the set 2859 * index - (OUT) Base index for the entries allocated in HW 2860 * Returns: 2861 * SOC_E_XXX 2862 */ 2863 int 2864 soc_profile_reg_add(int unit, 2865 soc_profile_reg_t *profile_reg, 2866 uint64 **entries, 2867 int entries_per_set, 2868 uint32 *index) 2869 { 2870 soc_reg_t reg; 2871 int base, free_index; 2872 int num_entries, reg_idx, i; 2873 uint64 *cache_p, *entry_p; 2874 2875 if (profile_reg == NULL || profile_reg->regs == NULL || 2876 profile_reg->entries == NULL) { 2877 return SOC_E_INIT; 2878 } 2879 2880 num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]); 2881 if (num_entries <= 0) { 2882 return SOC_E_INTERNAL; 2883 } 2884 2885 if (entries == NULL || index == NULL || 2886 entries_per_set < 1 || entries_per_set > num_entries) { 2887 return SOC_E_PARAM; 2888 } 2889 2890 /* 2891 * Search for an existing entry that has the same configuration. 2892 */ 2893 free_index = -1; 2894 for (base = 0; base < num_entries; base += entries_per_set) { 2895 /* Skip unused entries. */ 2896 if (profile_reg->entries[base].ref_count == 0) { 2897 if (free_index == -1) { 2898 /* Preserve location of free slot. */ 2899 free_index = base; 2900 for (i = 1; i < entries_per_set; i++) { 2901 if (profile_reg->entries[base + i].ref_count) { 2902 free_index = -1; 2903 break; 2904 } 2905 } 2906 } 2907 continue; 2908 } 2909 2910 for (i = 0; i < entries_per_set; i++) { 2911 if (profile_reg->entries[base + i].entries_per_set != 2912 entries_per_set) { 2913 break; 2914 } 2915 for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) { 2916 reg = profile_reg->regs[reg_idx]; 2917 entry_p = &entries[reg_idx][i]; 2918 cache_p = &profile_reg->entries[base + i].cache_p[reg_idx]; 2919 if (COMPILER_64_NE(*cache_p, *entry_p)) { 2920 break; 2921 } 2922 } 2923 if (reg_idx != profile_reg->regs_count) { 2924 break; 2925 } 2926 } 2927 if (i == entries_per_set) { 2928 for (i = 0; i < entries_per_set; i++) { 2929 profile_reg->entries[base + i].ref_count++; 2930 } 2931 *index = base; 2932 return SOC_E_NONE; 2933 } 2934 if (profile_reg->entries[base].entries_per_set > entries_per_set) { 2935 base += profile_reg->entries[base].entries_per_set - 2936 entries_per_set; 2937 } 2938 } 2939 2940 if (free_index == -1) { 2941 return SOC_E_RESOURCE; 2942 } 2943 2944 for (i = 0; i < entries_per_set; i++) { 2945 for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) { 2946 reg = profile_reg->regs[reg_idx]; 2947 entry_p = &entries[reg_idx][i]; 2948 cache_p = &profile_reg->entries[free_index + i].cache_p[reg_idx]; 2949 2950 if (profile_reg->profile_flag & SOC_PROFILE_FLAG_XPE_SINGLE_ACC) { 2951 int xpe; 2952 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 2953 int inst = xpe | SOC_REG_ADDR_INSTANCE_MASK; 2954 /* Insert the new entries into profile table */ 2955 SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg, inst, 2956 free_index + i, *entry_p)); 2957 } 2958 } else { 2959 /* Insert the new entries into profile table */ 2960 SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg, REG_PORT_ANY, 2961 free_index + i, *entry_p)); 2962 } 2963 2964 /* Copy entry into the software cache. */ 2965 *cache_p = *entry_p; 2966 } 2967 profile_reg->entries[free_index + i].ref_count++; 2968 profile_reg->entries[free_index + i].entries_per_set = entries_per_set; 2969 } 2970 *index = free_index; 2971 return SOC_E_NONE; 2972 } 2973 2974 /* 2975 * Function: 2976 * soc_profile_reg_delete 2977 * Purpose: 2978 * Delete the reference to the set of entries (one or more entries) at 2979 * the specified index. 2980 * 2981 * Parameters: 2982 * unit - (IN) Unit 2983 * profile_reg - (IN) Pointer to profile register structure 2984 * index - (IN) Base index for the entries allocated in HW 2985 * Returns: 2986 * SOC_E_XXX 2987 */ 2988 int 2989 soc_profile_reg_delete(int unit, 2990 soc_profile_reg_t *profile_reg, 2991 uint32 index) 2992 { 2993 soc_reg_t reg; 2994 int num_entries, entries_per_set, reg_idx, i; 2995 uint64 rval; 2996 2997 if (profile_reg == NULL || profile_reg->regs == NULL || 2998 profile_reg->entries == NULL) { 2999 return SOC_E_INIT; 3000 } 3001 3002 num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]); 3003 if (num_entries <= 0) { 3004 return SOC_E_INTERNAL; 3005 } 3006 3007 if ((int)index >= num_entries) { 3008 return SOC_E_PARAM; 3009 } 3010 3011 if (profile_reg->entries[index].ref_count == 0) { 3012 return SOC_E_NOT_FOUND; 3013 } 3014 3015 entries_per_set = profile_reg->entries[index].entries_per_set; 3016 if (index % entries_per_set) { 3017 return SOC_E_BADID; 3018 } 3019 3020 profile_reg->entries[index].ref_count--; 3021 for (i = 1; i < entries_per_set; i++) { 3022 profile_reg->entries[index + i].ref_count--; 3023 if (profile_reg->entries[index + i].ref_count != 3024 profile_reg->entries[index].ref_count || 3025 profile_reg->entries[index + i].entries_per_set != 3026 profile_reg->entries[index].entries_per_set) { 3027 return SOC_E_INTERNAL; 3028 } 3029 } 3030 3031 if (profile_reg->entries[index].ref_count != 0) { 3032 return SOC_E_NONE; 3033 } 3034 3035 COMPILER_64_ZERO(rval); 3036 for (i = 0; i < entries_per_set; i++) { 3037 for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) { 3038 /* Clear the entry in the HW */ 3039 reg = profile_reg->regs[reg_idx]; 3040 if (profile_reg->profile_flag & SOC_PROFILE_FLAG_XPE_SINGLE_ACC) { 3041 int xpe; 3042 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 3043 int inst = xpe | SOC_REG_ADDR_INSTANCE_MASK; 3044 SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg, inst, 3045 index + i, rval)); 3046 } 3047 } else { 3048 SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg, REG_PORT_ANY, 3049 index + i, rval)); 3050 } 3051 } 3052 } 3053 3054 return SOC_E_NONE; 3055 } 3056 3057 /* 3058 * Function: 3059 * soc_profile_reg_get 3060 * Purpose: 3061 * Get a set of entries (one or more entries) at the specified index. 3062 * 3063 * Parameters: 3064 * unit - (IN) Unit 3065 * profile_reg - (IN) Pointer to profile register structure 3066 * index - (IN) Base index for the entries allocated in HW 3067 * count - (IN) Number of entries to retreive 3068 * entries - (OUT) Array of pointer to register entries set 3069 * Returns: 3070 * SOC_E_XXX 3071 */ 3072 int 3073 soc_profile_reg_get(int unit, 3074 soc_profile_reg_t *profile_reg, 3075 uint32 index, 3076 int count, 3077 uint64 **entries) 3078 { 3079 int num_entries, reg_idx, i; 3080 uint64 *cache_p, *entry_p; 3081 3082 if (profile_reg == NULL || profile_reg->regs == NULL || 3083 profile_reg->entries == NULL) { 3084 return SOC_E_INIT; 3085 } 3086 3087 num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]); 3088 if (num_entries <= 0) { 3089 return SOC_E_INTERNAL; 3090 } 3091 3092 if (entries == NULL || (int)index >= num_entries || count <= 0) { 3093 return SOC_E_PARAM; 3094 } 3095 3096 if (profile_reg->entries[index].ref_count == 0) { 3097 return SOC_E_NOT_FOUND; 3098 } 3099 3100 if (count > profile_reg->entries[index].entries_per_set) { 3101 return SOC_E_PARAM; 3102 } 3103 3104 if (index % profile_reg->entries[index].entries_per_set) { 3105 return SOC_E_BADID; 3106 } 3107 3108 for (i = 1; i < count; i++) { 3109 /* Do some optional data integrity check */ 3110 if (profile_reg->entries[index + i].ref_count != 3111 profile_reg->entries[index].ref_count || 3112 profile_reg->entries[index + i].entries_per_set != 3113 profile_reg->entries[index].entries_per_set) { 3114 return SOC_E_INTERNAL; 3115 } 3116 } 3117 3118 for (i = 0; i < count; i++) { 3119 for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) { 3120 entry_p = &entries[reg_idx][i]; 3121 cache_p = &profile_reg->entries[index + i].cache_p[reg_idx]; 3122 3123 /* Copy entry from the software cache. */ 3124 *entry_p = *cache_p; 3125 } 3126 } 3127 3128 return SOC_E_NONE; 3129 } 3130 3131 /* 3132 * Function: 3133 * soc_profile_reg_reference 3134 * Purpose: 3135 * Add the reference to the set of entries (one or more entries) at 3136 * the specified base index. 3137 * 3138 * Parameters: 3139 * unit - (IN) Unit 3140 * profile_reg - (IN) Pointer to profile register structure 3141 * index - (IN) Base index for the entries allocated in HW 3142 * Returns: 3143 * SOC_E_XXX 3144 */ 3145 int 3146 soc_profile_reg_reference(int unit, 3147 soc_profile_reg_t *profile_reg, 3148 uint32 index, 3149 int entries_per_set_override) 3150 { 3151 int num_entries, entries_per_set, i; 3152 3153 if (profile_reg == NULL || profile_reg->regs == NULL || 3154 profile_reg->entries == NULL) { 3155 return SOC_E_INIT; 3156 } 3157 3158 num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]); 3159 if (num_entries <= 0) { 3160 return SOC_E_INTERNAL; 3161 } 3162 3163 if ((int)index >= num_entries) { 3164 return SOC_E_PARAM; 3165 } 3166 3167 if ((profile_reg->entries[index].ref_count == 0) && 3168 (!SOC_WARM_BOOT(unit))) { 3169 return SOC_E_NOT_FOUND; 3170 } 3171 3172 if (SOC_WARM_BOOT(unit)) { 3173 /* During WB, use the passed in entries_per_set_override value */ 3174 if ((entries_per_set_override < 1) || 3175 (entries_per_set_override > num_entries)) { 3176 return SOC_E_PARAM; 3177 } 3178 profile_reg->entries[index].entries_per_set = 3179 entries_per_set_override; 3180 } 3181 entries_per_set = profile_reg->entries[index].entries_per_set; 3182 if (index % entries_per_set) { 3183 return SOC_E_BADID; 3184 } 3185 3186 profile_reg->entries[index].ref_count++; 3187 for (i = 1; i < entries_per_set; i++) { 3188 profile_reg->entries[index + i].ref_count++; 3189 if (SOC_WARM_BOOT(unit)) { 3190 /* During WB, use the passed in entries_per_set_override value */ 3191 profile_reg->entries[index + i].entries_per_set = 3192 entries_per_set_override; 3193 } 3194 /* Do some optional data integrity check */ 3195 if (profile_reg->entries[index + i].ref_count != 3196 profile_reg->entries[index].ref_count || 3197 profile_reg->entries[index + i].entries_per_set != 3198 profile_reg->entries[index].entries_per_set) { 3199 return SOC_E_INTERNAL; 3200 } 3201 } 3202 3203 return SOC_E_NONE; 3204 } 3205 3206 /* 3207 * Function: 3208 * soc_profile_reg_ref_count_get 3209 * Purpose: 3210 * Get the reference count of the cached entry at the specified index. 3211 * 3212 * Parameters: 3213 * unit - (IN) Unit 3214 * profile_reg - (IN) Pointer to profile register structure 3215 * index - (IN) Base index for the entries allocated in HW 3216 * ref_count - (OUT) Reference count 3217 * Returns: 3218 * SOC_E_XXX 3219 */ 3220 int 3221 soc_profile_reg_ref_count_get(int unit, 3222 soc_profile_reg_t *profile_reg, 3223 uint32 index, int *ref_count) 3224 { 3225 int num_entries, entries_per_set; 3226 3227 if (profile_reg == NULL || profile_reg->regs == NULL || 3228 profile_reg->entries == NULL || ref_count == NULL) { 3229 return SOC_E_INIT; 3230 } 3231 3232 num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]); 3233 if (num_entries <= 0) { 3234 return SOC_E_INTERNAL; 3235 } 3236 3237 if ((int)index >= num_entries) { 3238 return SOC_E_PARAM; 3239 } 3240 3241 if (profile_reg->entries[index].ref_count == 0) { 3242 *ref_count = 0; 3243 return SOC_E_NONE; 3244 } 3245 3246 entries_per_set = profile_reg->entries[index].entries_per_set; 3247 if (index % entries_per_set) { 3248 return SOC_E_BADID; 3249 } 3250 3251 *ref_count = profile_reg->entries[index].ref_count; 3252 3253 return SOC_E_NONE; 3254 } 3255 3256 /* 3257 * Function: 3258 * soc_profile_mem_write_mode_get 3259 * Purpose: 3260 * Get dma or pio write operation mode 3261 * for a profile table mem. 3262 * 3263 * Parameters: 3264 * unit - (IN) Unit 3265 * profile - (IN) Pointer to profile memory structure 3266 * index0 - (IN) Base index to get mode 3267 * mode - (OUT) table write mode 3268 * Returns: 3269 * SOC_E_XXX 3270 */ 3271 int 3272 soc_profile_mem_write_mode_get(int unit, 3273 soc_profile_mem_t *profile, 3274 uint32 index0, int *mode) 3275 { 3276 soc_profile_mem_table_t *table; 3277 int entries_per_set; 3278 int base0; 3279 3280 if (profile == NULL) { 3281 return SOC_E_PARAM; 3282 } 3283 3284 if (profile->tables == NULL || profile->table_count == 0) { 3285 return SOC_E_INIT; 3286 } 3287 3288 table = &profile->tables[0]; 3289 if (index0 < table->index_min || index0 > table->index_max) { 3290 return SOC_E_PARAM; 3291 } 3292 3293 base0 = index0 - table->index_min; 3294 3295 if (table->entries[base0].ref_count == 0) { 3296 return SOC_E_NOT_FOUND; 3297 } 3298 3299 entries_per_set = table->entries[base0].entries_per_set; 3300 3301 if (base0 % entries_per_set) { 3302 return SOC_E_PARAM; 3303 } 3304 3305 if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) { 3306 *mode = SOC_PROFILE_MEM_WRITE_DMA_MODE; 3307 } else { 3308 *mode = SOC_PROFILE_MEM_WRITE_PIO_MODE; 3309 } 3310 3311 return SOC_E_NONE; 3312 }