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