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