1/* 2 * Copyright (c) 2006 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ali Saidi 29 */ 30 31/* @file 32 * Device model for Intel's 8254x line of gigabit ethernet controllers. 33 */ 34 35#ifndef __DEV_NET_I8254XGBE_HH__ 36#define __DEV_NET_I8254XGBE_HH__ 37 38#include <deque> 39#include <string> 40 41#include "base/cp_annotate.hh" 42#include "base/inet.hh" 43#include "debug/EthernetDesc.hh" 44#include "debug/EthernetIntr.hh" 45#include "dev/net/etherdevice.hh" 46#include "dev/net/etherint.hh" 47#include "dev/net/etherpkt.hh" 48#include "dev/net/i8254xGBe_defs.hh" 49#include "dev/net/pktfifo.hh" 50#include "dev/pci/device.hh" 51#include "params/IGbE.hh" 52#include "sim/eventq.hh" 53 54class IGbEInt; 55 56class IGbE : public EtherDevice 57{ 58 private: 59 IGbEInt *etherInt; 60 CPA *cpa; 61 62 // device registers 63 iGbReg::Regs regs; 64 65 // eeprom data, status and control bits 66 int eeOpBits, eeAddrBits, eeDataBits; 67 uint8_t eeOpcode, eeAddr; 68 uint16_t flash[iGbReg::EEPROM_SIZE]; 69 70 // packet fifos 71 PacketFifo rxFifo; 72 PacketFifo txFifo; 73 74 // Packet that we are currently putting into the txFifo 75 EthPacketPtr txPacket; 76 77 // Should to Rx/Tx State machine tick? 78 bool inTick; 79 bool rxTick; 80 bool txTick; 81 bool txFifoTick; 82 83 bool rxDmaPacket; 84 85 // Number of bytes copied from current RX packet 86 unsigned pktOffset; 87 88 // Delays in managaging descriptors 89 Tick fetchDelay, wbDelay; 90 Tick fetchCompDelay, wbCompDelay; 91 Tick rxWriteDelay, txReadDelay; 92 93 // Event and function to deal with RDTR timer expiring 94 void rdtrProcess() { 95 rxDescCache.writeback(0); 96 DPRINTF(EthernetIntr, 97 "Posting RXT interrupt because RDTR timer expired\n"); 98 postInterrupt(iGbReg::IT_RXT); 99 } 100 101 EventFunctionWrapper rdtrEvent; 102 103 // Event and function to deal with RADV timer expiring 104 void radvProcess() { 105 rxDescCache.writeback(0); 106 DPRINTF(EthernetIntr, 107 "Posting RXT interrupt because RADV timer expired\n"); 108 postInterrupt(iGbReg::IT_RXT); 109 } 110 111 EventFunctionWrapper radvEvent; 112 113 // Event and function to deal with TADV timer expiring 114 void tadvProcess() { 115 txDescCache.writeback(0); 116 DPRINTF(EthernetIntr, 117 "Posting TXDW interrupt because TADV timer expired\n"); 118 postInterrupt(iGbReg::IT_TXDW); 119 } 120 121 EventFunctionWrapper tadvEvent; 122 123 // Event and function to deal with TIDV timer expiring 124 void tidvProcess() { 125 txDescCache.writeback(0); 126 DPRINTF(EthernetIntr, 127 "Posting TXDW interrupt because TIDV timer expired\n"); 128 postInterrupt(iGbReg::IT_TXDW); 129 } 130 EventFunctionWrapper tidvEvent; 131 132 // Main event to tick the device 133 void tick(); 134 EventFunctionWrapper tickEvent; 135 136 137 uint64_t macAddr; 138 139 void rxStateMachine(); 140 void txStateMachine(); 141 void txWire(); 142 143 /** Write an interrupt into the interrupt pending register and check mask 144 * and interrupt limit timer before sending interrupt to CPU 145 * @param t the type of interrupt we are posting 146 * @param now should we ignore the interrupt limiting timer 147 */ 148 void postInterrupt(iGbReg::IntTypes t, bool now = false); 149 150 /** Check and see if changes to the mask register have caused an interrupt 151 * to need to be sent or perhaps removed an interrupt cause. 152 */ 153 void chkInterrupt(); 154 155 /** Send an interrupt to the cpu 156 */ 157 void delayIntEvent(); 158 void cpuPostInt(); 159 // Event to moderate interrupts 160 EventFunctionWrapper interEvent; 161 162 /** Clear the interupt line to the cpu 163 */ 164 void cpuClearInt(); 165 166 Tick intClock() { return SimClock::Int::ns * 1024; } 167 168 /** This function is used to restart the clock so it can handle things like 169 * draining and resume in one place. */ 170 void restartClock(); 171 172 /** Check if all the draining things that need to occur have occured and 173 * handle the drain event if so. 174 */ 175 void checkDrain(); 176 177 void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) { 178 if (cpa) 179 cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st); 180 } 181 182 void anQ(std::string sm, std::string q) { 183 if (cpa) 184 cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr); 185 } 186 187 void anDq(std::string sm, std::string q) { 188 if (cpa) 189 cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr); 190 } 191 192 void anPq(std::string sm, std::string q, int num = 1) { 193 if (cpa) 194 cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num); 195 } 196 197 void anRq(std::string sm, std::string q, int num = 1) { 198 if (cpa) 199 cpa->hwRq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num); 200 } 201 202 void anWe(std::string sm, std::string q) { 203 if (cpa) 204 cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr); 205 } 206 207 void anWf(std::string sm, std::string q) { 208 if (cpa) 209 cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr); 210 } 211 212 213 template<class T> 214 class DescCache : public Serializable 215 { 216 protected: 217 virtual Addr descBase() const = 0; 218 virtual long descHead() const = 0; 219 virtual long descTail() const = 0; 220 virtual long descLen() const = 0; 221 virtual void updateHead(long h) = 0; 222 virtual void enableSm() = 0; 223 virtual void actionAfterWb() {} 224 virtual void fetchAfterWb() = 0; 225 226 typedef std::deque<T *> CacheType; 227 CacheType usedCache; 228 CacheType unusedCache; 229 230 T *fetchBuf; 231 T *wbBuf; 232 233 // Pointer to the device we cache for 234 IGbE *igbe; 235 236 // Name of this descriptor cache 237 std::string _name; 238 239 // How far we've cached 240 int cachePnt; 241 242 // The size of the descriptor cache 243 int size; 244 245 // How many descriptors we are currently fetching 246 int curFetching; 247 248 // How many descriptors we are currently writing back 249 int wbOut; 250 251 // if the we wrote back to the end of the descriptor ring and are going 252 // to have to wrap and write more 253 bool moreToWb; 254 255 // What the alignment is of the next descriptor writeback 256 Addr wbAlignment; 257 258 /** The packet that is currently being dmad to memory if any */ 259 EthPacketPtr pktPtr; 260 261 /** Shortcut for DMA address translation */ 262 Addr pciToDma(Addr a) { return igbe->pciToDma(a); } 263 264 public: 265 /** Annotate sm*/ 266 std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ, 267 annUsedDescQ, annUnusedCacheQ, annDescQ; 268 269 DescCache(IGbE *i, const std::string n, int s); 270 virtual ~DescCache(); 271 272 std::string name() { return _name; } 273 274 /** If the address/len/head change when we've got descriptors that are 275 * dirty that is very bad. This function checks that we don't and if we 276 * do panics. 277 */ 278 void areaChanged(); 279 280 void writeback(Addr aMask); 281 void writeback1(); 282 EventFunctionWrapper wbDelayEvent; 283 284 /** Fetch a chunk of descriptors into the descriptor cache. 285 * Calls fetchComplete when the memory system returns the data 286 */ 287 void fetchDescriptors(); 288 void fetchDescriptors1(); 289 EventFunctionWrapper fetchDelayEvent; 290 291 /** Called by event when dma to read descriptors is completed 292 */ 293 void fetchComplete(); 294 EventFunctionWrapper fetchEvent; 295 296 /** Called by event when dma to writeback descriptors is completed 297 */ 298 void wbComplete(); 299 EventFunctionWrapper wbEvent; 300 301 /* Return the number of descriptors left in the ring, so the device has 302 * a way to figure out if it needs to interrupt. 303 */ 304 unsigned 305 descLeft() const 306 { 307 unsigned left = unusedCache.size(); 308 if (cachePnt > descTail()) 309 left += (descLen() - cachePnt + descTail()); 310 else 311 left += (descTail() - cachePnt); 312 313 return left; 314 } 315 316 /* Return the number of descriptors used and not written back. 317 */ 318 unsigned descUsed() const { return usedCache.size(); } 319 320 /* Return the number of cache unused descriptors we have. */ 321 unsigned descUnused() const { return unusedCache.size(); } 322 323 /* Get into a state where the descriptor address/head/etc colud be 324 * changed */ 325 void reset(); 326 327 328 void serialize(CheckpointOut &cp) const override; 329 void unserialize(CheckpointIn &cp) override; 330 331 virtual bool hasOutstandingEvents() { 332 return wbEvent.scheduled() || fetchEvent.scheduled(); 333 } 334 335 }; 336 337 338 class RxDescCache : public DescCache<iGbReg::RxDesc> 339 { 340 protected: 341 Addr descBase() const override { return igbe->regs.rdba(); } 342 long descHead() const override { return igbe->regs.rdh(); } 343 long descLen() const override { return igbe->regs.rdlen() >> 4; } 344 long descTail() const override { return igbe->regs.rdt(); } 345 void updateHead(long h) override { igbe->regs.rdh(h); } 346 void enableSm() override; 347 void fetchAfterWb() override { 348 if (!igbe->rxTick && igbe->drainState() == DrainState::Running) 349 fetchDescriptors(); 350 } 351 352 bool pktDone; 353 354 /** Variable to head with header/data completion events */ 355 int splitCount; 356 357 /** Bytes of packet that have been copied, so we know when to 358 set EOP */ 359 unsigned bytesCopied; 360 361 public: 362 RxDescCache(IGbE *i, std::string n, int s); 363 364 /** Write the given packet into the buffer(s) pointed to by the 365 * descriptor and update the book keeping. Should only be called when 366 * there are no dma's pending. 367 * @param packet ethernet packet to write 368 * @param pkt_offset bytes already copied from the packet to memory 369 * @return pkt_offset + number of bytes copied during this call 370 */ 371 int writePacket(EthPacketPtr packet, int pkt_offset); 372 373 /** Called by event when dma to write packet is completed 374 */ 375 void pktComplete(); 376 377 /** Check if the dma on the packet has completed and RX state machine 378 * can continue 379 */ 380 bool packetDone(); 381 382 EventFunctionWrapper pktEvent; 383 384 // Event to handle issuing header and data write at the same time 385 // and only callking pktComplete() when both are completed 386 void pktSplitDone(); 387 EventFunctionWrapper pktHdrEvent; 388 EventFunctionWrapper pktDataEvent; 389 390 bool hasOutstandingEvents() override; 391 392 void serialize(CheckpointOut &cp) const override; 393 void unserialize(CheckpointIn &cp) override; 394 }; 395 friend class RxDescCache; 396 397 RxDescCache rxDescCache; 398 399 class TxDescCache : public DescCache<iGbReg::TxDesc> 400 { 401 protected: 402 Addr descBase() const override { return igbe->regs.tdba(); } 403 long descHead() const override { return igbe->regs.tdh(); } 404 long descTail() const override { return igbe->regs.tdt(); } 405 long descLen() const override { return igbe->regs.tdlen() >> 4; } 406 void updateHead(long h) override { igbe->regs.tdh(h); } 407 void enableSm() override; 408 void actionAfterWb() override; 409 void fetchAfterWb() override { 410 if (!igbe->txTick && igbe->drainState() == DrainState::Running) 411 fetchDescriptors(); 412 } 413 414 415 416 bool pktDone; 417 bool isTcp; 418 bool pktWaiting; 419 bool pktMultiDesc; 420 Addr completionAddress; 421 bool completionEnabled; 422 uint32_t descEnd; 423 424 425 // tso variables 426 bool useTso; 427 Addr tsoHeaderLen; 428 Addr tsoMss; 429 Addr tsoTotalLen; 430 Addr tsoUsedLen; 431 Addr tsoPrevSeq; 432 Addr tsoPktPayloadBytes; 433 bool tsoLoadedHeader; 434 bool tsoPktHasHeader; 435 uint8_t tsoHeader[256]; 436 Addr tsoDescBytesUsed; 437 Addr tsoCopyBytes; 438 int tsoPkts; 439 440 public: 441 TxDescCache(IGbE *i, std::string n, int s); 442 443 /** Tell the cache to DMA a packet from main memory into its buffer and 444 * return the size the of the packet to reserve space in tx fifo. 445 * @return size of the packet 446 */ 447 unsigned getPacketSize(EthPacketPtr p); 448 void getPacketData(EthPacketPtr p); 449 void processContextDesc(); 450 451 /** Return the number of dsecriptors in a cache block for threshold 452 * operations. 453 */ 454 unsigned 455 descInBlock(unsigned num_desc) 456 { 457 return num_desc / igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc); 458 } 459 460 /** Ask if the packet has been transfered so the state machine can give 461 * it to the fifo. 462 * @return packet available in descriptor cache 463 */ 464 bool packetAvailable(); 465 466 /** Ask if we are still waiting for the packet to be transfered. 467 * @return packet still in transit. 468 */ 469 bool packetWaiting() { return pktWaiting; } 470 471 /** Ask if this packet is composed of multiple descriptors 472 * so even if we've got data, we need to wait for more before 473 * we can send it out. 474 * @return packet can't be sent out because it's a multi-descriptor 475 * packet 476 */ 477 bool packetMultiDesc() { return pktMultiDesc;} 478 479 /** Called by event when dma to write packet is completed 480 */ 481 void pktComplete(); 482 EventFunctionWrapper pktEvent; 483 484 void headerComplete(); 485 EventFunctionWrapper headerEvent; 486 487 488 void completionWriteback(Addr a, bool enabled) { 489 DPRINTF(EthernetDesc, 490 "Completion writeback Addr: %#x enabled: %d\n", 491 a, enabled); 492 completionAddress = a; 493 completionEnabled = enabled; 494 } 495 496 bool hasOutstandingEvents() override; 497 498 void nullCallback() { 499 DPRINTF(EthernetDesc, "Completion writeback complete\n"); 500 } 501 EventFunctionWrapper nullEvent; 502 503 void serialize(CheckpointOut &cp) const override; 504 void unserialize(CheckpointIn &cp) override; 505 }; 506 507 friend class TxDescCache; 508 509 TxDescCache txDescCache; 510 511 public: 512 typedef IGbEParams Params; 513 const Params * 514 params() const { 515 return dynamic_cast<const Params *>(_params); 516 } 517 518 IGbE(const Params *params); 519 ~IGbE(); 520 void init() override; 521 522 Port &getPort(const std::string &if_name, 523 PortID idx=InvalidPortID) override; 524 525 Tick lastInterrupt; 526 527 Tick read(PacketPtr pkt) override; 528 Tick write(PacketPtr pkt) override; 529 530 Tick writeConfig(PacketPtr pkt) override; 531 532 bool ethRxPkt(EthPacketPtr packet); 533 void ethTxDone(); 534 535 void serialize(CheckpointOut &cp) const override; 536 void unserialize(CheckpointIn &cp) override; 537 538 DrainState drain() override; 539 void drainResume() override; 540 541}; 542 543class IGbEInt : public EtherInt 544{ 545 private: 546 IGbE *dev; 547 548 public: 549 IGbEInt(const std::string &name, IGbE *d) 550 : EtherInt(name), dev(d) 551 { } 552 553 virtual bool recvPacket(EthPacketPtr pkt) { return dev->ethRxPkt(pkt); } 554 virtual void sendDone() { dev->ethTxDone(); } 555}; 556 557#endif //__DEV_NET_I8254XGBE_HH__ 558