1/* 2 * Copyright (c) 2014, 2018-2019 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Stan Czerniawski 38 * Damian Richardson 39 */ 40 41#include "dev/arm/smmu_v3_caches.hh" 42 43#include <numeric> 44 45#include "base/bitfield.hh" 46#include "base/intmath.hh" 47#include "base/logging.hh" 48#include "sim/stats.hh" 49 50 51// taken from hex expansion of pi 52#define SMMUTLB_SEED 0xEA752DFE 53#define ARMARCHTLB_SEED 0x8B021FA1 54#define IPACACHE_SEED 0xE5A0CC0F 55#define CONFIGCACHE_SEED 0xB56F74E8 56#define WALKCACHE_SEED 0x18ACF3D6 57 58/* 59 * BaseCache 60 * 61 * TODO: move more code into this base class to reduce duplication. 62 */ 63 64SMMUv3BaseCache::SMMUv3BaseCache(const std::string &policy_name, uint32_t seed) : 65 replacementPolicy(decodePolicyName(policy_name)), 66 nextToReplace(0), 67 random(seed), 68 useStamp(0) 69{} 70 71int 72SMMUv3BaseCache::decodePolicyName(const std::string &policy_name) 73{ 74 if (policy_name == "rr") { 75 return SMMU_CACHE_REPL_ROUND_ROBIN; 76 } else if (policy_name == "rand") { 77 return SMMU_CACHE_REPL_RANDOM; 78 } else if (policy_name == "lru") { 79 return SMMU_CACHE_REPL_LRU; 80 } else { 81 panic("Unknown cache replacement policy '%s'\n", policy_name); 82 } 83} 84 85void 86SMMUv3BaseCache::regStats(const std::string &name) 87{ 88 using namespace Stats; 89 90 91 averageLookups 92 .name(name + ".averageLookups") 93 .desc("Average number lookups per second") 94 .flags(pdf); 95 96 totalLookups 97 .name(name + ".totalLookups") 98 .desc("Total number of lookups") 99 .flags(pdf); 100 101 averageLookups = totalLookups / simSeconds; 102 103 104 averageMisses 105 .name(name + ".averageMisses") 106 .desc("Average number misses per second") 107 .flags(pdf); 108 109 totalMisses 110 .name(name + ".totalMisses") 111 .desc("Total number of misses") 112 .flags(pdf); 113 114 averageMisses = totalMisses / simSeconds; 115 116 117 averageUpdates 118 .name(name + ".averageUpdates") 119 .desc("Average number updates per second") 120 .flags(pdf); 121 122 totalUpdates 123 .name(name + ".totalUpdates") 124 .desc("Total number of updates") 125 .flags(pdf); 126 127 averageUpdates = totalUpdates / simSeconds; 128 129 130 averageHitRate 131 .name(name + ".averageHitRate") 132 .desc("Average hit rate") 133 .flags(pdf); 134 135 averageHitRate = (totalLookups - totalMisses) / totalLookups; 136 137 insertions 138 .name(name + ".insertions") 139 .desc("Number of insertions (not replacements)") 140 .flags(pdf); 141} 142 143 144 145/* 146 * SMMUTLB 147 */ 148 149SMMUTLB::SMMUTLB(unsigned numEntries, unsigned _associativity, 150 const std::string &policy) 151: 152 SMMUv3BaseCache(policy, SMMUTLB_SEED), 153 associativity(_associativity) 154{ 155 if (associativity == 0) 156 associativity = numEntries; // fully associative 157 158 if (numEntries == 0) 159 fatal("SMMUTLB must have at least one entry\n"); 160 161 if (associativity > numEntries) 162 fatal("SMMUTLB associativity cannot be higher than " 163 "its number of entries\n"); 164 165 unsigned num_sets = numEntries / associativity; 166 167 if (num_sets*associativity != numEntries) 168 fatal("Number of SMMUTLB entries must be divisible " 169 "by its associativity\n"); 170 171 Entry e; 172 e.valid = false; 173 174 Set set(associativity, e); 175 sets.resize(num_sets, set); 176} 177 178const SMMUTLB::Entry* 179SMMUTLB::lookup(uint32_t sid, uint32_t ssid, 180 Addr va, bool updStats) 181{ 182 const Entry *result = NULL; 183 184 Set &set = sets[pickSetIdx(va)]; 185 186 for (size_t i = 0; i < set.size(); i++) { 187 const Entry &e = set[i]; 188 189 if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) && 190 e.sid==sid && e.ssid==ssid) 191 { 192 if (result != NULL) 193 panic("SMMUTLB: duplicate entry found!\n"); 194 195 result = &e; 196 break; 197 } 198 } 199 200 if (updStats) { 201 if (result) 202 result->lastUsed = useStamp++; 203 204 totalLookups++; 205 if (result == NULL) 206 totalMisses++; 207 } 208 209 return result; 210} 211 212const SMMUTLB::Entry* 213SMMUTLB::lookupAnyVA(uint32_t sid, uint32_t ssid, bool updStats) 214{ 215 const Entry *result = NULL; 216 217 for (size_t s = 0; s < sets.size(); s++) { 218 Set &set = sets[s]; 219 220 for (size_t i = 0; i < set.size(); i++) { 221 const Entry &e = set[i]; 222 223 if (e.valid && e.sid==sid && e.ssid==ssid) { 224 result = &e; 225 break; 226 } 227 } 228 } 229 230 if (updStats) { 231 totalLookups++; 232 if (result == NULL) 233 totalMisses++; 234 } 235 236 return result; 237} 238 239void 240SMMUTLB::store(const Entry &incoming, AllocPolicy alloc) 241{ 242 if (!incoming.valid) 243 panic("Tried to store an invalid entry\n"); 244 245 incoming.lastUsed = 0; 246 247 const Entry *existing = 248 lookup(incoming.sid, incoming.ssid, incoming.va, false); 249 250 if (existing) { 251 *const_cast<Entry *> (existing) = incoming; 252 } else { 253 Set &set = sets[pickSetIdx(incoming.va)]; 254 set[pickEntryIdxToReplace(set, alloc)] = incoming; 255 } 256 257 totalUpdates++; 258} 259 260void 261SMMUTLB::invalidateSSID(uint32_t sid, uint32_t ssid) 262{ 263 Set &set = sets[pickSetIdx(sid, ssid)]; 264 265 for (size_t i = 0; i < set.size(); i++) { 266 Entry &e = set[i]; 267 268 if (e.sid == sid && e.ssid == ssid) 269 e.valid = false; 270 } 271} 272 273void 274SMMUTLB::invalidateSID(uint32_t sid) 275{ 276 for (size_t s = 0; s < sets.size(); s++) { 277 Set &set = sets[s]; 278 279 for (size_t i = 0; i < set.size(); i++) { 280 Entry &e = set[i]; 281 282 if (e.sid == sid) 283 e.valid = false; 284 } 285 } 286} 287 288void 289SMMUTLB::invalidateVA(Addr va, uint16_t asid, uint16_t vmid) 290{ 291 Set &set = sets[pickSetIdx(va)]; 292 293 for (size_t i = 0; i < set.size(); i++) { 294 Entry &e = set[i]; 295 296 if ((e.va & e.vaMask) == (va & e.vaMask) && 297 e.asid==asid && e.vmid==vmid) 298 { 299 e.valid = false; 300 } 301 } 302} 303 304void 305SMMUTLB::invalidateVAA(Addr va, uint16_t vmid) 306{ 307 Set &set = sets[pickSetIdx(va)]; 308 309 for (size_t i = 0; i < set.size(); i++) { 310 Entry &e = set[i]; 311 312 if ((e.va & e.vaMask) == (va & e.vaMask) && e.vmid==vmid) 313 e.valid = false; 314 } 315} 316 317void 318SMMUTLB::invalidateASID(uint16_t asid, uint16_t vmid) 319{ 320 for (size_t s = 0; s < sets.size(); s++) { 321 Set &set = sets[s]; 322 323 for (size_t i = 0; i < set.size(); i++) { 324 Entry &e = set[i]; 325 326 if (e.asid==asid && e.vmid==vmid) 327 e.valid = false; 328 } 329 } 330} 331 332void 333SMMUTLB::invalidateVMID(uint16_t vmid) 334{ 335 for (size_t s = 0; s < sets.size(); s++) { 336 Set &set = sets[s]; 337 338 for (size_t i = 0; i < set.size(); i++) { 339 Entry &e = set[i]; 340 341 if (e.vmid == vmid) 342 e.valid = false; 343 } 344 } 345} 346 347void 348SMMUTLB::invalidateAll() 349{ 350 for (size_t s = 0; s < sets.size(); s++) { 351 Set &set = sets[s]; 352 353 for (size_t i = 0; i < set.size(); i++) 354 set[i].valid = false; 355 } 356} 357 358size_t 359SMMUTLB::pickSetIdx(Addr va) const 360{ 361 return (va >> 12) % sets.size(); 362} 363 364size_t 365SMMUTLB::pickSetIdx(uint32_t sid, uint32_t ssid) const 366{ 367 return (sid^ssid) % sets.size(); 368} 369 370size_t 371SMMUTLB::pickEntryIdxToReplace(const Set &set, AllocPolicy alloc) 372{ 373 if (alloc == ALLOC_LAST_WAY) 374 return associativity - 1; 375 376 uint32_t lru_tick = UINT32_MAX; 377 size_t lru_idx = 0; 378 size_t max_idx = 379 alloc==ALLOC_ANY_BUT_LAST_WAY ? 380 set.size()-1 : set.size(); 381 382 for (size_t i = 0; i < max_idx; i++) { 383 if (!set[i].valid) { 384 insertions++; 385 return i; 386 } 387 388 if (set[i].lastUsed < lru_tick) { 389 lru_idx = i; 390 lru_tick = set[i].lastUsed; 391 } 392 } 393 394 switch (replacementPolicy) { 395 case SMMU_CACHE_REPL_ROUND_ROBIN: 396 switch (alloc) { 397 case ALLOC_ANY_WAY: 398 return nextToReplace = ((nextToReplace+1) % associativity); 399 case ALLOC_ANY_BUT_LAST_WAY: 400 return nextToReplace = ((nextToReplace+1) % (associativity-1)); 401 default: 402 panic("Unknown allocation mode %d\n", alloc); 403 } 404 405 case SMMU_CACHE_REPL_RANDOM: 406 switch (alloc) { 407 case ALLOC_ANY_WAY: 408 return random.random<size_t>(0, associativity-1); 409 case ALLOC_ANY_BUT_LAST_WAY: 410 return random.random<size_t>(0, associativity-2); 411 default: 412 panic("Unknown allocation mode %d\n", alloc); 413 } 414 415 case SMMU_CACHE_REPL_LRU: 416 return lru_idx; 417 418 default: 419 panic("Unknown replacement policy %d\n", replacementPolicy); 420 } 421} 422 423 424 425/* 426 * ARMArchTLB 427 */ 428 429ARMArchTLB::ARMArchTLB(unsigned numEntries, unsigned _associativity, 430 const std::string &policy) 431: 432 SMMUv3BaseCache(policy, ARMARCHTLB_SEED), 433 associativity(_associativity) 434{ 435 if (associativity == 0) 436 associativity = numEntries; // fully associative 437 438 if (numEntries == 0) 439 fatal("ARMArchTLB must have at least one entry\n"); 440 441 if (associativity > numEntries) 442 fatal("ARMArchTLB associativity cannot be higher than " 443 "its number of entries\n"); 444 445 unsigned num_sets = numEntries / associativity; 446 447 if (num_sets*associativity != numEntries) 448 fatal("Number of ARMArchTLB entries must be divisible " 449 "by its associativity\n"); 450 451 Entry e; 452 e.valid = false; 453 454 Set set(associativity, e); 455 sets.resize(num_sets, set); 456} 457 458const ARMArchTLB::Entry * 459ARMArchTLB::lookup(Addr va, uint16_t asid, uint16_t vmid, bool updStats) 460{ 461 const Entry *result = NULL; 462 463 Set &set = sets[pickSetIdx(va, asid, vmid)]; 464 465 for (size_t i = 0; i < set.size(); i++) { 466 const Entry &e = set[i]; 467 468 if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) && 469 e.asid==asid && e.vmid==vmid) 470 { 471 if (result != NULL) 472 panic("ARMArchTLB: duplicate entry found!\n"); 473 474 result = &e; 475 break; 476 } 477 } 478 479 if (updStats) { 480 if (result) 481 result->lastUsed = useStamp++; 482 483 totalLookups++; 484 if (result == NULL) 485 totalMisses++; 486 } 487 488 return result; 489} 490 491void 492ARMArchTLB::store(const Entry &incoming) 493{ 494 if (!incoming.valid) 495 panic("Tried to store an invalid entry\n"); 496 497 incoming.lastUsed = 0; 498 499 const Entry *existing = 500 lookup(incoming.va, incoming.asid, incoming.vmid, false); 501 502 if (existing) { 503 *const_cast<Entry *> (existing) = incoming; 504 } else { 505 Set &set = sets[pickSetIdx(incoming.va, incoming.asid, incoming.vmid)]; 506 set[pickEntryIdxToReplace(set)] = incoming; 507 } 508 509 totalUpdates++; 510} 511 512void 513ARMArchTLB::invalidateVA(Addr va, uint16_t asid, uint16_t vmid) 514{ 515 Set &set = sets[pickSetIdx(va, asid, vmid)]; 516 517 for (size_t i = 0; i < set.size(); i++) { 518 Entry &e = set[i]; 519 520 if ((e.va & e.vaMask) == (va & e.vaMask) && 521 e.asid==asid && e.vmid==vmid) 522 { 523 e.valid = false; 524 } 525 } 526} 527 528void 529ARMArchTLB::invalidateVAA(Addr va, uint16_t vmid) 530{ 531 for (size_t s = 0; s < sets.size(); s++) { 532 Set &set = sets[s]; 533 534 for (size_t i = 0; i < set.size(); i++) { 535 Entry &e = set[i]; 536 537 if ((e.va & e.vaMask) == (va & e.vaMask) && e.vmid==vmid) 538 e.valid = false; 539 } 540 } 541} 542 543void 544ARMArchTLB::invalidateASID(uint16_t asid, uint16_t vmid) 545{ 546 for (size_t s = 0; s < sets.size(); s++) { 547 Set &set = sets[s]; 548 549 for (size_t i = 0; i < set.size(); i++) { 550 Entry &e = set[i]; 551 552 if (e.asid==asid && e.vmid==vmid) 553 e.valid = false; 554 } 555 } 556} 557 558void 559ARMArchTLB::invalidateVMID(uint16_t vmid) 560{ 561 for (size_t s = 0; s < sets.size(); s++) { 562 Set &set = sets[s]; 563 564 for (size_t i = 0; i < set.size(); i++) { 565 Entry &e = set[i]; 566 567 if (e.vmid == vmid) 568 e.valid = false; 569 } 570 } 571} 572 573void 574ARMArchTLB::invalidateAll() 575{ 576 for (size_t s = 0; s < sets.size(); s++) { 577 Set &set = sets[s]; 578 579 for (size_t i = 0; i < set.size(); i++) 580 set[i].valid = false; 581 } 582} 583 584size_t 585ARMArchTLB::pickSetIdx(Addr va, uint16_t asid, uint16_t vmid) const 586{ 587 return ((va >> 12) ^ asid ^ vmid) % sets.size(); 588} 589 590size_t 591ARMArchTLB::pickEntryIdxToReplace(const Set &set) 592{ 593 size_t lru_idx = 0; 594 uint32_t lru_tick = UINT32_MAX; 595 596 for (size_t i = 0; i < set.size(); i++) { 597 if (!set[i].valid) { 598 insertions++; 599 return i; 600 } 601 602 if (set[i].lastUsed < lru_tick) { 603 lru_idx = i; 604 lru_tick = set[i].lastUsed; 605 } 606 } 607 608 switch (replacementPolicy) { 609 case SMMU_CACHE_REPL_ROUND_ROBIN: 610 return nextToReplace = ((nextToReplace+1) % associativity); 611 612 case SMMU_CACHE_REPL_RANDOM: 613 return random.random<size_t>(0, associativity-1); 614 615 case SMMU_CACHE_REPL_LRU: 616 return lru_idx; 617 618 default: 619 panic("Unknown replacement policy %d\n", replacementPolicy); 620 } 621 622} 623 624/* 625 * IPACache 626 */ 627 628IPACache::IPACache(unsigned numEntries, unsigned _associativity, 629 const std::string &policy) 630: 631 SMMUv3BaseCache(policy, IPACACHE_SEED), 632 associativity(_associativity) 633{ 634 if (associativity == 0) 635 associativity = numEntries; // fully associative 636 637 if (numEntries == 0) 638 fatal("IPACache must have at least one entry\n"); 639 640 if (associativity > numEntries) 641 fatal("IPACache associativity cannot be higher than " 642 "its number of entries\n"); 643 644 unsigned num_sets = numEntries / associativity; 645 646 if (num_sets*associativity != numEntries) 647 fatal("Number of IPACache entries must be divisible " 648 "by its associativity\n"); 649 650 Entry e; 651 e.valid = false; 652 653 Set set(associativity, e); 654 sets.resize(num_sets, set); 655} 656 657const IPACache::Entry* 658IPACache::lookup(Addr ipa, uint16_t vmid, bool updStats) 659{ 660 const Entry *result = NULL; 661 662 Set &set = sets[pickSetIdx(ipa, vmid)]; 663 664 for (size_t i = 0; i < set.size(); i++) { 665 const Entry &e = set[i]; 666 667 if (e.valid && (e.ipa & e.ipaMask) == (ipa & e.ipaMask) && 668 e.vmid==vmid) 669 { 670 if (result != NULL) 671 panic("IPACache: duplicate entry found!\n"); 672 673 result = &e; 674 break; 675 } 676 } 677 678 if (updStats) { 679 if (result) 680 result->lastUsed = useStamp++; 681 682 totalLookups++; 683 if (result == NULL) 684 totalMisses++; 685 } 686 687 return result; 688} 689 690void 691IPACache::store(const Entry &incoming) 692{ 693 if (!incoming.valid) 694 panic("Tried to store an invalid entry\n"); 695 696 incoming.lastUsed = 0; 697 698 const Entry *existing = lookup(incoming.ipa, incoming.vmid, false); 699 700 if (existing) { 701 *const_cast<Entry *> (existing) = incoming; 702 } else { 703 Set &set = sets[pickSetIdx(incoming.ipa, incoming.vmid)]; 704 set[pickEntryIdxToReplace(set)] = incoming; 705 } 706 707 totalUpdates++; 708} 709 710void 711IPACache::invalidateIPA(Addr ipa, uint16_t vmid) 712{ 713 Set &set = sets[pickSetIdx(ipa, vmid)]; 714 715 for (size_t i = 0; i < set.size(); i++) { 716 Entry &e = set[i]; 717 718 if ((e.ipa & e.ipaMask) == (ipa & e.ipaMask) && e.vmid==vmid) 719 e.valid = false; 720 } 721} 722 723void 724IPACache::invalidateIPAA(Addr ipa) 725{ 726 for (size_t s = 0; s < sets.size(); s++) { 727 Set &set = sets[s]; 728 729 for (size_t i = 0; i < set.size(); i++) { 730 Entry &e = set[i]; 731 732 if ((e.ipa & e.ipaMask) == (ipa & e.ipaMask)) 733 e.valid = false; 734 } 735 } 736} 737 738void 739IPACache::invalidateVMID(uint16_t vmid) 740{ 741 for (size_t s = 0; s < sets.size(); s++) { 742 Set &set = sets[s]; 743 744 for (size_t i = 0; i < set.size(); i++) { 745 Entry &e = set[i]; 746 747 if (e.vmid == vmid) 748 e.valid = false; 749 } 750 } 751} 752 753void 754IPACache::invalidateAll() 755{ 756 for (size_t s = 0; s < sets.size(); s++) { 757 Set &set = sets[s]; 758 759 for (size_t i = 0; i < set.size(); i++) 760 set[i].valid = false; 761 } 762} 763 764size_t 765IPACache::pickSetIdx(Addr va, uint16_t vmid) const 766{ 767 return ((va >> 12) ^ vmid) % sets.size(); 768} 769 770size_t 771IPACache::pickEntryIdxToReplace(const Set &set) 772{ 773 size_t lru_idx = 0; 774 uint32_t lru_tick = UINT32_MAX; 775 776 for (size_t i = 0; i < set.size(); i++) { 777 if (!set[i].valid) { 778 insertions++; 779 return i; 780 } 781 782 if (set[i].lastUsed < lru_tick) { 783 lru_idx = i; 784 lru_tick = set[i].lastUsed; 785 } 786 } 787 788 switch (replacementPolicy) { 789 case SMMU_CACHE_REPL_ROUND_ROBIN: 790 return nextToReplace = ((nextToReplace+1) % associativity); 791 792 case SMMU_CACHE_REPL_RANDOM: 793 return random.random<size_t>(0, associativity-1); 794 795 case SMMU_CACHE_REPL_LRU: 796 return lru_idx; 797 798 default: 799 panic("Unknown replacement policy %d\n", replacementPolicy); 800 } 801 802} 803 804/* 805 * ConfigCache 806 */ 807 808ConfigCache::ConfigCache(unsigned numEntries, unsigned _associativity, 809 const std::string &policy) 810: 811 SMMUv3BaseCache(policy, CONFIGCACHE_SEED), 812 associativity(_associativity) 813{ 814 if (associativity == 0) 815 associativity = numEntries; // fully associative 816 817 if (numEntries == 0) 818 fatal("ConfigCache must have at least one entry\n"); 819 820 if (associativity > numEntries) 821 fatal("ConfigCache associativity cannot be higher than " 822 "its number of entries\n"); 823 824 unsigned num_sets = numEntries / associativity; 825 826 if (num_sets*associativity != numEntries) 827 fatal("Number of ConfigCache entries must be divisible " 828 "by its associativity\n"); 829 830 Entry e; 831 e.valid = false; 832 833 Set set(associativity, e); 834 sets.resize(num_sets, set); 835} 836 837const ConfigCache::Entry * 838ConfigCache::lookup(uint32_t sid, uint32_t ssid, bool updStats) 839{ 840 const Entry *result = NULL; 841 842 Set &set = sets[pickSetIdx(sid, ssid)]; 843 844 for (size_t i = 0; i < set.size(); i++) { 845 const Entry &e = set[i]; 846 847 if (e.valid && e.sid==sid && e.ssid==ssid) 848 { 849 if (result != NULL) 850 panic("ConfigCache: duplicate entry found!\n"); 851 852 result = &e; 853 break; 854 } 855 } 856 857 if (updStats) { 858 if (result) 859 result->lastUsed = useStamp++; 860 861 totalLookups++; 862 if (result == NULL) 863 totalMisses++; 864 } 865 866 return result; 867} 868 869void 870ConfigCache::store(const Entry &incoming) 871{ 872 if (!incoming.valid) 873 panic("Tried to store an invalid entry\n"); 874 875 incoming.lastUsed = 0; 876 877 const Entry *existing = lookup(incoming.sid, incoming.ssid, false); 878 879 if (existing) { 880 *const_cast<Entry *> (existing) = incoming; 881 } else { 882 Set &set = sets[pickSetIdx(incoming.sid, incoming.ssid)]; 883 set[pickEntryIdxToReplace(set)] = incoming; 884 } 885 886 totalUpdates++; 887} 888 889void 890ConfigCache::invalidateSSID(uint32_t sid, uint32_t ssid) 891{ 892 Set &set = sets[pickSetIdx(sid, ssid)]; 893 894 for (size_t i = 0; i < set.size(); i++) { 895 Entry &e = set[i]; 896 897 if (e.sid==sid && e.ssid==ssid) 898 e.valid = false; 899 } 900} 901 902void 903ConfigCache::invalidateSID(uint32_t sid) 904{ 905 for (size_t s = 0; s < sets.size(); s++) { 906 Set &set = sets[s]; 907 908 for (size_t i = 0; i < set.size(); i++) { 909 Entry &e = set[i]; 910 911 if (e.sid == sid) 912 e.valid = false; 913 } 914 } 915} 916 917void 918ConfigCache::invalidateAll() 919{ 920 for (size_t s = 0; s < sets.size(); s++) { 921 Set &set = sets[s]; 922 923 for (size_t i = 0; i < set.size(); i++) 924 set[i].valid = false; 925 } 926} 927 928size_t 929ConfigCache::pickSetIdx(uint32_t sid, uint32_t ssid) const 930{ 931 return (sid^ssid) % sets.size(); 932} 933 934size_t 935ConfigCache::pickEntryIdxToReplace(const Set &set) 936{ 937 size_t lru_idx = 0; 938 uint32_t lru_tick = UINT32_MAX; 939 940 for (size_t i = 0; i < set.size(); i++) { 941 if (!set[i].valid) { 942 insertions++; 943 return i; 944 } 945 946 if (set[i].lastUsed < lru_tick) { 947 lru_idx = i; 948 lru_tick = set[i].lastUsed; 949 } 950 } 951 952 switch (replacementPolicy) { 953 case SMMU_CACHE_REPL_ROUND_ROBIN: 954 return nextToReplace = ((nextToReplace+1) % associativity); 955 956 case SMMU_CACHE_REPL_RANDOM: 957 return random.random<size_t>(0, associativity-1); 958 959 case SMMU_CACHE_REPL_LRU: 960 return lru_idx; 961 962 default: 963 panic("Unknown replacement policy %d\n", replacementPolicy); 964 } 965 966} 967 968/* 969 * WalkCache 970 */ 971 972WalkCache::WalkCache(const std::array<unsigned, 2*WALK_CACHE_LEVELS> &_sizes, 973 unsigned _associativity, const std::string &policy) : 974 SMMUv3BaseCache(policy, WALKCACHE_SEED), 975 associativity(_associativity), 976 sizes() 977{ 978 unsigned numEntries = std::accumulate(&_sizes[0], 979 &_sizes[2*WALK_CACHE_LEVELS], 0); 980 981 if (associativity == 0) 982 associativity = numEntries; // fully associative 983 984 if (numEntries == 0) 985 fatal("WalkCache must have at least one entry\n"); 986 987 for (size_t i = 0; i < 2*WALK_CACHE_LEVELS; i++){ 988 if (_sizes[i] % associativity != 0) 989 fatal("Number of WalkCache entries at each level must be " 990 "divisible by WalkCache associativity\n"); 991 992 sizes[i] = _sizes[i] / associativity; 993 offsets[i] = i==0 ? 0 : offsets[i-1] + sizes[i-1]; 994 } 995 996 if (associativity > numEntries) 997 fatal("WalkCache associativity cannot be higher than " 998 "its number of entries\n"); 999 1000 unsigned num_sets = numEntries / associativity; 1001 1002 if (num_sets*associativity != numEntries) 1003 fatal("Number of WalkCache entries must be divisible " 1004 "by its associativity\n"); 1005 1006 Entry e; 1007 e.valid = false; 1008 1009 Set set(associativity, e); 1010 sets.resize(num_sets, set); 1011} 1012 1013const WalkCache::Entry* 1014WalkCache::lookup(Addr va, Addr vaMask, 1015 uint16_t asid, uint16_t vmid, 1016 unsigned stage, unsigned level, 1017 bool updStats) 1018{ 1019 const Entry *result = NULL; 1020 1021 Set &set = sets[pickSetIdx(va, vaMask, stage, level)]; 1022 1023 for (size_t i = 0; i < set.size(); i++) { 1024 const Entry &e = set[i]; 1025 1026 if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) && 1027 e.asid==asid && e.vmid==vmid && e.stage==stage && e.level==level) 1028 { 1029 if (result != NULL) 1030 panic("WalkCache: duplicate entry found!\n"); 1031 1032 result = &e; 1033 break; 1034 } 1035 } 1036 1037 if (updStats) { 1038 if (result) 1039 result->lastUsed = useStamp++; 1040 1041 totalLookups++; 1042 if (result == NULL) 1043 totalMisses++; 1044 1045 lookupsByStageLevel[stage-1][level]++; 1046 totalLookupsByStageLevel[stage-1][level]++; 1047 if (result == NULL) { 1048 missesByStageLevel[stage-1][level]++; 1049 totalMissesByStageLevel[stage-1][level]++; 1050 } 1051 } 1052 1053 return result; 1054} 1055 1056void 1057WalkCache::store(const Entry &incoming) 1058{ 1059 if (!incoming.valid) 1060 panic("Tried to store an invalid entry\n"); 1061 1062 assert(incoming.stage==1 || incoming.stage==2); 1063 assert(incoming.level<=WALK_CACHE_LEVELS); 1064 1065 incoming.lastUsed = 0; 1066 1067 const Entry *existing = lookup(incoming.va, incoming.vaMask, 1068 incoming.asid, incoming.vmid, 1069 incoming.stage, incoming.level, false); 1070 1071 if (existing) { 1072 *const_cast<Entry *> (existing) = incoming; 1073 } else { 1074 Set &set = sets[pickSetIdx(incoming.va, incoming.vaMask, 1075 incoming.stage, incoming.level)]; 1076 set[pickEntryIdxToReplace(set, incoming.stage, incoming.level)] = 1077 incoming; 1078 } 1079 1080 totalUpdates++; 1081 updatesByStageLevel[incoming.stage-1][incoming.level]++; 1082 totalUpdatesByStageLevel[incoming.stage-1][incoming.level]++; 1083} 1084 1085void 1086WalkCache::invalidateVA(Addr va, uint16_t asid, uint16_t vmid, 1087 const bool leaf_only) 1088{ 1089 for (size_t s = 0; s < sets.size(); s++) { 1090 Set &set = sets[s]; 1091 1092 for (size_t i = 0; i < set.size(); i++) { 1093 Entry &e = set[i]; 1094 1095 if ((!leaf_only || e.leaf) && (e.va & e.vaMask) == (va & e.vaMask) 1096 && e.asid == asid && e.vmid == vmid) 1097 { 1098 e.valid = false; 1099 } 1100 } 1101 } 1102} 1103 1104void 1105WalkCache::invalidateVAA(Addr va, uint16_t vmid, const bool leaf_only) 1106{ 1107 for (size_t s = 0; s < sets.size(); s++) { 1108 Set &set = sets[s]; 1109 1110 for (size_t i = 0; i < set.size(); i++) { 1111 Entry &e = set[i]; 1112 1113 if ((!leaf_only || e.leaf) && (e.va & e.vaMask) == (va & e.vaMask) 1114 && e.vmid == vmid) 1115 { 1116 e.valid = false; 1117 } 1118 } 1119 } 1120} 1121 1122void 1123WalkCache::invalidateASID(uint16_t asid, uint16_t vmid) 1124{ 1125 for (size_t s = 0; s < sets.size(); s++) { 1126 Set &set = sets[s]; 1127 1128 for (size_t i = 0; i < set.size(); i++) { 1129 Entry &e = set[i]; 1130 1131 if (e.asid==asid && e.vmid==vmid) 1132 e.valid = false; 1133 } 1134 } 1135} 1136 1137void 1138WalkCache::invalidateVMID(uint16_t vmid) 1139{ 1140 for (size_t s = 0; s < sets.size(); s++) { 1141 Set &set = sets[s]; 1142 1143 for (size_t i = 0; i < set.size(); i++) { 1144 Entry &e = set[i]; 1145 1146 if (e.vmid == vmid) 1147 e.valid = false; 1148 } 1149 } 1150} 1151 1152void 1153WalkCache::invalidateAll() 1154{ 1155 for (size_t s = 0; s < sets.size(); s++) { 1156 Set &set = sets[s]; 1157 1158 for (size_t i = 0; i < set.size(); i++) 1159 set[i].valid = false; 1160 } 1161} 1162 1163size_t 1164WalkCache::pickSetIdx(Addr va, Addr vaMask, 1165 unsigned stage, unsigned level) const 1166{ 1167 (void) stage; 1168 1169 int size, offset; 1170 1171 switch (stage) { 1172 case 1: 1173 assert (level<=3); 1174 size = sizes[0*WALK_CACHE_LEVELS + level]; 1175 offset = offsets[0*WALK_CACHE_LEVELS + level]; 1176 break; 1177 1178 case 2: 1179 assert (level<=3); 1180 size = sizes[1*WALK_CACHE_LEVELS + level]; 1181 offset = offsets[1*WALK_CACHE_LEVELS + level]; 1182 break; 1183 1184 default: 1185 panic("bad stage"); 1186 } 1187 1188 return ((va >> findLsbSet(vaMask)) % size) + offset; 1189} 1190 1191size_t 1192WalkCache::pickEntryIdxToReplace(const Set &set, 1193 unsigned stage, unsigned level) 1194{ 1195 size_t lru_idx = 0; 1196 uint32_t lru_tick = UINT32_MAX; 1197 1198 for (size_t i = 0; i < set.size(); i++) { 1199 if (!set[i].valid) { 1200 insertions++; 1201 insertionsByStageLevel[stage-1][level]++; 1202 return i; 1203 } 1204 1205 if (set[i].lastUsed < lru_tick) { 1206 lru_idx = i; 1207 lru_tick = set[i].lastUsed; 1208 } 1209 } 1210 1211 switch (replacementPolicy) { 1212 case SMMU_CACHE_REPL_ROUND_ROBIN: 1213 return nextToReplace = ((nextToReplace+1) % associativity); 1214 1215 case SMMU_CACHE_REPL_RANDOM: 1216 return random.random<size_t>(0, associativity-1); 1217 1218 case SMMU_CACHE_REPL_LRU: 1219 return lru_idx; 1220 1221 default: 1222 panic("Unknown replacement policy %d\n", replacementPolicy); 1223 } 1224 1225} 1226 1227void 1228WalkCache::regStats(const std::string &name) 1229{ 1230 using namespace Stats; 1231 1232 SMMUv3BaseCache::regStats(name); 1233 1234 for (int s = 0; s < 2; s++) { 1235 for (int l = 0; l < WALK_CACHE_LEVELS; l++) { 1236 averageLookupsByStageLevel[s][l] 1237 .name(csprintf("%s.averageLookupsS%dL%d", name, s+1, l)) 1238 .desc("Average number lookups per second") 1239 .flags(pdf); 1240 1241 totalLookupsByStageLevel[s][l] 1242 .name(csprintf("%s.totalLookupsS%dL%d", name, s+1, l)) 1243 .desc("Total number of lookups") 1244 .flags(pdf); 1245 1246 averageLookupsByStageLevel[s][l] = 1247 totalLookupsByStageLevel[s][l] / simSeconds; 1248 1249 1250 averageMissesByStageLevel[s][l] 1251 .name(csprintf("%s.averageMissesS%dL%d", name, s+1, l)) 1252 .desc("Average number misses per second") 1253 .flags(pdf); 1254 1255 totalMissesByStageLevel[s][l] 1256 .name(csprintf("%s.totalMissesS%dL%d", name, s+1, l)) 1257 .desc("Total number of misses") 1258 .flags(pdf); 1259 1260 averageMissesByStageLevel[s][l] = 1261 totalMissesByStageLevel[s][l] / simSeconds; 1262 1263 1264 averageUpdatesByStageLevel[s][l] 1265 .name(csprintf("%s.averageUpdatesS%dL%d", name, s+1, l)) 1266 .desc("Average number updates per second") 1267 .flags(pdf); 1268 1269 totalUpdatesByStageLevel[s][l] 1270 .name(csprintf("%s.totalUpdatesS%dL%d", name, s+1, l)) 1271 .desc("Total number of updates") 1272 .flags(pdf); 1273 1274 averageUpdatesByStageLevel[s][l] = 1275 totalUpdatesByStageLevel[s][l] / simSeconds; 1276 1277 1278 averageHitRateByStageLevel[s][l] 1279 .name(csprintf("%s.averageHitRateS%dL%d", name, s+1, l)) 1280 .desc("Average hit rate") 1281 .flags(pdf); 1282 1283 averageHitRateByStageLevel[s][l] = 1284 (totalLookupsByStageLevel[s][l] - 1285 totalMissesByStageLevel[s][l]) 1286 / totalLookupsByStageLevel[s][l]; 1287 1288 insertionsByStageLevel[s][l] 1289 .name(csprintf("%s.insertionsS%dL%d", name, s+1, l)) 1290 .desc("Number of insertions (not replacements)") 1291 .flags(pdf); 1292 } 1293 } 1294} 1295