gic_v3_its.cc revision 14181:8dcab501009c
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; 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; 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; 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 const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE); 183 const Addr address = base + device_id; 184 185 uint64_t dte; 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 const Addr address = itt_base + event_id; 197 198 uint64_t itte; 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 const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE); 209 const Addr address = base + collection_id; 210 211 uint64_t cte; 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 masterId(params->system->getMasterId(this)), 784 gic(nullptr), 785 commandEvent([this] { checkCommandQueue(); }, name()), 786 pendingCommands(false), 787 pendingTranslations(0) 788{ 789 for (auto idx = 0; idx < NUM_BASER_REGS; idx++) { 790 BASER gits_baser = 0; 791 gits_baser.type = idx; 792 gits_baser.entrySize = sizeof(uint64_t) - 1; 793 tableBases.push_back(gits_baser); 794 } 795} 796 797void 798Gicv3Its::setGIC(Gicv3 *_gic) 799{ 800 assert(!gic); 801 gic = _gic; 802} 803 804AddrRangeList 805Gicv3Its::getAddrRanges() const 806{ 807 assert(pioSize != 0); 808 AddrRangeList ranges; 809 DPRINTF(AddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize); 810 ranges.push_back(RangeSize(pioAddr, pioSize)); 811 return ranges; 812} 813 814Tick 815Gicv3Its::read(PacketPtr pkt) 816{ 817 const Addr addr = pkt->getAddr() - pioAddr; 818 uint64_t value = 0; 819 820 DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr); 821 822 switch (addr) { 823 case GITS_CTLR: 824 value = gitsControl; 825 break; 826 827 case GITS_IIDR: 828 value = gitsIidr; 829 break; 830 831 case GITS_TYPER: 832 value = gitsTyper; 833 break; 834 835 case GITS_CBASER: 836 value = gitsCbaser; 837 break; 838 839 case GITS_CBASER + 4: 840 value = gitsCbaser.high; 841 break; 842 843 case GITS_CWRITER: 844 value = gitsCwriter; 845 break; 846 847 case GITS_CWRITER + 4: 848 value = gitsCwriter.high; 849 break; 850 851 case GITS_CREADR: 852 value = gitsCreadr; 853 break; 854 855 case GITS_CREADR + 4: 856 value = gitsCreadr.high; 857 break; 858 859 case GITS_PIDR2: 860 value = gic->getDistributor()->gicdPidr2; 861 break; 862 863 case GITS_TRANSLATER: 864 value = gitsTranslater; 865 break; 866 867 default: 868 if (GITS_BASER.contains(addr)) { 869 auto relative_addr = addr - GITS_BASER.start(); 870 auto baser_index = relative_addr / sizeof(uint64_t); 871 872 value = tableBases[baser_index]; 873 break; 874 } else { 875 panic("Unrecognized register access\n"); 876 } 877 } 878 879 pkt->setUintX(value, LittleEndianByteOrder); 880 pkt->makeAtomicResponse(); 881 return pioDelay; 882} 883 884Tick 885Gicv3Its::write(PacketPtr pkt) 886{ 887 Addr addr = pkt->getAddr() - pioAddr; 888 889 DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr); 890 891 switch (addr) { 892 case GITS_CTLR: 893 assert(pkt->getSize() == sizeof(uint32_t)); 894 gitsControl = (pkt->getLE<uint32_t>() & ~CTLR_QUIESCENT); 895 // We should check here if the ITS has been disabled, and if 896 // that's the case, flush GICv3 caches to external memory. 897 // This is not happening now, since LPI caching is not 898 // currently implemented in gem5. 899 break; 900 901 case GITS_IIDR: 902 panic("GITS_IIDR is Read Only\n"); 903 904 case GITS_TYPER: 905 panic("GITS_TYPER is Read Only\n"); 906 907 case GITS_CBASER: 908 if (pkt->getSize() == sizeof(uint32_t)) { 909 gitsCbaser.low = pkt->getLE<uint32_t>(); 910 } else { 911 assert(pkt->getSize() == sizeof(uint64_t)); 912 gitsCbaser = pkt->getLE<uint64_t>(); 913 } 914 915 gitsCreadr = 0; // Cleared when CBASER gets written 916 917 checkCommandQueue(); 918 break; 919 920 case GITS_CBASER + 4: 921 assert(pkt->getSize() == sizeof(uint32_t)); 922 gitsCbaser.high = pkt->getLE<uint32_t>(); 923 924 gitsCreadr = 0; // Cleared when CBASER gets written 925 926 checkCommandQueue(); 927 break; 928 929 case GITS_CWRITER: 930 if (pkt->getSize() == sizeof(uint32_t)) { 931 gitsCwriter.low = pkt->getLE<uint32_t>(); 932 } else { 933 assert(pkt->getSize() == sizeof(uint64_t)); 934 gitsCwriter = pkt->getLE<uint64_t>(); 935 } 936 937 checkCommandQueue(); 938 break; 939 940 case GITS_CWRITER + 4: 941 assert(pkt->getSize() == sizeof(uint32_t)); 942 gitsCwriter.high = pkt->getLE<uint32_t>(); 943 944 checkCommandQueue(); 945 break; 946 947 case GITS_CREADR: 948 panic("GITS_READR is Read Only\n"); 949 950 case GITS_TRANSLATER: 951 if (gitsControl.enabled) { 952 translate(pkt); 953 } 954 break; 955 956 default: 957 if (GITS_BASER.contains(addr)) { 958 auto relative_addr = addr - GITS_BASER.start(); 959 auto baser_index = relative_addr / sizeof(uint64_t); 960 961 BASER val = pkt->getLE<uint64_t>(); 962 963 panic_if(val.indirect, 964 "We currently don't support two level ITS tables"); 965 966 tableBases[baser_index] = val; 967 break; 968 } else { 969 panic("Unrecognized register access\n"); 970 } 971 } 972 973 pkt->makeAtomicResponse(); 974 return pioDelay; 975} 976 977bool 978Gicv3Its::idOutOfRange(uint32_t event_id, uint8_t itt_range) const 979{ 980 const uint32_t id_bits = gitsTyper.idBits; 981 return event_id >= (1ULL << (id_bits + 1)) || 982 event_id >= ((1ULL << itt_range) + 1); 983} 984 985bool 986Gicv3Its::deviceOutOfRange(uint32_t device_id) const 987{ 988 return device_id >= (1ULL << (gitsTyper.devBits + 1)); 989} 990 991bool 992Gicv3Its::sizeOutOfRange(uint32_t size) const 993{ 994 return size > gitsTyper.idBits; 995} 996 997bool 998Gicv3Its::collectionOutOfRange(uint32_t collection_id) const 999{ 1000 // If GITS_TYPER.CIL == 0, ITS supports 16-bit CollectionID 1001 // Otherwise, #bits is specified by GITS_TYPER.CIDbits 1002 const auto cid_bits = gitsTyper.cil == 0 ? 1003 16 : gitsTyper.cidBits + 1; 1004 1005 return collection_id >= (1ULL << cid_bits); 1006} 1007 1008bool 1009Gicv3Its::lpiOutOfRange(uint32_t intid) const 1010{ 1011 return intid >= (1ULL << (Gicv3Distributor::IDBITS + 1)) || 1012 (intid < Gicv3Redistributor::SMALLEST_LPI_ID && 1013 intid != Gicv3::INTID_SPURIOUS); 1014} 1015 1016DrainState 1017Gicv3Its::drain() 1018{ 1019 if (!pendingCommands && !pendingTranslations) { 1020 return DrainState::Drained; 1021 } else { 1022 DPRINTF(Drain, "GICv3 ITS not drained\n"); 1023 return DrainState::Draining; 1024 } 1025} 1026 1027void 1028Gicv3Its::serialize(CheckpointOut & cp) const 1029{ 1030 SERIALIZE_SCALAR(gitsControl); 1031 SERIALIZE_SCALAR(gitsTyper); 1032 SERIALIZE_SCALAR(gitsCbaser); 1033 SERIALIZE_SCALAR(gitsCreadr); 1034 SERIALIZE_SCALAR(gitsCwriter); 1035 SERIALIZE_SCALAR(gitsIidr); 1036 1037 SERIALIZE_CONTAINER(tableBases); 1038} 1039 1040void 1041Gicv3Its::unserialize(CheckpointIn & cp) 1042{ 1043 UNSERIALIZE_SCALAR(gitsControl); 1044 UNSERIALIZE_SCALAR(gitsTyper); 1045 UNSERIALIZE_SCALAR(gitsCbaser); 1046 UNSERIALIZE_SCALAR(gitsCreadr); 1047 UNSERIALIZE_SCALAR(gitsCwriter); 1048 UNSERIALIZE_SCALAR(gitsIidr); 1049 1050 UNSERIALIZE_CONTAINER(tableBases); 1051} 1052 1053void 1054Gicv3Its::incrementReadPointer() 1055{ 1056 // Make the reader point to the next element 1057 gitsCreadr.offset = gitsCreadr.offset + 1; 1058 1059 // Check for wrapping 1060 auto queue_end = (4096 * (gitsCbaser.size + 1)); 1061 1062 if (gitsCreadr.offset == queue_end) { 1063 gitsCreadr.offset = 0; 1064 } 1065} 1066 1067void 1068Gicv3Its::checkCommandQueue() 1069{ 1070 if (!gitsControl.enabled || !gitsCbaser.valid) 1071 return; 1072 1073 if (gitsCwriter.offset != gitsCreadr.offset) { 1074 // writer and reader pointing to different command 1075 // entries: queue not empty. 1076 DPRINTF(ITS, "Reading command from queue\n"); 1077 1078 if (!pendingCommands) { 1079 auto *cmd_proc = new ItsCommand(*this); 1080 1081 runProcess(cmd_proc, nullptr); 1082 } else { 1083 DPRINTF(ITS, "Waiting for pending command to finish\n"); 1084 } 1085 } 1086} 1087 1088Port & 1089Gicv3Its::getPort(const std::string &if_name, PortID idx) 1090{ 1091 if (if_name == "dma") { 1092 return dmaPort; 1093 } 1094 return BasicPioDevice::getPort(if_name, idx); 1095} 1096 1097void 1098Gicv3Its::recvReqRetry() 1099{ 1100 assert(!packetsToRetry.empty()); 1101 1102 while (!packetsToRetry.empty()) { 1103 ItsAction a = packetsToRetry.front(); 1104 1105 assert(a.type == ItsActionType::SEND_REQ); 1106 1107 if (!dmaPort.sendTimingReq(a.pkt)) 1108 break; 1109 1110 packetsToRetry.pop(); 1111 } 1112} 1113 1114bool 1115Gicv3Its::recvTimingResp(PacketPtr pkt) 1116{ 1117 // @todo: We need to pay for this and not just zero it out 1118 pkt->headerDelay = pkt->payloadDelay = 0; 1119 1120 ItsProcess *proc = 1121 safe_cast<ItsProcess *>(pkt->popSenderState()); 1122 1123 runProcessTiming(proc, pkt); 1124 1125 return true; 1126} 1127 1128ItsAction 1129Gicv3Its::runProcess(ItsProcess *proc, PacketPtr pkt) 1130{ 1131 if (sys->isAtomicMode()) { 1132 return runProcessAtomic(proc, pkt); 1133 } else if (sys->isTimingMode()) { 1134 return runProcessTiming(proc, pkt); 1135 } else { 1136 panic("Not in timing or atomic mode\n"); 1137 } 1138} 1139 1140ItsAction 1141Gicv3Its::runProcessTiming(ItsProcess *proc, PacketPtr pkt) 1142{ 1143 ItsAction action = proc->run(pkt); 1144 1145 switch (action.type) { 1146 case ItsActionType::SEND_REQ: 1147 action.pkt->pushSenderState(proc); 1148 1149 if (packetsToRetry.empty() && 1150 dmaPort.sendTimingReq(action.pkt)) { 1151 1152 } else { 1153 packetsToRetry.push(action); 1154 } 1155 break; 1156 1157 case ItsActionType::TERMINATE: 1158 delete proc; 1159 if (!pendingCommands && !commandEvent.scheduled()) { 1160 schedule(commandEvent, clockEdge()); 1161 } 1162 break; 1163 1164 default: 1165 panic("Unknown action\n"); 1166 } 1167 1168 return action; 1169} 1170 1171ItsAction 1172Gicv3Its::runProcessAtomic(ItsProcess *proc, PacketPtr pkt) 1173{ 1174 ItsAction action; 1175 Tick delay = 0; 1176 bool terminate = false; 1177 1178 do { 1179 action = proc->run(pkt); 1180 1181 switch (action.type) { 1182 case ItsActionType::SEND_REQ: 1183 delay += dmaPort.sendAtomic(action.pkt); 1184 pkt = action.pkt; 1185 break; 1186 1187 case ItsActionType::TERMINATE: 1188 delete proc; 1189 terminate = true; 1190 break; 1191 1192 default: 1193 panic("Unknown action\n"); 1194 } 1195 1196 } while (!terminate); 1197 1198 action.delay = delay; 1199 1200 return action; 1201} 1202 1203void 1204Gicv3Its::translate(PacketPtr pkt) 1205{ 1206 DPRINTF(ITS, "Starting Translation Request\n"); 1207 1208 auto *proc = new ItsTranslation(*this); 1209 runProcess(proc, pkt); 1210} 1211 1212Gicv3Redistributor* 1213Gicv3Its::getRedistributor(uint64_t rd_base) 1214{ 1215 if (gitsTyper.pta == 1) { 1216 // RDBase is a redistributor address 1217 return gic->getRedistributorByAddr(rd_base << 16); 1218 } else { 1219 // RDBase is a redistributor number 1220 return gic->getRedistributor(rd_base); 1221 } 1222} 1223 1224Addr 1225Gicv3Its::pageAddress(Gicv3Its::ItsTables table) 1226{ 1227 const BASER base = tableBases[table]; 1228 // real address depends on page size 1229 switch (base.pageSize) { 1230 case SIZE_4K: 1231 case SIZE_16K: 1232 return mbits(base, 47, 12); 1233 case SIZE_64K: 1234 return mbits(base, 47, 16) | (bits(base, 15, 12) << 48); 1235 default: 1236 panic("Unsupported page size\n"); 1237 } 1238} 1239 1240void 1241Gicv3Its::moveAllPendingState( 1242 Gicv3Redistributor *rd1, Gicv3Redistributor *rd2) 1243{ 1244 const uint64_t largest_lpi_id = 1ULL << (rd1->lpiIDBits + 1); 1245 uint8_t lpi_pending_table[largest_lpi_id / 8]; 1246 1247 // Copying the pending table from redistributor 1 to redistributor 2 1248 rd1->memProxy->readBlob( 1249 rd1->lpiPendingTablePtr, (uint8_t *)lpi_pending_table, 1250 sizeof(lpi_pending_table)); 1251 1252 rd2->memProxy->writeBlob( 1253 rd2->lpiPendingTablePtr, (uint8_t *)lpi_pending_table, 1254 sizeof(lpi_pending_table)); 1255 1256 // Clearing pending table in redistributor 2 1257 rd1->memProxy->memsetBlob( 1258 rd1->lpiPendingTablePtr, 1259 0, sizeof(lpi_pending_table)); 1260 1261 rd2->updateAndInformCPUInterface(); 1262} 1263 1264Gicv3Its * 1265Gicv3ItsParams::create() 1266{ 1267 return new Gicv3Its(this); 1268} 1269