CPA: Add annotations to IGbE and CopyEngine device models.
[gem5.git] / src / dev / i8254xGBe.hh
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_I8254XGBE_HH__
36 #define __DEV_I8254XGBE_HH__
37
38 #include <deque>
39 #include <string>
40
41 #include "base/cp_annotate.hh"
42 #include "base/inet.hh"
43 #include "dev/etherdevice.hh"
44 #include "dev/etherint.hh"
45 #include "dev/etherpkt.hh"
46 #include "dev/i8254xGBe_defs.hh"
47 #include "dev/pcidev.hh"
48 #include "dev/pktfifo.hh"
49 #include "params/IGbE.hh"
50 #include "sim/eventq.hh"
51
52 class IGbEInt;
53
54 class IGbE : public EtherDevice
55 {
56 private:
57 IGbEInt *etherInt;
58 CPA *cpa;
59
60 // device registers
61 iGbReg::Regs regs;
62
63 // eeprom data, status and control bits
64 int eeOpBits, eeAddrBits, eeDataBits;
65 uint8_t eeOpcode, eeAddr;
66 uint16_t flash[iGbReg::EEPROM_SIZE];
67
68 // The drain event if we have one
69 Event *drainEvent;
70
71 // cached parameters from params struct
72 bool useFlowControl;
73
74 // packet fifos
75 PacketFifo rxFifo;
76 PacketFifo txFifo;
77
78 // Packet that we are currently putting into the txFifo
79 EthPacketPtr txPacket;
80
81 // Should to Rx/Tx State machine tick?
82 bool rxTick;
83 bool txTick;
84 bool txFifoTick;
85
86 bool rxDmaPacket;
87
88 // Number of bytes copied from current RX packet
89 int pktOffset;
90
91 // Delays in managaging descriptors
92 Tick fetchDelay, wbDelay;
93 Tick fetchCompDelay, wbCompDelay;
94 Tick rxWriteDelay, txReadDelay;
95
96 // Event and function to deal with RDTR timer expiring
97 void rdtrProcess() {
98 rxDescCache.writeback(0);
99 DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n");
100 postInterrupt(iGbReg::IT_RXT);
101 }
102
103 //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
104 EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
105
106 // Event and function to deal with RADV timer expiring
107 void radvProcess() {
108 rxDescCache.writeback(0);
109 DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n");
110 postInterrupt(iGbReg::IT_RXT);
111 }
112
113 //friend class EventWrapper<IGbE, &IGbE::radvProcess>;
114 EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
115
116 // Event and function to deal with TADV timer expiring
117 void tadvProcess() {
118 txDescCache.writeback(0);
119 DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n");
120 postInterrupt(iGbReg::IT_TXDW);
121 }
122
123 //friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
124 EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent;
125
126 // Event and function to deal with TIDV timer expiring
127 void tidvProcess() {
128 txDescCache.writeback(0);
129 DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n");
130 postInterrupt(iGbReg::IT_TXDW);
131 }
132 //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
133 EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
134
135 // Main event to tick the device
136 void tick();
137 //friend class EventWrapper<IGbE, &IGbE::tick>;
138 EventWrapper<IGbE, &IGbE::tick> tickEvent;
139
140
141 uint64_t macAddr;
142
143 void rxStateMachine();
144 void txStateMachine();
145 void txWire();
146
147 /** Write an interrupt into the interrupt pending register and check mask
148 * and interrupt limit timer before sending interrupt to CPU
149 * @param t the type of interrupt we are posting
150 * @param now should we ignore the interrupt limiting timer
151 */
152 void postInterrupt(iGbReg::IntTypes t, bool now = false);
153
154 /** Check and see if changes to the mask register have caused an interrupt
155 * to need to be sent or perhaps removed an interrupt cause.
156 */
157 void chkInterrupt();
158
159 /** Send an interrupt to the cpu
160 */
161 void delayIntEvent();
162 void cpuPostInt();
163 // Event to moderate interrupts
164 EventWrapper<IGbE, &IGbE::delayIntEvent> interEvent;
165
166 /** Clear the interupt line to the cpu
167 */
168 void cpuClearInt();
169
170 Tick intClock() { return Clock::Int::ns * 1024; }
171
172 /** This function is used to restart the clock so it can handle things like
173 * draining and resume in one place. */
174 void restartClock();
175
176 /** Check if all the draining things that need to occur have occured and
177 * handle the drain event if so.
178 */
179 void checkDrain();
180
181 void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) {
182 cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st);
183 }
184
185 void anQ(std::string sm, std::string q) {
186 cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
187 }
188
189 void anDq(std::string sm, std::string q) {
190 cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
191 }
192
193 void anPq(std::string sm, std::string q, int num = 1) {
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 cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
199 }
200
201 void anWe(std::string sm, std::string q) {
202 cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
203 }
204
205 void anWf(std::string sm, std::string q) {
206 cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
207 }
208
209
210 template<class T>
211 class DescCache
212 {
213 protected:
214 virtual Addr descBase() const = 0;
215 virtual long descHead() const = 0;
216 virtual long descTail() const = 0;
217 virtual long descLen() const = 0;
218 virtual void updateHead(long h) = 0;
219 virtual void enableSm() = 0;
220 virtual void actionAfterWb() {}
221 virtual void fetchAfterWb() = 0;
222
223 std::deque<T*> usedCache;
224 std::deque<T*> unusedCache;
225
226 T *fetchBuf;
227 T *wbBuf;
228
229 // Pointer to the device we cache for
230 IGbE *igbe;
231
232 // Name of this descriptor cache
233 std::string _name;
234
235 // How far we've cached
236 int cachePnt;
237
238 // The size of the descriptor cache
239 int size;
240
241 // How many descriptors we are currently fetching
242 int curFetching;
243
244 // How many descriptors we are currently writing back
245 int wbOut;
246
247 // if the we wrote back to the end of the descriptor ring and are going
248 // to have to wrap and write more
249 bool moreToWb;
250
251 // What the alignment is of the next descriptor writeback
252 Addr wbAlignment;
253
254 /** The packet that is currently being dmad to memory if any
255 */
256 EthPacketPtr pktPtr;
257
258 public:
259 /** Annotate sm*/
260 std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
261 annUsedDescQ, annUnusedCacheQ, annDescQ;
262
263 DescCache(IGbE *i, const std::string n, int s)
264 : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0),
265 pktPtr(NULL), wbDelayEvent(this), fetchDelayEvent(this),
266 fetchEvent(this), wbEvent(this)
267 {
268 fetchBuf = new T[size];
269 wbBuf = new T[size];
270 }
271
272 virtual ~DescCache()
273 {
274 reset();
275 }
276
277 std::string name() { return _name; }
278
279 /** If the address/len/head change when we've got descriptors that are
280 * dirty that is very bad. This function checks that we don't and if we
281 * do panics.
282 */
283 void areaChanged()
284 {
285 if (usedCache.size() > 0 || curFetching || wbOut)
286 panic("Descriptor Address, Length or Head changed. Bad\n");
287 reset();
288
289 }
290
291 void writeback(Addr aMask)
292 {
293 int curHead = descHead();
294 int max_to_wb = usedCache.size();
295
296 // Check if this writeback is less restrictive that the previous
297 // and if so setup another one immediately following it
298 if (wbOut) {
299 if (aMask < wbAlignment) {
300 moreToWb = true;
301 wbAlignment = aMask;
302 }
303 DPRINTF(EthernetDesc, "Writing back already in process, returning\n");
304 return;
305 }
306
307 moreToWb = false;
308 wbAlignment = aMask;
309
310
311 DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
312 "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
313 curHead, descTail(), descLen(), cachePnt, max_to_wb,
314 descLeft());
315
316 if (max_to_wb + curHead >= descLen()) {
317 max_to_wb = descLen() - curHead;
318 moreToWb = true;
319 // this is by definition aligned correctly
320 } else if (wbAlignment != 0) {
321 // align the wb point to the mask
322 max_to_wb = max_to_wb & ~wbAlignment;
323 }
324
325 DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
326
327 if (max_to_wb <= 0) {
328 if (usedCache.size())
329 igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
330 else
331 igbe->anWe(annSmWb, annUsedCacheQ);
332 return;
333 }
334
335 wbOut = max_to_wb;
336
337 assert(!wbDelayEvent.scheduled());
338 igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
339 igbe->anBegin(annSmWb, "Prepare Writeback Desc");
340 }
341
342 void writeback1()
343 {
344 // If we're draining delay issuing this DMA
345 if (igbe->getState() != SimObject::Running) {
346 igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
347 return;
348 }
349
350 DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
351
352 for (int x = 0; x < wbOut; x++) {
353 assert(usedCache.size());
354 memcpy(&wbBuf[x], usedCache[x], sizeof(T));
355 igbe->anPq(annSmWb, annUsedCacheQ);
356 igbe->anPq(annSmWb, annDescQ);
357 igbe->anQ(annSmWb, annUsedDescQ);
358 }
359
360
361 igbe->anBegin(annSmWb, "Writeback Desc DMA");
362
363 assert(wbOut);
364 igbe->dmaWrite(igbe->platform->pciToDma(descBase() + descHead() * sizeof(T)),
365 wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
366 igbe->wbCompDelay);
367 }
368 EventWrapper<DescCache, &DescCache::writeback1> wbDelayEvent;
369
370 /** Fetch a chunk of descriptors into the descriptor cache.
371 * Calls fetchComplete when the memory system returns the data
372 */
373
374 void fetchDescriptors()
375 {
376 size_t max_to_fetch;
377
378 if (curFetching) {
379 DPRINTF(EthernetDesc, "Currently fetching %d descriptors, returning\n", curFetching);
380 return;
381 }
382
383 if (descTail() >= cachePnt)
384 max_to_fetch = descTail() - cachePnt;
385 else
386 max_to_fetch = descLen() - cachePnt;
387
388 size_t free_cache = size - usedCache.size() - unusedCache.size();
389
390 if (!max_to_fetch)
391 igbe->anWe(annSmFetch, annUnusedDescQ);
392 else
393 igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
394
395 if (max_to_fetch) {
396 if (!free_cache)
397 igbe->anWf(annSmFetch, annDescQ);
398 else
399 igbe->anRq(annSmFetch, annDescQ, free_cache);
400 }
401
402 max_to_fetch = std::min(max_to_fetch, free_cache);
403
404
405 DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
406 "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
407 descHead(), descTail(), descLen(), cachePnt,
408 max_to_fetch, descLeft());
409
410 // Nothing to do
411 if (max_to_fetch == 0)
412 return;
413
414 // So we don't have two descriptor fetches going on at once
415 curFetching = max_to_fetch;
416
417 assert(!fetchDelayEvent.scheduled());
418 igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
419 igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
420 }
421
422 void fetchDescriptors1()
423 {
424 // If we're draining delay issuing this DMA
425 if (igbe->getState() != SimObject::Running) {
426 igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
427 return;
428 }
429
430 igbe->anBegin(annSmFetch, "Fetch Desc");
431
432 DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
433 descBase() + cachePnt * sizeof(T),
434 igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
435 curFetching * sizeof(T));
436 assert(curFetching);
437 igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
438 curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
439 igbe->fetchCompDelay);
440 }
441
442 EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
443
444 /** Called by event when dma to read descriptors is completed
445 */
446 void fetchComplete()
447 {
448 T *newDesc;
449 igbe->anBegin(annSmFetch, "Fetch Complete");
450 for (int x = 0; x < curFetching; x++) {
451 newDesc = new T;
452 memcpy(newDesc, &fetchBuf[x], sizeof(T));
453 unusedCache.push_back(newDesc);
454 igbe->anDq(annSmFetch, annUnusedDescQ);
455 igbe->anQ(annSmFetch, annUnusedCacheQ);
456 igbe->anQ(annSmFetch, annDescQ);
457 }
458
459
460 #ifndef NDEBUG
461 int oldCp = cachePnt;
462 #endif
463
464 cachePnt += curFetching;
465 assert(cachePnt <= descLen());
466 if (cachePnt == descLen())
467 cachePnt = 0;
468
469 curFetching = 0;
470
471 DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
472 oldCp, cachePnt);
473
474 if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
475 cachePnt)) == 0)
476 {
477 igbe->anWe(annSmFetch, annUnusedDescQ);
478 } else if (!(size - usedCache.size() - unusedCache.size())) {
479 igbe->anWf(annSmFetch, annDescQ);
480 } else {
481 igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
482 }
483
484 enableSm();
485 igbe->checkDrain();
486 }
487
488 EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
489
490 /** Called by event when dma to writeback descriptors is completed
491 */
492 void wbComplete()
493 {
494
495 igbe->anBegin(annSmWb, "Finish Writeback");
496
497 long curHead = descHead();
498 #ifndef NDEBUG
499 long oldHead = curHead;
500 #endif
501
502 for (int x = 0; x < wbOut; x++) {
503 assert(usedCache.size());
504 delete usedCache[0];
505 usedCache.pop_front();
506
507 igbe->anDq(annSmWb, annUsedCacheQ);
508 igbe->anDq(annSmWb, annDescQ);
509 }
510
511 curHead += wbOut;
512 wbOut = 0;
513
514 if (curHead >= descLen())
515 curHead -= descLen();
516
517 // Update the head
518 updateHead(curHead);
519
520 DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
521 oldHead, curHead);
522
523 // If we still have more to wb, call wb now
524 actionAfterWb();
525 if (moreToWb) {
526 moreToWb = false;
527 DPRINTF(EthernetDesc, "Writeback has more todo\n");
528 writeback(wbAlignment);
529 }
530
531 if (!wbOut) {
532 igbe->checkDrain();
533 if (usedCache.size())
534 igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
535 else
536 igbe->anWe(annSmWb, annUsedCacheQ);
537 }
538 fetchAfterWb();
539 }
540
541
542 EventWrapper<DescCache, &DescCache::wbComplete> wbEvent;
543
544 /* Return the number of descriptors left in the ring, so the device has
545 * a way to figure out if it needs to interrupt.
546 */
547 int descLeft() const
548 {
549 int left = unusedCache.size();
550 if (cachePnt >= descTail())
551 left += (descLen() - cachePnt + descTail());
552 else
553 left += (descTail() - cachePnt);
554
555 return left;
556 }
557
558 /* Return the number of descriptors used and not written back.
559 */
560 int descUsed() const { return usedCache.size(); }
561
562 /* Return the number of cache unused descriptors we have. */
563 int descUnused() const {return unusedCache.size(); }
564
565 /* Get into a state where the descriptor address/head/etc colud be
566 * changed */
567 void reset()
568 {
569 DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
570 for (int x = 0; x < usedCache.size(); x++)
571 delete usedCache[x];
572 for (int x = 0; x < unusedCache.size(); x++)
573 delete unusedCache[x];
574
575 usedCache.clear();
576 unusedCache.clear();
577
578 cachePnt = 0;
579
580 }
581
582 virtual void serialize(std::ostream &os)
583 {
584 SERIALIZE_SCALAR(cachePnt);
585 SERIALIZE_SCALAR(curFetching);
586 SERIALIZE_SCALAR(wbOut);
587 SERIALIZE_SCALAR(moreToWb);
588 SERIALIZE_SCALAR(wbAlignment);
589
590 int usedCacheSize = usedCache.size();
591 SERIALIZE_SCALAR(usedCacheSize);
592 for(int x = 0; x < usedCacheSize; x++) {
593 arrayParamOut(os, csprintf("usedCache_%d", x),
594 (uint8_t*)usedCache[x],sizeof(T));
595 }
596
597 int unusedCacheSize = unusedCache.size();
598 SERIALIZE_SCALAR(unusedCacheSize);
599 for(int x = 0; x < unusedCacheSize; x++) {
600 arrayParamOut(os, csprintf("unusedCache_%d", x),
601 (uint8_t*)unusedCache[x],sizeof(T));
602 }
603
604 Tick fetch_delay = 0, wb_delay = 0;
605 if (fetchDelayEvent.scheduled())
606 fetch_delay = fetchDelayEvent.when();
607 SERIALIZE_SCALAR(fetch_delay);
608 if (wbDelayEvent.scheduled())
609 wb_delay = wbDelayEvent.when();
610 SERIALIZE_SCALAR(wb_delay);
611
612
613 }
614
615 virtual void unserialize(Checkpoint *cp, const std::string &section)
616 {
617 UNSERIALIZE_SCALAR(cachePnt);
618 UNSERIALIZE_SCALAR(curFetching);
619 UNSERIALIZE_SCALAR(wbOut);
620 UNSERIALIZE_SCALAR(moreToWb);
621 UNSERIALIZE_SCALAR(wbAlignment);
622
623 int usedCacheSize;
624 UNSERIALIZE_SCALAR(usedCacheSize);
625 T *temp;
626 for(int x = 0; x < usedCacheSize; x++) {
627 temp = new T;
628 arrayParamIn(cp, section, csprintf("usedCache_%d", x),
629 (uint8_t*)temp,sizeof(T));
630 usedCache.push_back(temp);
631 }
632
633 int unusedCacheSize;
634 UNSERIALIZE_SCALAR(unusedCacheSize);
635 for(int x = 0; x < unusedCacheSize; x++) {
636 temp = new T;
637 arrayParamIn(cp, section, csprintf("unusedCache_%d", x),
638 (uint8_t*)temp,sizeof(T));
639 unusedCache.push_back(temp);
640 }
641 Tick fetch_delay = 0, wb_delay = 0;
642 UNSERIALIZE_SCALAR(fetch_delay);
643 UNSERIALIZE_SCALAR(wb_delay);
644 if (fetch_delay)
645 igbe->schedule(fetchDelayEvent, fetch_delay);
646 if (wb_delay)
647 igbe->schedule(wbDelayEvent, wb_delay);
648
649
650 }
651 virtual bool hasOutstandingEvents() {
652 return wbEvent.scheduled() || fetchEvent.scheduled();
653 }
654
655 };
656
657
658 class RxDescCache : public DescCache<iGbReg::RxDesc>
659 {
660 protected:
661 virtual Addr descBase() const { return igbe->regs.rdba(); }
662 virtual long descHead() const { return igbe->regs.rdh(); }
663 virtual long descLen() const { return igbe->regs.rdlen() >> 4; }
664 virtual long descTail() const { return igbe->regs.rdt(); }
665 virtual void updateHead(long h) { igbe->regs.rdh(h); }
666 virtual void enableSm();
667 virtual void fetchAfterWb() {
668 if (!igbe->rxTick && igbe->getState() == SimObject::Running)
669 fetchDescriptors();
670 }
671
672 bool pktDone;
673
674 /** Variable to head with header/data completion events */
675 int splitCount;
676
677 /** Bytes of packet that have been copied, so we know when to set EOP */
678 int bytesCopied;
679
680 public:
681 RxDescCache(IGbE *i, std::string n, int s);
682
683 /** Write the given packet into the buffer(s) pointed to by the
684 * descriptor and update the book keeping. Should only be called when
685 * there are no dma's pending.
686 * @param packet ethernet packet to write
687 * @param pkt_offset bytes already copied from the packet to memory
688 * @return pkt_offset + number of bytes copied during this call
689 */
690 int writePacket(EthPacketPtr packet, int pkt_offset);
691
692 /** Called by event when dma to write packet is completed
693 */
694 void pktComplete();
695
696 /** Check if the dma on the packet has completed and RX state machine
697 * can continue
698 */
699 bool packetDone();
700
701 EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
702
703 // Event to handle issuing header and data write at the same time
704 // and only callking pktComplete() when both are completed
705 void pktSplitDone();
706 EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent;
707 EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent;
708
709 virtual bool hasOutstandingEvents();
710
711 virtual void serialize(std::ostream &os);
712 virtual void unserialize(Checkpoint *cp, const std::string &section);
713 };
714 friend class RxDescCache;
715
716 RxDescCache rxDescCache;
717
718 class TxDescCache : public DescCache<iGbReg::TxDesc>
719 {
720 protected:
721 virtual Addr descBase() const { return igbe->regs.tdba(); }
722 virtual long descHead() const { return igbe->regs.tdh(); }
723 virtual long descTail() const { return igbe->regs.tdt(); }
724 virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
725 virtual void updateHead(long h) { igbe->regs.tdh(h); }
726 virtual void enableSm();
727 virtual void actionAfterWb();
728 virtual void fetchAfterWb() {
729 if (!igbe->txTick && igbe->getState() == SimObject::Running)
730 fetchDescriptors();
731 }
732
733
734
735 bool pktDone;
736 bool isTcp;
737 bool pktWaiting;
738 bool pktMultiDesc;
739 Addr completionAddress;
740 bool completionEnabled;
741 uint32_t descEnd;
742
743
744 // tso variables
745 bool useTso;
746 Addr tsoHeaderLen;
747 Addr tsoMss;
748 Addr tsoTotalLen;
749 Addr tsoUsedLen;
750 Addr tsoPrevSeq;;
751 Addr tsoPktPayloadBytes;
752 bool tsoLoadedHeader;
753 bool tsoPktHasHeader;
754 uint8_t tsoHeader[256];
755 Addr tsoDescBytesUsed;
756 Addr tsoCopyBytes;
757 int tsoPkts;
758
759 public:
760 TxDescCache(IGbE *i, std::string n, int s);
761
762 /** Tell the cache to DMA a packet from main memory into its buffer and
763 * return the size the of the packet to reserve space in tx fifo.
764 * @return size of the packet
765 */
766 int getPacketSize(EthPacketPtr p);
767 void getPacketData(EthPacketPtr p);
768 void processContextDesc();
769
770 /** Return the number of dsecriptors in a cache block for threshold
771 * operations.
772 */
773 int descInBlock(int num_desc) { return num_desc /
774 igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc); }
775 /** Ask if the packet has been transfered so the state machine can give
776 * it to the fifo.
777 * @return packet available in descriptor cache
778 */
779 bool packetAvailable();
780
781 /** Ask if we are still waiting for the packet to be transfered.
782 * @return packet still in transit.
783 */
784 bool packetWaiting() { return pktWaiting; }
785
786 /** Ask if this packet is composed of multiple descriptors
787 * so even if we've got data, we need to wait for more before
788 * we can send it out.
789 * @return packet can't be sent out because it's a multi-descriptor
790 * packet
791 */
792 bool packetMultiDesc() { return pktMultiDesc;}
793
794 /** Called by event when dma to write packet is completed
795 */
796 void pktComplete();
797 EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
798
799 void headerComplete();
800 EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
801
802
803 void completionWriteback(Addr a, bool enabled) {
804 DPRINTF(EthernetDesc, "Completion writeback Addr: %#x enabled: %d\n",
805 a, enabled);
806 completionAddress = a;
807 completionEnabled = enabled;
808 }
809
810 virtual bool hasOutstandingEvents();
811
812 void nullCallback() { DPRINTF(EthernetDesc, "Completion writeback complete\n"); }
813 EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
814
815 virtual void serialize(std::ostream &os);
816 virtual void unserialize(Checkpoint *cp, const std::string &section);
817
818 };
819 friend class TxDescCache;
820
821 TxDescCache txDescCache;
822
823 public:
824 typedef IGbEParams Params;
825 const Params *
826 params() const
827 {
828 return dynamic_cast<const Params *>(_params);
829 }
830 IGbE(const Params *params);
831 ~IGbE() {}
832 virtual void init();
833
834 virtual EtherInt *getEthPort(const std::string &if_name, int idx);
835
836 Tick clock;
837 Tick lastInterrupt;
838 inline Tick ticks(int numCycles) const { return numCycles * clock; }
839
840 virtual Tick read(PacketPtr pkt);
841 virtual Tick write(PacketPtr pkt);
842
843 virtual Tick writeConfig(PacketPtr pkt);
844
845 bool ethRxPkt(EthPacketPtr packet);
846 void ethTxDone();
847
848 virtual void serialize(std::ostream &os);
849 virtual void unserialize(Checkpoint *cp, const std::string &section);
850 virtual unsigned int drain(Event *de);
851 virtual void resume();
852
853 };
854
855 class IGbEInt : public EtherInt
856 {
857 private:
858 IGbE *dev;
859
860 public:
861 IGbEInt(const std::string &name, IGbE *d)
862 : EtherInt(name), dev(d)
863 { }
864
865 virtual bool recvPacket(EthPacketPtr pkt) { return dev->ethRxPkt(pkt); }
866 virtual void sendDone() { dev->ethTxDone(); }
867 };
868
869
870
871
872
873 #endif //__DEV_I8254XGBE_HH__
874