gic_v3_its.hh revision 14235:3c7ca56da5a1
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#ifndef __DEV_ARM_GICV3_ITS_H__ 41#define __DEV_ARM_GICV3_ITS_H__ 42 43#include <queue> 44 45#include "base/coroutine.hh" 46#include "dev/dma_device.hh" 47#include "params/Gicv3Its.hh" 48 49class Gicv3; 50class Gicv3Redistributor; 51class ItsProcess; 52class ItsTranslation; 53class ItsCommand; 54 55enum class ItsActionType 56{ 57 INITIAL_NOP, 58 SEND_REQ, 59 TERMINATE, 60}; 61 62struct ItsAction 63{ 64 ItsActionType type; 65 PacketPtr pkt; 66 Tick delay; 67}; 68 69/** 70 * GICv3 ITS module. This class is just modelling a pio device with its 71 * memory mapped registers. Most of the ITS functionalities are 72 * implemented as processes (ItsProcess) objects, like ItsTranslation or 73 * ItsCommand. 74 * Main job of Gicv3Its is to spawn those processes upon receival of packets. 75 */ 76class Gicv3Its : public BasicPioDevice 77{ 78 friend class ::ItsProcess; 79 friend class ::ItsTranslation; 80 friend class ::ItsCommand; 81 public: 82 class DataPort : public MasterPort 83 { 84 protected: 85 Gicv3Its &its; 86 87 public: 88 DataPort(const std::string &_name, Gicv3Its &_its) : 89 MasterPort(_name, &_its), 90 its(_its) 91 {} 92 93 virtual ~DataPort() {} 94 95 bool recvTimingResp(PacketPtr pkt) { return its.recvTimingResp(pkt); } 96 void recvReqRetry() { return its.recvReqRetry(); } 97 }; 98 99 DataPort dmaPort; 100 101 Port & getPort(const std::string &if_name, PortID idx) override; 102 bool recvTimingResp(PacketPtr pkt); 103 void recvReqRetry(); 104 105 Gicv3Its(const Gicv3ItsParams *params); 106 107 void setGIC(Gicv3 *_gic); 108 109 static const uint32_t itsControl = 0x0; 110 static const uint32_t itsTranslate = 0x10000; 111 112 // Address range part of Control frame 113 static const AddrRange GITS_BASER; 114 115 static const uint32_t NUM_BASER_REGS = 8; 116 117 // We currently don't support two level ITS tables 118 // The indirect bit is RAZ/WI for implementations that only 119 // support flat tables. 120 static const uint64_t BASER_INDIRECT = 0x4000000000000000; 121 static const uint64_t BASER_TYPE = 0x0700000000000000; 122 static const uint64_t BASER_ESZ = 0x001F000000000000; 123 static const uint64_t BASER_SZ = 0x00000000000000FF; 124 static const uint64_t BASER_WMASK = 125 ~(BASER_INDIRECT | BASER_TYPE | BASER_ESZ); 126 static const uint64_t BASER_WMASK_UNIMPL = 127 ~(BASER_INDIRECT | BASER_TYPE | BASER_ESZ | BASER_SZ); 128 129 // GITS_CTLR.quiescent mask 130 static const uint32_t CTLR_QUIESCENT; 131 132 enum : Addr 133 { 134 // Control frame 135 GITS_CTLR = itsControl + 0x0000, 136 GITS_IIDR = itsControl + 0x0004, 137 GITS_TYPER = itsControl + 0x0008, 138 GITS_CBASER = itsControl + 0x0080, 139 GITS_CWRITER = itsControl + 0x0088, 140 GITS_CREADR = itsControl + 0x0090, 141 GITS_PIDR2 = itsControl + 0xffe8, 142 143 // Translation frame 144 GITS_TRANSLATER = itsTranslate + 0x0040 145 }; 146 147 AddrRangeList getAddrRanges() const override; 148 149 Tick read(PacketPtr pkt) override; 150 Tick write(PacketPtr pkt) override; 151 152 DrainState drain() override; 153 void serialize(CheckpointOut & cp) const override; 154 void unserialize(CheckpointIn & cp) override; 155 156 void translate(PacketPtr pkt); 157 158 BitUnion32(CTLR) 159 Bitfield<31> quiescent; 160 Bitfield<7, 4> itsNumber; 161 Bitfield<1> imDe; 162 Bitfield<0> enabled; 163 EndBitUnion(CTLR) 164 165 // Command read/write, (CREADR, CWRITER) 166 BitUnion64(CRDWR) 167 Bitfield<63, 32> high; 168 Bitfield<31, 0> low; 169 Bitfield<19, 5> offset; 170 Bitfield<0> retry; 171 Bitfield<0> stalled; 172 EndBitUnion(CRDWR) 173 174 BitUnion64(CBASER) 175 Bitfield<63, 32> high; 176 Bitfield<31, 0> low; 177 Bitfield<63> valid; 178 Bitfield<61, 59> innerCache; 179 Bitfield<55, 53> outerCache; 180 Bitfield<51, 12> physAddr; 181 Bitfield<11, 10> shareability; 182 Bitfield<7, 0> size; 183 EndBitUnion(CBASER) 184 185 BitUnion64(BASER) 186 Bitfield<63> valid; 187 Bitfield<62> indirect; 188 Bitfield<61, 59> innerCache; 189 Bitfield<58, 56> type; 190 Bitfield<55, 53> outerCache; 191 Bitfield<52, 48> entrySize; 192 Bitfield<47, 12> physAddr; 193 Bitfield<11, 10> shareability; 194 Bitfield<9, 8> pageSize; 195 Bitfield<7, 0> size; 196 EndBitUnion(BASER) 197 198 BitUnion64(TYPER) 199 Bitfield<63, 32> high; 200 Bitfield<31, 0> low; 201 Bitfield<37> vmovp; 202 Bitfield<36> cil; 203 Bitfield<35, 32> cidBits; 204 Bitfield<31, 24> hcc; 205 Bitfield<19> pta; 206 Bitfield<18> seis; 207 Bitfield<17, 13> devBits; 208 Bitfield<12, 8> idBits; 209 Bitfield<7, 4> ittEntrySize; 210 Bitfield<2> cct; 211 Bitfield<1> _virtual; 212 Bitfield<0> physical; 213 EndBitUnion(TYPER) 214 215 CTLR gitsControl; 216 TYPER gitsTyper; 217 CBASER gitsCbaser; 218 CRDWR gitsCreadr; 219 CRDWR gitsCwriter; 220 uint32_t gitsIidr; 221 uint32_t gitsTranslater; 222 223 std::vector<BASER> tableBases; 224 225 /** 226 * Returns TRUE if the eventID supplied has bits above the implemented 227 * size or above the itt_range 228 */ 229 bool idOutOfRange(uint32_t event_id, uint8_t itt_range) const; 230 231 /** 232 * Returns TRUE if the value supplied has bits above the implemented range 233 * or if the value supplied exceeds the maximum configured size in the 234 * appropriate GITS_BASER<n> 235 */ 236 bool deviceOutOfRange(uint32_t device_id) const; 237 238 /** 239 * Returns TRUE if the value (size) supplied exceeds the maximum 240 * allowed by GITS_TYPER.ID_bits. Size is the parameter which is 241 * passed to the ITS via the MAPD command and is stored in the 242 * DTE.ittRange field. 243 */ 244 bool sizeOutOfRange(uint32_t size) const; 245 246 /** 247 * Returns TRUE if the value supplied has bits above the implemented range 248 * or if the value exceeds the total number of collections supported in 249 * hardware and external memory 250 */ 251 bool collectionOutOfRange(uint32_t collection_id) const; 252 253 /** 254 * Returns TRUE if the value supplied is larger than that permitted by 255 * GICD_TYPER.IDbits or not in the LPI range and is not 1023 256 */ 257 bool lpiOutOfRange(uint32_t intid) const; 258 259 private: // Command 260 void checkCommandQueue(); 261 void incrementReadPointer(); 262 263 public: // TableWalk 264 BitUnion64(DTE) 265 Bitfield<57, 53> ittRange; 266 Bitfield<52, 1> ittAddress; 267 Bitfield<0> valid; 268 EndBitUnion(DTE) 269 270 BitUnion64(ITTE) 271 Bitfield<59, 46> vpeid; 272 Bitfield<45, 30> icid; 273 Bitfield<29, 16> intNumHyp; 274 Bitfield<15, 2> intNum; 275 Bitfield<1> intType; 276 Bitfield<0> valid; 277 EndBitUnion(ITTE) 278 279 BitUnion64(CTE) 280 Bitfield<40, 1> rdBase; 281 Bitfield<0> valid; 282 EndBitUnion(CTE) 283 284 enum InterruptType 285 { 286 VIRTUAL_INTERRUPT = 0, 287 PHYSICAL_INTERRUPT = 1 288 }; 289 290 private: 291 Gicv3Redistributor* getRedistributor(uint64_t rd_base); 292 Gicv3Redistributor* getRedistributor(CTE cte) 293 { 294 return getRedistributor(cte.rdBase); 295 } 296 297 ItsAction runProcess(ItsProcess *proc, PacketPtr pkt); 298 ItsAction runProcessTiming(ItsProcess *proc, PacketPtr pkt); 299 ItsAction runProcessAtomic(ItsProcess *proc, PacketPtr pkt); 300 301 enum ItsTables 302 { 303 DEVICE_TABLE = 1, 304 VPE_TABLE = 2, 305 TRANSLATION_TABLE = 3, 306 COLLECTION_TABLE = 4 307 }; 308 309 enum PageSize 310 { 311 SIZE_4K, 312 SIZE_16K, 313 SIZE_64K 314 }; 315 316 Addr pageAddress(enum ItsTables table); 317 318 void moveAllPendingState( 319 Gicv3Redistributor *rd1, Gicv3Redistributor *rd2); 320 321 private: 322 std::queue<ItsAction> packetsToRetry; 323 uint32_t masterId; 324 Gicv3 *gic; 325 EventFunctionWrapper commandEvent; 326 327 bool pendingCommands; 328 uint32_t pendingTranslations; 329}; 330 331/** 332 * ItsProcess is a base coroutine wrapper which is spawned by 333 * the Gicv3Its module when the latter needs to perform different 334 * actions, like translating a peripheral's MSI into an LPI 335 * (See derived ItsTranslation) or processing a Command from the 336 * ITS queue (ItsCommand). 337 * The action to take is implemented by the method: 338 * 339 * virtual void main(Yield &yield) = 0; 340 * It's inheriting from Packet::SenderState since the generic process 341 * will be stopped (we are using coroutines) and sent with the packet 342 * to memory when doing table walks. 343 * When Gicv3Its receives a response, it will resume the coroutine from 344 * the point it stopped when yielding. 345 */ 346class ItsProcess : public Packet::SenderState 347{ 348 public: 349 using DTE = Gicv3Its::DTE; 350 using ITTE = Gicv3Its::ITTE; 351 using CTE = Gicv3Its::CTE; 352 using Coroutine = m5::Coroutine<PacketPtr, ItsAction>; 353 using Yield = Coroutine::CallerType; 354 355 ItsProcess(Gicv3Its &_its); 356 virtual ~ItsProcess(); 357 358 /** Returns the Gicv3Its name. Mainly used for DPRINTS */ 359 const std::string name() const; 360 361 ItsAction run(PacketPtr pkt); 362 363 protected: 364 void reinit(); 365 virtual void main(Yield &yield) = 0; 366 367 void writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte); 368 369 void writeIrqTranslationTable( 370 Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte); 371 372 void writeIrqCollectionTable( 373 Yield &yield, uint32_t collection_id, CTE cte); 374 375 uint64_t readDeviceTable( 376 Yield &yield, uint32_t device_id); 377 378 uint64_t readIrqTranslationTable( 379 Yield &yield, const Addr itt_base, uint32_t event_id); 380 381 uint64_t readIrqCollectionTable(Yield &yield, uint32_t collection_id); 382 383 void doRead(Yield &yield, Addr addr, void *ptr, size_t size); 384 void doWrite(Yield &yield, Addr addr, void *ptr, size_t size); 385 void terminate(Yield &yield); 386 387 protected: 388 Gicv3Its &its; 389 390 private: 391 std::unique_ptr<Coroutine> coroutine; 392}; 393 394/** 395 * An ItsTranslation is created whenever a peripheral writes a message in 396 * GITS_TRANSLATER (MSI). In this case main will simply do the table walks 397 * until it gets a redistributor and an INTID. It will then raise the 398 * LPI interrupt to the target redistributor. 399 */ 400class ItsTranslation : public ItsProcess 401{ 402 public: 403 ItsTranslation(Gicv3Its &_its); 404 ~ItsTranslation(); 405 406 protected: 407 void main(Yield &yield) override; 408 409 std::pair<uint32_t, Gicv3Redistributor *> 410 translateLPI(Yield &yield, uint32_t device_id, uint32_t event_id); 411}; 412 413/** 414 * An ItsCommand is created whenever there is a new command in the command 415 * queue. Only one command can be executed per time. 416 * main will firstly read the command from memory and then it will process 417 * it. 418 */ 419class ItsCommand : public ItsProcess 420{ 421 public: 422 union CommandEntry 423 { 424 struct 425 { 426 uint32_t type; 427 uint32_t deviceId; 428 uint32_t eventId; 429 uint32_t pintId; 430 431 uint32_t data[4]; 432 }; 433 uint64_t raw[4]; 434 }; 435 436 enum CommandType : uint32_t 437 { 438 CLEAR = 0x04, 439 DISCARD = 0x0F, 440 INT = 0x03, 441 INV = 0x0C, 442 INVALL = 0x0D, 443 MAPC = 0x09, 444 MAPD = 0x08, 445 MAPI = 0x0B, 446 MAPTI = 0x0A, 447 MOVALL = 0x0E, 448 MOVI = 0x01, 449 SYNC = 0x05, 450 VINVALL = 0x2D, 451 VMAPI = 0x2B, 452 VMAPP = 0x29, 453 VMAPTI = 0x2A, 454 VMOVI = 0x21, 455 VMOVP = 0x22, 456 VSYNC = 0x25 457 }; 458 459 ItsCommand(Gicv3Its &_its); 460 ~ItsCommand(); 461 462 protected: 463 /** 464 * Dispatch entry is a metadata struct which contains information about 465 * the command (like the name) and the function object implementing 466 * the command. 467 */ 468 struct DispatchEntry 469 { 470 using ExecFn = std::function<void(ItsCommand*, Yield&, CommandEntry&)>; 471 472 DispatchEntry(std::string _name, ExecFn _exec) 473 : name(_name), exec(_exec) 474 {} 475 476 std::string name; 477 ExecFn exec; 478 }; 479 480 using DispatchTable = std::unordered_map< 481 std::underlying_type<enum CommandType>::type, DispatchEntry>; 482 483 static DispatchTable cmdDispatcher; 484 485 static std::string commandName(uint32_t cmd); 486 487 void main(Yield &yield) override; 488 489 void readCommand(Yield &yield, CommandEntry &command); 490 void processCommand(Yield &yield, CommandEntry &command); 491 492 // Commands 493 void clear(Yield &yield, CommandEntry &command); 494 void discard(Yield &yield, CommandEntry &command); 495 void mapc(Yield &yield, CommandEntry &command); 496 void mapd(Yield &yield, CommandEntry &command); 497 void mapi(Yield &yield, CommandEntry &command); 498 void mapti(Yield &yield, CommandEntry &command); 499 void movall(Yield &yield, CommandEntry &command); 500 void movi(Yield &yield, CommandEntry &command); 501 void sync(Yield &yield, CommandEntry &command); 502 void doInt(Yield &yield, CommandEntry &command); 503 void inv(Yield &yield, CommandEntry &command); 504 void invall(Yield &yield, CommandEntry &command); 505 void vinvall(Yield &yield, CommandEntry &command); 506 void vmapi(Yield &yield, CommandEntry &command); 507 void vmapp(Yield &yield, CommandEntry &command); 508 void vmapti(Yield &yield, CommandEntry &command); 509 void vmovi(Yield &yield, CommandEntry &command); 510 void vmovp(Yield &yield, CommandEntry &command); 511 void vsync(Yield &yield, CommandEntry &command); 512 513 protected: // Helpers 514 bool idOutOfRange(CommandEntry &command, DTE dte) const 515 { 516 return its.idOutOfRange(command.eventId, dte.ittRange); 517 } 518 519 bool deviceOutOfRange(CommandEntry &command) const 520 { 521 return its.deviceOutOfRange(command.deviceId); 522 } 523 524 bool sizeOutOfRange(CommandEntry &command) const 525 { 526 const auto size = bits(command.raw[1], 4, 0); 527 const auto valid = bits(command.raw[2], 63); 528 if (valid) 529 return its.sizeOutOfRange(size); 530 else 531 return false; 532 } 533 534 bool collectionOutOfRange(CommandEntry &command) const 535 { 536 return its.collectionOutOfRange(bits(command.raw[2], 15, 0)); 537 } 538}; 539 540#endif 541