gic_v3_its.cc revision 14180
1/* 2 * Copyright (c) 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: Giacomo Travaglini 38 */ 39 40#include "dev/arm/gic_v3_its.hh" 41 42#include "debug/AddrRanges.hh" 43#include "debug/Drain.hh" 44#include "debug/GIC.hh" 45#include "debug/ITS.hh" 46#include "dev/arm/gic_v3.hh" 47#include "dev/arm/gic_v3_distributor.hh" 48#include "dev/arm/gic_v3_redistributor.hh" 49#include "mem/packet_access.hh" 50 51#define COMMAND(x, method) { x, DispatchEntry(#x, method) } 52 53const AddrRange Gicv3Its::GITS_BASER(0x0100, 0x0138); 54 55ItsProcess::ItsProcess(Gicv3Its &_its) 56 : its(_its), coroutine(nullptr) 57{ 58} 59 60ItsProcess::~ItsProcess() 61{ 62} 63 64void 65ItsProcess::reinit() 66{ 67 coroutine.reset(new Coroutine( 68 std::bind(&ItsProcess::main, this, std::placeholders::_1))); 69} 70 71const std::string 72ItsProcess::name() const 73{ 74 return its.name(); 75} 76 77ItsAction 78ItsProcess::run(PacketPtr pkt) 79{ 80 assert(coroutine != nullptr); 81 assert(*coroutine); 82 return (*coroutine)(pkt).get(); 83} 84 85void 86ItsProcess::doRead(Yield &yield, Addr addr, void *ptr, size_t size) 87{ 88 ItsAction a; 89 a.type = ItsActionType::SEND_REQ; 90 91 RequestPtr req = std::make_shared<Request>( 92 addr, size, 0, its.masterId); 93 94 req->taskId(ContextSwitchTaskId::DMA); 95 96 a.pkt = new Packet(req, MemCmd::ReadReq); 97 a.pkt->dataStatic(ptr); 98 99 a.delay = 0; 100 101 PacketPtr pkt = yield(a).get(); 102 103 assert(pkt); 104 assert(pkt->getSize() >= size); 105 106 delete pkt; 107} 108 109void 110ItsProcess::doWrite(Yield &yield, Addr addr, void *ptr, size_t size) 111{ 112 ItsAction a; 113 a.type = ItsActionType::SEND_REQ; 114 115 RequestPtr req = std::make_shared<Request>( 116 addr, size, 0, its.masterId); 117 118 req->taskId(ContextSwitchTaskId::DMA); 119 120 a.pkt = new Packet(req, MemCmd::WriteReq); 121 a.pkt->dataStatic(ptr); 122 123 a.delay = 0; 124 125 PacketPtr pkt = yield(a).get(); 126 127 assert(pkt); 128 assert(pkt->getSize() >= size); 129 130 delete pkt; 131} 132 133void 134ItsProcess::terminate(Yield &yield) 135{ 136 ItsAction a; 137 a.type = ItsActionType::TERMINATE; 138 a.pkt = NULL; 139 a.delay = 0; 140 yield(a); 141} 142 143void 144ItsProcess::writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte) 145{ 146 const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE); 147 const Addr address = base + device_id; 148 149 DPRINTF(ITS, "Writing DTE at address %#x: %#x\n", address, dte); 150 151 doWrite(yield, address, &dte, sizeof(dte)); 152} 153 154void 155ItsProcess::writeIrqTranslationTable( 156 Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte) 157{ 158 const Addr address = itt_base + event_id; 159 160 doWrite(yield, address, &itte, sizeof(itte)); 161 162 DPRINTF(ITS, "Writing ITTE at address %#x: %#x\n", address, itte); 163} 164 165void 166ItsProcess::writeIrqCollectionTable( 167 Yield &yield, uint32_t collection_id, CTE cte) 168{ 169 const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE); 170 const Addr address = base + collection_id; 171 172 doWrite(yield, address, &cte, sizeof(cte)); 173 174 DPRINTF(ITS, "Writing CTE at address %#x: %#x\n", address, cte); 175} 176 177uint64_t 178ItsProcess::readDeviceTable(Yield &yield, uint32_t device_id) 179{ 180 const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE); 181 const Addr address = base + device_id; 182 183 uint64_t dte; 184 doRead(yield, address, &dte, sizeof(dte)); 185 186 DPRINTF(ITS, "Reading DTE at address %#x: %#x\n", address, dte); 187 return dte; 188} 189 190uint64_t 191ItsProcess::readIrqTranslationTable( 192 Yield &yield, const Addr itt_base, uint32_t event_id) 193{ 194 const Addr address = itt_base + event_id; 195 196 uint64_t itte; 197 doRead(yield, address, &itte, sizeof(itte)); 198 199 DPRINTF(ITS, "Reading ITTE at address %#x: %#x\n", address, itte); 200 return itte; 201} 202 203uint64_t 204ItsProcess::readIrqCollectionTable(Yield &yield, uint32_t collection_id) 205{ 206 const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE); 207 const Addr address = base + collection_id; 208 209 uint64_t cte; 210 doRead(yield, address, &cte, sizeof(cte)); 211 212 DPRINTF(ITS, "Reading CTE at address %#x: %#x\n", address, cte); 213 return cte; 214} 215 216ItsTranslation::ItsTranslation(Gicv3Its &_its) 217 : ItsProcess(_its) 218{ 219 reinit(); 220 its.pendingTranslations++; 221} 222 223ItsTranslation::~ItsTranslation() 224{ 225 assert(its.pendingTranslations >= 1); 226 its.pendingTranslations--; 227} 228 229void 230ItsTranslation::main(Yield &yield) 231{ 232 PacketPtr pkt = yield.get(); 233 234 const uint32_t device_id = pkt->req->streamId(); 235 const uint32_t event_id = pkt->getLE<uint32_t>(); 236 237 auto result = translateLPI(yield, device_id, event_id); 238 239 uint32_t intid = result.first; 240 Gicv3Redistributor *redist = result.second; 241 242 // Set the LPI in the redistributor 243 redist->setClrLPI(intid, true); 244 245 // Update the value in GITS_TRANSLATER only once we know 246 // there was no error in the tranlation process (before 247 // terminating the translation 248 its.gitsTranslater = event_id; 249 250 terminate(yield); 251} 252 253std::pair<uint32_t, Gicv3Redistributor *> 254ItsTranslation::translateLPI(Yield &yield, uint32_t device_id, 255 uint32_t event_id) 256{ 257 if (its.deviceOutOfRange(device_id)) { 258 terminate(yield); 259 } 260 261 DTE dte = readDeviceTable(yield, device_id); 262 263 if (!dte.valid || its.idOutOfRange(event_id, dte.ittRange)) { 264 terminate(yield); 265 } 266 267 ITTE itte = readIrqTranslationTable(yield, dte.ittAddress, event_id); 268 const auto collection_id = itte.icid; 269 270 if (!itte.valid || its.collectionOutOfRange(collection_id)) { 271 terminate(yield); 272 } 273 274 CTE cte = readIrqCollectionTable(yield, collection_id); 275 276 if (!cte.valid) { 277 terminate(yield); 278 } 279 280 // Returning the INTID and the target Redistributor 281 return std::make_pair(itte.intNum, its.getRedistributor(cte)); 282} 283 284ItsCommand::DispatchTable ItsCommand::cmdDispatcher = 285{ 286 COMMAND(CLEAR, &ItsCommand::clear), 287 COMMAND(DISCARD, &ItsCommand::discard), 288 COMMAND(INT, &ItsCommand::doInt), 289 COMMAND(INV, &ItsCommand::inv), 290 COMMAND(INVALL, &ItsCommand::invall), 291 COMMAND(MAPC, &ItsCommand::mapc), 292 COMMAND(MAPD, &ItsCommand::mapd), 293 COMMAND(MAPI, &ItsCommand::mapi), 294 COMMAND(MAPTI, &ItsCommand::mapti), 295 COMMAND(MOVALL, &ItsCommand::movall), 296 COMMAND(MOVI, &ItsCommand::movi), 297 COMMAND(SYNC, &ItsCommand::sync), 298 COMMAND(VINVALL, &ItsCommand::vinvall), 299 COMMAND(VMAPI, &ItsCommand::vmapi), 300 COMMAND(VMAPP, &ItsCommand::vmapp), 301 COMMAND(VMAPTI, &ItsCommand::vmapti), 302 COMMAND(VMOVI, &ItsCommand::vmovi), 303 COMMAND(VMOVP, &ItsCommand::vmovp), 304 COMMAND(VSYNC, &ItsCommand::vsync), 305}; 306 307ItsCommand::ItsCommand(Gicv3Its &_its) 308 : ItsProcess(_its) 309{ 310 reinit(); 311 its.pendingCommands = true; 312} 313 314ItsCommand::~ItsCommand() 315{ 316 its.pendingCommands = false; 317} 318 319std::string 320ItsCommand::commandName(uint32_t cmd) 321{ 322 const auto entry = cmdDispatcher.find(cmd); 323 return entry != cmdDispatcher.end() ? entry->second.name : "INVALID"; 324} 325 326void 327ItsCommand::main(Yield &yield) 328{ 329 ItsAction a; 330 a.type = ItsActionType::INITIAL_NOP; 331 a.pkt = nullptr; 332 a.delay = 0; 333 yield(a); 334 335 while (its.gitsCwriter.offset != its.gitsCreadr.offset) { 336 CommandEntry command; 337 338 // Reading the command from CMDQ 339 readCommand(yield, command); 340 341 processCommand(yield, command); 342 343 its.incrementReadPointer(); 344 } 345 346 terminate(yield); 347} 348 349void 350ItsCommand::readCommand(Yield &yield, CommandEntry &command) 351{ 352 // read the command pointed by GITS_CREADR 353 const Addr cmd_addr = 354 (its.gitsCbaser.physAddr << 12) + (its.gitsCreadr.offset << 5); 355 356 doRead(yield, cmd_addr, &command, sizeof(command)); 357 358 DPRINTF(ITS, "Command %s read from queue at address: %#x\n", 359 commandName(command.type), cmd_addr); 360 DPRINTF(ITS, "dw0: %#x dw1: %#x dw2: %#x dw3: %#x\n", 361 command.raw[0], command.raw[1], command.raw[2], command.raw[3]); 362} 363 364void 365ItsCommand::processCommand(Yield &yield, CommandEntry &command) 366{ 367 const auto entry = cmdDispatcher.find(command.type); 368 369 if (entry != cmdDispatcher.end()) { 370 // Execute the command 371 entry->second.exec(this, yield, command); 372 } else { 373 panic("Unrecognized command type: %u", command.type); 374 } 375} 376 377void 378ItsCommand::clear(Yield &yield, CommandEntry &command) 379{ 380 if (deviceOutOfRange(command)) { 381 its.incrementReadPointer(); 382 terminate(yield); 383 } 384 385 DTE dte = readDeviceTable(yield, command.deviceId); 386 387 if (!dte.valid || idOutOfRange(command, dte)) { 388 its.incrementReadPointer(); 389 terminate(yield); 390 } 391 392 ITTE itte = readIrqTranslationTable( 393 yield, dte.ittAddress, command.eventId); 394 395 if (!itte.valid) { 396 its.incrementReadPointer(); 397 terminate(yield); 398 } 399 400 const auto collection_id = itte.icid; 401 CTE cte = readIrqCollectionTable(yield, collection_id); 402 403 if (!cte.valid) { 404 its.incrementReadPointer(); 405 terminate(yield); 406 } 407 408 // Clear the LPI in the redistributor 409 its.getRedistributor(cte)->setClrLPI(itte.intNum, false); 410} 411 412void 413ItsCommand::discard(Yield &yield, CommandEntry &command) 414{ 415 if (deviceOutOfRange(command)) { 416 its.incrementReadPointer(); 417 terminate(yield); 418 } 419 420 DTE dte = readDeviceTable(yield, command.deviceId); 421 422 if (!dte.valid || idOutOfRange(command, dte)) { 423 its.incrementReadPointer(); 424 terminate(yield); 425 } 426 427 ITTE itte = readIrqTranslationTable( 428 yield, dte.ittAddress, command.eventId); 429 430 if (!itte.valid) { 431 its.incrementReadPointer(); 432 terminate(yield); 433 } 434 435 const auto collection_id = itte.icid; 436 Gicv3Its::CTE cte = readIrqCollectionTable(yield, collection_id); 437 438 if (!cte.valid) { 439 its.incrementReadPointer(); 440 terminate(yield); 441 } 442 443 its.getRedistributor(cte)->setClrLPI(itte.intNum, false); 444 445 // Then removes the mapping from the ITT (invalidating) 446 itte.valid = 0; 447 writeIrqTranslationTable( 448 yield, dte.ittAddress, command.eventId, itte); 449} 450 451void 452ItsCommand::doInt(Yield &yield, CommandEntry &command) 453{ 454 if (deviceOutOfRange(command)) { 455 its.incrementReadPointer(); 456 terminate(yield); 457 } 458 459 DTE dte = readDeviceTable(yield, command.deviceId); 460 461 if (!dte.valid || idOutOfRange(command, dte)) { 462 its.incrementReadPointer(); 463 terminate(yield); 464 } 465 466 ITTE itte = readIrqTranslationTable( 467 yield, dte.ittAddress, command.eventId); 468 469 if (!itte.valid) { 470 its.incrementReadPointer(); 471 terminate(yield); 472 } 473 474 const auto collection_id = itte.icid; 475 CTE cte = readIrqCollectionTable(yield, collection_id); 476 477 if (!cte.valid) { 478 its.incrementReadPointer(); 479 terminate(yield); 480 } 481 482 // Set the LPI in the redistributor 483 its.getRedistributor(cte)->setClrLPI(itte.intNum, true); 484} 485 486void 487ItsCommand::inv(Yield &yield, CommandEntry &command) 488{ 489 if (deviceOutOfRange(command)) { 490 its.incrementReadPointer(); 491 terminate(yield); 492 } 493 494 DTE dte = readDeviceTable(yield, command.deviceId); 495 496 if (!dte.valid || idOutOfRange(command, dte)) { 497 its.incrementReadPointer(); 498 terminate(yield); 499 } 500 501 ITTE itte = readIrqTranslationTable( 502 yield, dte.ittAddress, command.eventId); 503 504 if (!itte.valid) { 505 its.incrementReadPointer(); 506 terminate(yield); 507 } 508 509 const auto collection_id = itte.icid; 510 CTE cte = readIrqCollectionTable(yield, collection_id); 511 512 if (!cte.valid) { 513 its.incrementReadPointer(); 514 terminate(yield); 515 } 516 // Do nothing since caching is currently not supported in 517 // Redistributor 518} 519 520void 521ItsCommand::invall(Yield &yield, CommandEntry &command) 522{ 523 if (collectionOutOfRange(command)) { 524 its.incrementReadPointer(); 525 terminate(yield); 526 } 527 528 const auto icid = bits(command.raw[2], 15, 0); 529 530 CTE cte = readIrqCollectionTable(yield, icid); 531 532 if (!cte.valid) { 533 its.incrementReadPointer(); 534 terminate(yield); 535 } 536 // Do nothing since caching is currently not supported in 537 // Redistributor 538} 539 540void 541ItsCommand::mapc(Yield &yield, CommandEntry &command) 542{ 543 if (collectionOutOfRange(command)) { 544 its.incrementReadPointer(); 545 terminate(yield); 546 } 547 548 CTE cte = 0; 549 cte.valid = bits(command.raw[2], 63); 550 cte.rdBase = bits(command.raw[2], 50, 16); 551 552 const auto icid = bits(command.raw[2], 15, 0); 553 554 writeIrqCollectionTable(yield, icid, cte); 555} 556 557void 558ItsCommand::mapd(Yield &yield, CommandEntry &command) 559{ 560 if (deviceOutOfRange(command) || sizeOutOfRange(command)) { 561 its.incrementReadPointer(); 562 terminate(yield); 563 } 564 565 DTE dte = 0; 566 dte.valid = bits(command.raw[2], 63); 567 dte.ittAddress = mbits(command.raw[2], 51, 8); 568 dte.ittRange = bits(command.raw[1], 4, 0); 569 570 writeDeviceTable(yield, command.deviceId, dte); 571} 572 573void 574ItsCommand::mapi(Yield &yield, CommandEntry &command) 575{ 576 if (deviceOutOfRange(command)) { 577 its.incrementReadPointer(); 578 terminate(yield); 579 } 580 581 if (collectionOutOfRange(command)) { 582 its.incrementReadPointer(); 583 terminate(yield); 584 } 585 586 DTE dte = readDeviceTable(yield, command.deviceId); 587 588 if (!dte.valid || idOutOfRange(command, dte) || 589 its.lpiOutOfRange(command.eventId)) { 590 591 its.incrementReadPointer(); 592 terminate(yield); 593 } 594 595 Gicv3Its::ITTE itte = readIrqTranslationTable( 596 yield, dte.ittAddress, command.eventId); 597 598 itte.valid = 1; 599 itte.intType = Gicv3Its::PHYSICAL_INTERRUPT; 600 itte.intNum = command.eventId; 601 itte.icid = bits(command.raw[2], 15, 0); 602 603 writeIrqTranslationTable( 604 yield, dte.ittAddress, command.eventId, itte); 605} 606 607void 608ItsCommand::mapti(Yield &yield, CommandEntry &command) 609{ 610 if (deviceOutOfRange(command)) { 611 its.incrementReadPointer(); 612 terminate(yield); 613 } 614 615 if (collectionOutOfRange(command)) { 616 its.incrementReadPointer(); 617 terminate(yield); 618 } 619 620 DTE dte = readDeviceTable(yield, command.deviceId); 621 622 const auto pintid = bits(command.raw[1], 63, 32); 623 624 if (!dte.valid || idOutOfRange(command, dte) || 625 its.lpiOutOfRange(pintid)) { 626 627 its.incrementReadPointer(); 628 terminate(yield); 629 } 630 631 ITTE itte = readIrqTranslationTable( 632 yield, dte.ittAddress, command.eventId); 633 634 itte.valid = 1; 635 itte.intType = Gicv3Its::PHYSICAL_INTERRUPT; 636 itte.intNum = pintid; 637 itte.icid = bits(command.raw[2], 15, 0); 638 639 writeIrqTranslationTable( 640 yield, dte.ittAddress, command.eventId, itte); 641} 642 643void 644ItsCommand::movall(Yield &yield, CommandEntry &command) 645{ 646 const uint64_t rd1 = bits(command.raw[2], 50, 16); 647 const uint64_t rd2 = bits(command.raw[3], 50, 16); 648 649 if (rd1 != rd2) { 650 Gicv3Redistributor * redist1 = its.getRedistributor(rd1); 651 Gicv3Redistributor * redist2 = its.getRedistributor(rd2); 652 653 its.moveAllPendingState(redist1, redist2); 654 } 655} 656 657void 658ItsCommand::movi(Yield &yield, CommandEntry &command) 659{ 660 if (deviceOutOfRange(command)) { 661 its.incrementReadPointer(); 662 terminate(yield); 663 } 664 665 if (collectionOutOfRange(command)) { 666 its.incrementReadPointer(); 667 terminate(yield); 668 } 669 670 DTE dte = readDeviceTable(yield, command.deviceId); 671 672 if (!dte.valid || idOutOfRange(command, dte)) { 673 its.incrementReadPointer(); 674 terminate(yield); 675 } 676 677 ITTE itte = readIrqTranslationTable( 678 yield, dte.ittAddress, command.eventId); 679 680 if (!itte.valid || itte.intType == Gicv3Its::VIRTUAL_INTERRUPT) { 681 its.incrementReadPointer(); 682 terminate(yield); 683 } 684 685 const auto collection_id1 = itte.icid; 686 CTE cte1 = readIrqCollectionTable(yield, collection_id1); 687 688 if (!cte1.valid) { 689 its.incrementReadPointer(); 690 terminate(yield); 691 } 692 693 const auto collection_id2 = bits(command.raw[2], 15, 0); 694 CTE cte2 = readIrqCollectionTable(yield, collection_id2); 695 696 if (!cte2.valid) { 697 its.incrementReadPointer(); 698 terminate(yield); 699 } 700 701 Gicv3Redistributor *first_redist = its.getRedistributor(cte1); 702 Gicv3Redistributor *second_redist = its.getRedistributor(cte2); 703 704 if (second_redist != first_redist) { 705 // move pending state of the interrupt from one redistributor 706 // to the other. 707 if (first_redist->isPendingLPI(itte.intNum)) { 708 first_redist->setClrLPI(itte.intNum, false); 709 second_redist->setClrLPI(itte.intNum, true); 710 } 711 } 712 713 itte.icid = collection_id2; 714 writeIrqTranslationTable( 715 yield, dte.ittAddress, command.eventId, itte); 716} 717 718void 719ItsCommand::sync(Yield &yield, CommandEntry &command) 720{ 721 warn("ITS %s command unimplemented", __func__); 722} 723 724void 725ItsCommand::vinvall(Yield &yield, CommandEntry &command) 726{ 727 panic("ITS %s command unimplemented", __func__); 728} 729 730void 731ItsCommand::vmapi(Yield &yield, CommandEntry &command) 732{ 733 panic("ITS %s command unimplemented", __func__); 734} 735 736void 737ItsCommand::vmapp(Yield &yield, CommandEntry &command) 738{ 739 panic("ITS %s command unimplemented", __func__); 740} 741 742void 743ItsCommand::vmapti(Yield &yield, CommandEntry &command) 744{ 745 panic("ITS %s command unimplemented", __func__); 746} 747 748void 749ItsCommand::vmovi(Yield &yield, CommandEntry &command) 750{ 751 panic("ITS %s command unimplemented", __func__); 752} 753 754void 755ItsCommand::vmovp(Yield &yield, CommandEntry &command) 756{ 757 panic("ITS %s command unimplemented", __func__); 758} 759 760void 761ItsCommand::vsync(Yield &yield, CommandEntry &command) 762{ 763 panic("ITS %s command unimplemented", __func__); 764} 765 766Gicv3Its::Gicv3Its(const Gicv3ItsParams *params) 767 : BasicPioDevice(params, params->pio_size), 768 dmaPort(name() + ".dma", *this), 769 gitsControl(0x1), 770 gitsTyper(params->gits_typer), 771 gitsCbaser(0), gitsCreadr(0), 772 gitsCwriter(0), gitsIidr(0), 773 masterId(params->system->getMasterId(this)), 774 gic(nullptr), 775 commandEvent([this] { checkCommandQueue(); }, name()), 776 pendingCommands(false), 777 pendingTranslations(0) 778{ 779 for (auto idx = 0; idx < NUM_BASER_REGS; idx++) { 780 BASER gits_baser = 0; 781 gits_baser.type = idx; 782 gits_baser.entrySize = sizeof(uint64_t) - 1; 783 tableBases.push_back(gits_baser); 784 } 785} 786 787void 788Gicv3Its::setGIC(Gicv3 *_gic) 789{ 790 assert(!gic); 791 gic = _gic; 792} 793 794AddrRangeList 795Gicv3Its::getAddrRanges() const 796{ 797 assert(pioSize != 0); 798 AddrRangeList ranges; 799 DPRINTF(AddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize); 800 ranges.push_back(RangeSize(pioAddr, pioSize)); 801 return ranges; 802} 803 804Tick 805Gicv3Its::read(PacketPtr pkt) 806{ 807 const Addr addr = pkt->getAddr() - pioAddr; 808 uint64_t value = 0; 809 810 DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr); 811 812 switch (addr) { 813 case GITS_CTLR: 814 value = gitsControl; 815 break; 816 817 case GITS_IIDR: 818 value = gitsIidr; 819 break; 820 821 case GITS_TYPER: 822 value = gitsTyper; 823 break; 824 825 case GITS_CBASER: 826 value = gitsCbaser; 827 break; 828 829 case GITS_CBASER + 4: 830 value = gitsCbaser.high; 831 break; 832 833 case GITS_CWRITER: 834 value = gitsCwriter; 835 break; 836 837 case GITS_CWRITER + 4: 838 value = gitsCwriter.high; 839 break; 840 841 case GITS_CREADR: 842 value = gitsCreadr; 843 break; 844 845 case GITS_CREADR + 4: 846 value = gitsCreadr.high; 847 break; 848 849 case GITS_PIDR2: 850 value = gic->getDistributor()->gicdPidr2; 851 break; 852 853 case GITS_TRANSLATER: 854 value = gitsTranslater; 855 break; 856 857 default: 858 if (GITS_BASER.contains(addr)) { 859 auto relative_addr = addr - GITS_BASER.start(); 860 auto baser_index = relative_addr / sizeof(uint64_t); 861 862 value = tableBases[baser_index]; 863 break; 864 } else { 865 panic("Unrecognized register access\n"); 866 } 867 } 868 869 pkt->setUintX(value, LittleEndianByteOrder); 870 pkt->makeAtomicResponse(); 871 return pioDelay; 872} 873 874Tick 875Gicv3Its::write(PacketPtr pkt) 876{ 877 Addr addr = pkt->getAddr() - pioAddr; 878 879 DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr); 880 881 switch (addr) { 882 case GITS_CTLR: 883 assert(pkt->getSize() == sizeof(uint32_t)); 884 gitsControl = pkt->getLE<uint32_t>(); 885 break; 886 887 case GITS_IIDR: 888 panic("GITS_IIDR is Read Only\n"); 889 890 case GITS_TYPER: 891 panic("GITS_TYPER is Read Only\n"); 892 893 case GITS_CBASER: 894 if (pkt->getSize() == sizeof(uint32_t)) { 895 gitsCbaser.low = pkt->getLE<uint32_t>(); 896 } else { 897 assert(pkt->getSize() == sizeof(uint64_t)); 898 gitsCbaser = pkt->getLE<uint64_t>(); 899 } 900 901 gitsCreadr = 0; // Cleared when CBASER gets written 902 903 checkCommandQueue(); 904 break; 905 906 case GITS_CBASER + 4: 907 assert(pkt->getSize() == sizeof(uint32_t)); 908 gitsCbaser.high = pkt->getLE<uint32_t>(); 909 910 gitsCreadr = 0; // Cleared when CBASER gets written 911 912 checkCommandQueue(); 913 break; 914 915 case GITS_CWRITER: 916 if (pkt->getSize() == sizeof(uint32_t)) { 917 gitsCwriter.low = pkt->getLE<uint32_t>(); 918 } else { 919 assert(pkt->getSize() == sizeof(uint64_t)); 920 gitsCwriter = pkt->getLE<uint64_t>(); 921 } 922 923 checkCommandQueue(); 924 break; 925 926 case GITS_CWRITER + 4: 927 assert(pkt->getSize() == sizeof(uint32_t)); 928 gitsCwriter.high = pkt->getLE<uint32_t>(); 929 930 checkCommandQueue(); 931 break; 932 933 case GITS_CREADR: 934 panic("GITS_READR is Read Only\n"); 935 936 case GITS_TRANSLATER: 937 if (gitsControl.enabled) { 938 translate(pkt); 939 } 940 break; 941 942 default: 943 if (GITS_BASER.contains(addr)) { 944 auto relative_addr = addr - GITS_BASER.start(); 945 auto baser_index = relative_addr / sizeof(uint64_t); 946 947 BASER val = pkt->getLE<uint64_t>(); 948 949 panic_if(val.indirect, 950 "We currently don't support two level ITS tables"); 951 952 tableBases[baser_index] = val; 953 break; 954 } else { 955 panic("Unrecognized register access\n"); 956 } 957 } 958 959 pkt->makeAtomicResponse(); 960 return pioDelay; 961} 962 963bool 964Gicv3Its::idOutOfRange(uint32_t event_id, uint8_t itt_range) const 965{ 966 const uint32_t id_bits = gitsTyper.idBits; 967 return event_id >= (1ULL << (id_bits + 1)) || 968 event_id >= ((1ULL << itt_range) + 1); 969} 970 971bool 972Gicv3Its::deviceOutOfRange(uint32_t device_id) const 973{ 974 return device_id >= (1ULL << (gitsTyper.devBits + 1)); 975} 976 977bool 978Gicv3Its::sizeOutOfRange(uint32_t size) const 979{ 980 return size > gitsTyper.idBits; 981} 982 983bool 984Gicv3Its::collectionOutOfRange(uint32_t collection_id) const 985{ 986 // If GITS_TYPER.CIL == 0, ITS supports 16-bit CollectionID 987 // Otherwise, #bits is specified by GITS_TYPER.CIDbits 988 const auto cid_bits = gitsTyper.cil == 0 ? 989 16 : gitsTyper.cidBits + 1; 990 991 return collection_id >= (1ULL << cid_bits); 992} 993 994bool 995Gicv3Its::lpiOutOfRange(uint32_t intid) const 996{ 997 return intid >= (1ULL << (Gicv3Distributor::IDBITS + 1)) || 998 (intid < Gicv3Redistributor::SMALLEST_LPI_ID && 999 intid != Gicv3::INTID_SPURIOUS); 1000} 1001 1002DrainState 1003Gicv3Its::drain() 1004{ 1005 if (!pendingCommands && !pendingTranslations) { 1006 return DrainState::Drained; 1007 } else { 1008 DPRINTF(Drain, "GICv3 ITS not drained\n"); 1009 return DrainState::Draining; 1010 } 1011} 1012 1013void 1014Gicv3Its::serialize(CheckpointOut & cp) const 1015{ 1016 SERIALIZE_SCALAR(gitsControl); 1017 SERIALIZE_SCALAR(gitsTyper); 1018 SERIALIZE_SCALAR(gitsCbaser); 1019 SERIALIZE_SCALAR(gitsCreadr); 1020 SERIALIZE_SCALAR(gitsCwriter); 1021 SERIALIZE_SCALAR(gitsIidr); 1022 1023 SERIALIZE_CONTAINER(tableBases); 1024} 1025 1026void 1027Gicv3Its::unserialize(CheckpointIn & cp) 1028{ 1029 UNSERIALIZE_SCALAR(gitsControl); 1030 UNSERIALIZE_SCALAR(gitsTyper); 1031 UNSERIALIZE_SCALAR(gitsCbaser); 1032 UNSERIALIZE_SCALAR(gitsCreadr); 1033 UNSERIALIZE_SCALAR(gitsCwriter); 1034 UNSERIALIZE_SCALAR(gitsIidr); 1035 1036 UNSERIALIZE_CONTAINER(tableBases); 1037} 1038 1039void 1040Gicv3Its::incrementReadPointer() 1041{ 1042 // Make the reader point to the next element 1043 gitsCreadr.offset = gitsCreadr.offset + 1; 1044 1045 // Check for wrapping 1046 auto queue_end = (4096 * (gitsCbaser.size + 1)); 1047 1048 if (gitsCreadr.offset == queue_end) { 1049 gitsCreadr.offset = 0; 1050 } 1051} 1052 1053void 1054Gicv3Its::checkCommandQueue() 1055{ 1056 if (!gitsControl.enabled || !gitsCbaser.valid) 1057 return; 1058 1059 if (gitsCwriter.offset != gitsCreadr.offset) { 1060 // writer and reader pointing to different command 1061 // entries: queue not empty. 1062 DPRINTF(ITS, "Reading command from queue\n"); 1063 1064 if (!pendingCommands) { 1065 auto *cmd_proc = new ItsCommand(*this); 1066 1067 runProcess(cmd_proc, nullptr); 1068 } else { 1069 DPRINTF(ITS, "Waiting for pending command to finish\n"); 1070 } 1071 } 1072} 1073 1074Port & 1075Gicv3Its::getPort(const std::string &if_name, PortID idx) 1076{ 1077 if (if_name == "dma") { 1078 return dmaPort; 1079 } 1080 return BasicPioDevice::getPort(if_name, idx); 1081} 1082 1083void 1084Gicv3Its::recvReqRetry() 1085{ 1086 assert(!packetsToRetry.empty()); 1087 1088 while (!packetsToRetry.empty()) { 1089 ItsAction a = packetsToRetry.front(); 1090 1091 assert(a.type == ItsActionType::SEND_REQ); 1092 1093 if (!dmaPort.sendTimingReq(a.pkt)) 1094 break; 1095 1096 packetsToRetry.pop(); 1097 } 1098} 1099 1100bool 1101Gicv3Its::recvTimingResp(PacketPtr pkt) 1102{ 1103 // @todo: We need to pay for this and not just zero it out 1104 pkt->headerDelay = pkt->payloadDelay = 0; 1105 1106 ItsProcess *proc = 1107 safe_cast<ItsProcess *>(pkt->popSenderState()); 1108 1109 runProcessTiming(proc, pkt); 1110 1111 return true; 1112} 1113 1114ItsAction 1115Gicv3Its::runProcess(ItsProcess *proc, PacketPtr pkt) 1116{ 1117 if (sys->isAtomicMode()) { 1118 return runProcessAtomic(proc, pkt); 1119 } else if (sys->isTimingMode()) { 1120 return runProcessTiming(proc, pkt); 1121 } else { 1122 panic("Not in timing or atomic mode\n"); 1123 } 1124} 1125 1126ItsAction 1127Gicv3Its::runProcessTiming(ItsProcess *proc, PacketPtr pkt) 1128{ 1129 ItsAction action = proc->run(pkt); 1130 1131 switch (action.type) { 1132 case ItsActionType::SEND_REQ: 1133 action.pkt->pushSenderState(proc); 1134 1135 if (packetsToRetry.empty() && 1136 dmaPort.sendTimingReq(action.pkt)) { 1137 1138 } else { 1139 packetsToRetry.push(action); 1140 } 1141 break; 1142 1143 case ItsActionType::TERMINATE: 1144 delete proc; 1145 if (!pendingCommands && !commandEvent.scheduled()) { 1146 schedule(commandEvent, clockEdge()); 1147 } 1148 break; 1149 1150 default: 1151 panic("Unknown action\n"); 1152 } 1153 1154 return action; 1155} 1156 1157ItsAction 1158Gicv3Its::runProcessAtomic(ItsProcess *proc, PacketPtr pkt) 1159{ 1160 ItsAction action; 1161 Tick delay = 0; 1162 bool terminate = false; 1163 1164 do { 1165 action = proc->run(pkt); 1166 1167 switch (action.type) { 1168 case ItsActionType::SEND_REQ: 1169 delay += dmaPort.sendAtomic(action.pkt); 1170 pkt = action.pkt; 1171 break; 1172 1173 case ItsActionType::TERMINATE: 1174 delete proc; 1175 terminate = true; 1176 break; 1177 1178 default: 1179 panic("Unknown action\n"); 1180 } 1181 1182 } while (!terminate); 1183 1184 action.delay = delay; 1185 1186 return action; 1187} 1188 1189void 1190Gicv3Its::translate(PacketPtr pkt) 1191{ 1192 DPRINTF(ITS, "Starting Translation Request\n"); 1193 1194 auto *proc = new ItsTranslation(*this); 1195 runProcess(proc, pkt); 1196} 1197 1198Gicv3Redistributor* 1199Gicv3Its::getRedistributor(uint64_t rd_base) 1200{ 1201 if (gitsTyper.pta == 1) { 1202 // RDBase is a redistributor address 1203 return gic->getRedistributorByAddr(rd_base << 16); 1204 } else { 1205 // RDBase is a redistributor number 1206 return gic->getRedistributor(rd_base); 1207 } 1208} 1209 1210Addr 1211Gicv3Its::pageAddress(Gicv3Its::ItsTables table) 1212{ 1213 const BASER base = tableBases[table]; 1214 // real address depends on page size 1215 switch (base.pageSize) { 1216 case SIZE_4K: 1217 case SIZE_16K: 1218 return mbits(base, 47, 12); 1219 case SIZE_64K: 1220 return mbits(base, 47, 16) | (bits(base, 15, 12) << 48); 1221 default: 1222 panic("Unsupported page size\n"); 1223 } 1224} 1225 1226void 1227Gicv3Its::moveAllPendingState( 1228 Gicv3Redistributor *rd1, Gicv3Redistributor *rd2) 1229{ 1230 const uint64_t largest_lpi_id = 1ULL << (rd1->lpiIDBits + 1); 1231 uint8_t lpi_pending_table[largest_lpi_id / 8]; 1232 1233 // Copying the pending table from redistributor 1 to redistributor 2 1234 rd1->memProxy->readBlob( 1235 rd1->lpiPendingTablePtr, (uint8_t *)lpi_pending_table, 1236 sizeof(lpi_pending_table)); 1237 1238 rd2->memProxy->writeBlob( 1239 rd2->lpiPendingTablePtr, (uint8_t *)lpi_pending_table, 1240 sizeof(lpi_pending_table)); 1241 1242 // Clearing pending table in redistributor 2 1243 rd1->memProxy->memsetBlob( 1244 rd1->lpiPendingTablePtr, 1245 0, sizeof(lpi_pending_table)); 1246 1247 rd2->updateAndInformCPUInterface(); 1248} 1249 1250Gicv3Its * 1251Gicv3ItsParams::create() 1252{ 1253 return new Gicv3Its(this); 1254} 1255