2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Nathan Binkert
35 #include "arch/vtophys.hh"
36 #include "base/debug.hh"
37 #include "base/inet.hh"
38 #include "base/types.hh"
39 #include "config/the_isa.hh"
40 #include "cpu/intr_control.hh"
41 #include "cpu/thread_context.hh"
42 #include "dev/etherlink.hh"
43 #include "dev/sinic.hh"
44 #include "mem/packet.hh"
45 #include "mem/packet_access.hh"
46 #include "sim/eventq.hh"
47 #include "sim/stats.hh"
51 using namespace TheISA
;
55 const char *RxStateStrings
[] =
64 const char *TxStateStrings
[] =
74 ///////////////////////////////////////////////////////////////////////
78 Base::Base(const Params
*p
)
79 : PciDev(p
), rxEnable(false), txEnable(false), clock(p
->clock
),
80 intrDelay(p
->intr_delay
), intrTick(0), cpuIntrEnable(false),
81 cpuPendingIntr(false), intrEvent(0), interface(NULL
)
85 Device::Device(const Params
*p
)
86 : Base(p
), rxUnique(0), txUnique(0),
87 virtualRegs(p
->virtual_count
< 1 ? 1 : p
->virtual_count
),
88 rxFifo(p
->rx_fifo_size
), txFifo(p
->tx_fifo_size
),
89 rxKickTick(0), txKickTick(0),
90 txEvent(this), rxDmaEvent(this), txDmaEvent(this),
91 dmaReadDelay(p
->dma_read_delay
), dmaReadFactor(p
->dma_read_factor
),
92 dmaWriteDelay(p
->dma_write_delay
), dmaWriteFactor(p
->dma_write_factor
)
94 interface
= new Interface(name() + ".int0", this);
106 .name(name() + ".rxBytes")
107 .desc("Bytes Received")
112 .name(name() + ".rxBandwidth")
113 .desc("Receive Bandwidth (bits/s)")
119 .name(name() + ".rxPackets")
120 .desc("Number of Packets Received")
125 .name(name() + ".rxPPS")
126 .desc("Packet Reception Rate (packets/s)")
132 .name(name() + ".rxIpPackets")
133 .desc("Number of IP Packets Received")
138 .name(name() + ".rxTcpPackets")
139 .desc("Number of Packets Received")
144 .name(name() + ".rxUdpPackets")
145 .desc("Number of UDP Packets Received")
150 .name(name() + ".rxIpChecksums")
151 .desc("Number of rx IP Checksums done by device")
157 .name(name() + ".rxTcpChecksums")
158 .desc("Number of rx TCP Checksums done by device")
164 .name(name() + ".rxUdpChecksums")
165 .desc("Number of rx UDP Checksums done by device")
171 .name(name() + ".totBandwidth")
172 .desc("Total Bandwidth (bits/s)")
178 .name(name() + ".totPackets")
179 .desc("Total Packets")
185 .name(name() + ".totBytes")
192 .name(name() + ".totPPS")
193 .desc("Total Tranmission Rate (packets/s)")
199 .name(name() + ".txBytes")
200 .desc("Bytes Transmitted")
205 .name(name() + ".txBandwidth")
206 .desc("Transmit Bandwidth (bits/s)")
212 .name(name() + ".txPackets")
213 .desc("Number of Packets Transmitted")
218 .name(name() + ".txPPS")
219 .desc("Packet Tranmission Rate (packets/s)")
225 .name(name() + ".txIpPackets")
226 .desc("Number of IP Packets Transmitted")
231 .name(name() + ".txTcpPackets")
232 .desc("Number of TCP Packets Transmitted")
237 .name(name() + ".txUdpPackets")
238 .desc("Number of Packets Transmitted")
243 .name(name() + ".txIpChecksums")
244 .desc("Number of tx IP Checksums done by device")
250 .name(name() + ".txTcpChecksums")
251 .desc("Number of tx TCP Checksums done by device")
257 .name(name() + ".txUdpChecksums")
258 .desc("Number of tx UDP Checksums done by device")
263 txBandwidth
= txBytes
* Stats::constant(8) / simSeconds
;
264 rxBandwidth
= rxBytes
* Stats::constant(8) / simSeconds
;
265 totBandwidth
= txBandwidth
+ rxBandwidth
;
266 totBytes
= txBytes
+ rxBytes
;
267 totPackets
= txPackets
+ rxPackets
;
268 txPacketRate
= txPackets
/ simSeconds
;
269 rxPacketRate
= rxPackets
/ simSeconds
;
271 _maxVnicDistance
= 0;
274 .name(name() + ".maxVnicDistance")
275 .desc("maximum vnic distance")
279 .name(name() + ".totalVnicDistance")
280 .desc("total vnic distance")
283 .name(name() + ".numVnicDistance")
284 .desc("number of vnic distance measurements")
288 .name(name() + ".avgVnicDistance")
289 .desc("average vnic distance")
292 avgVnicDistance
= totalVnicDistance
/ numVnicDistance
;
298 _maxVnicDistance
= 0;
302 Device::getEthPort(const std::string
&if_name
, int idx
)
304 if (if_name
== "interface") {
305 if (interface
->getPeer())
306 panic("interface already connected to\n");
315 Device::prepareIO(int cpu
, int index
)
317 int size
= virtualRegs
.size();
319 panic("Trying to access a vnic that doesn't exist %d > %d\n",
323 //add stats for head of line blocking
324 //add stats for average fifo length
325 //add stats for average number of vnics busy
328 Device::prepareRead(int cpu
, int index
)
330 using namespace Regs
;
331 prepareIO(cpu
, index
);
333 VirtualReg
&vnic
= virtualRegs
[index
];
335 // update rx registers
336 uint64_t rxdone
= vnic
.RxDone
;
337 rxdone
= set_RxDone_Packets(rxdone
, rxFifo
.countPacketsAfter(rxFifoPtr
));
338 rxdone
= set_RxDone_Empty(rxdone
, rxFifo
.empty());
339 rxdone
= set_RxDone_High(rxdone
, rxFifo
.size() > regs
.RxFifoHigh
);
340 rxdone
= set_RxDone_NotHigh(rxdone
, rxLow
);
341 regs
.RxData
= vnic
.RxData
;
342 regs
.RxDone
= rxdone
;
343 regs
.RxWait
= rxdone
;
345 // update tx regsiters
346 uint64_t txdone
= vnic
.TxDone
;
347 txdone
= set_TxDone_Packets(txdone
, txFifo
.packets());
348 txdone
= set_TxDone_Full(txdone
, txFifo
.avail() < regs
.TxMaxCopy
);
349 txdone
= set_TxDone_Low(txdone
, txFifo
.size() < regs
.TxFifoLow
);
350 regs
.TxData
= vnic
.TxData
;
351 regs
.TxDone
= txdone
;
352 regs
.TxWait
= txdone
;
356 if (!rxFifo
.empty()) {
357 int vnic
= rxFifo
.begin()->priv
;
358 if (vnic
!= -1 && virtualRegs
[vnic
].rxPacketOffset
> 0)
362 regs
.RxStatus
= set_RxStatus_Head(regs
.RxStatus
, head
);
363 regs
.RxStatus
= set_RxStatus_Busy(regs
.RxStatus
, rxBusyCount
);
364 regs
.RxStatus
= set_RxStatus_Mapped(regs
.RxStatus
, rxMappedCount
);
365 regs
.RxStatus
= set_RxStatus_Dirty(regs
.RxStatus
, rxDirtyCount
);
369 Device::prepareWrite(int cpu
, int index
)
371 prepareIO(cpu
, index
);
375 * I/O read of device register
378 Device::read(PacketPtr pkt
)
380 assert(config
.command
& PCI_CMD_MSE
);
381 assert(pkt
->getAddr() >= BARAddrs
[0] && pkt
->getSize() < BARSize
[0]);
383 int cpu
= pkt
->req
->contextId();
384 Addr daddr
= pkt
->getAddr() - BARAddrs
[0];
385 Addr index
= daddr
>> Regs::VirtualShift
;
386 Addr raddr
= daddr
& Regs::VirtualMask
;
390 if (!regValid(raddr
))
391 panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
392 cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
394 const Regs::Info
&info
= regInfo(raddr
);
396 panic("read %s (write only): "
397 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
398 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
400 panic("read %s (invalid size): "
401 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
402 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
404 prepareRead(cpu
, index
);
407 if (pkt
->getSize() == 4) {
408 uint32_t reg
= regData32(raddr
);
413 if (pkt
->getSize() == 8) {
414 uint64_t reg
= regData64(raddr
);
420 "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
421 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize(), value
);
423 // reading the interrupt status register has the side effect of
425 if (raddr
== Regs::IntrStatus
)
432 * IPR read of device register
435 Device::iprRead(Addr daddr, int cpu, uint64_t &result)
437 if (!regValid(daddr))
438 panic("invalid address: da=%#x", daddr);
440 const Regs::Info &info = regInfo(daddr);
442 panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
444 DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
445 info.name, cpu, daddr);
450 result = regData32(daddr);
453 result = regData64(daddr);
455 DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
456 info.name, cpu, result);
462 * I/O write of device register
465 Device::write(PacketPtr pkt
)
467 assert(config
.command
& PCI_CMD_MSE
);
468 assert(pkt
->getAddr() >= BARAddrs
[0] && pkt
->getSize() < BARSize
[0]);
470 int cpu
= pkt
->req
->contextId();
471 Addr daddr
= pkt
->getAddr() - BARAddrs
[0];
472 Addr index
= daddr
>> Regs::VirtualShift
;
473 Addr raddr
= daddr
& Regs::VirtualMask
;
475 if (!regValid(raddr
))
476 panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
477 cpu
, daddr
, pkt
->getAddr(), pkt
->getSize());
479 const Regs::Info
&info
= regInfo(raddr
);
481 panic("write %s (read only): "
482 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
483 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
485 if (pkt
->getSize() != info
.size
)
486 panic("write %s (invalid size): "
487 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
488 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
490 VirtualReg
&vnic
= virtualRegs
[index
];
493 "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
494 info
.name
, index
, cpu
, info
.size
== 4 ? pkt
->get
<uint32_t>() :
495 pkt
->get
<uint64_t>(), daddr
, pkt
->getAddr(), pkt
->getSize());
497 prepareWrite(cpu
, index
);
501 changeConfig(pkt
->get
<uint32_t>());
505 command(pkt
->get
<uint32_t>());
508 case Regs::IntrStatus
:
509 devIntrClear(regs
.IntrStatus
& pkt
->get
<uint32_t>());
513 devIntrChangeMask(pkt
->get
<uint32_t>());
517 if (Regs::get_RxDone_Busy(vnic
.RxDone
))
518 panic("receive machine busy with another request! rxState=%s",
519 RxStateStrings
[rxState
]);
521 vnic
.rxUnique
= rxUnique
++;
522 vnic
.RxDone
= Regs::RxDone_Busy
;
523 vnic
.RxData
= pkt
->get
<uint64_t>();
526 if (Regs::get_RxData_Vaddr(pkt
->get
<uint64_t>())) {
527 panic("vtophys not implemented in newmem");
529 Addr vaddr
= Regs::get_RxData_Addr(reg64
);
530 Addr paddr
= vtophys(req
->xc
, vaddr
);
531 DPRINTF(EthernetPIO
, "write RxData vnic %d (rxunique %d): "
532 "vaddr=%#x, paddr=%#x\n",
533 index
, vnic
.rxUnique
, vaddr
, paddr
);
535 vnic
.RxData
= Regs::set_RxData_Addr(vnic
.RxData
, paddr
);
538 DPRINTF(EthernetPIO
, "write RxData vnic %d (rxunique %d)\n",
539 index
, vnic
.rxUnique
);
542 if (vnic
.rxIndex
== rxFifo
.end()) {
543 DPRINTF(EthernetPIO
, "request new packet...appending to rxList\n");
544 rxList
.push_back(index
);
546 DPRINTF(EthernetPIO
, "packet exists...appending to rxBusy\n");
547 rxBusy
.push_back(index
);
550 if (rxEnable
&& (rxState
== rxIdle
|| rxState
== rxFifoBlock
)) {
551 rxState
= rxFifoBlock
;
557 if (Regs::get_TxDone_Busy(vnic
.TxDone
))
558 panic("transmit machine busy with another request! txState=%s",
559 TxStateStrings
[txState
]);
561 vnic
.txUnique
= txUnique
++;
562 vnic
.TxDone
= Regs::TxDone_Busy
;
564 if (Regs::get_TxData_Vaddr(pkt
->get
<uint64_t>())) {
565 panic("vtophys won't work here in newmem.\n");
567 Addr vaddr
= Regs::get_TxData_Addr(reg64
);
568 Addr paddr
= vtophys(req
->xc
, vaddr
);
569 DPRINTF(EthernetPIO
, "write TxData vnic %d (txunique %d): "
570 "vaddr=%#x, paddr=%#x\n",
571 index
, vnic
.txUnique
, vaddr
, paddr
);
573 vnic
.TxData
= Regs::set_TxData_Addr(vnic
.TxData
, paddr
);
576 DPRINTF(EthernetPIO
, "write TxData vnic %d (txunique %d)\n",
577 index
, vnic
.txUnique
);
580 if (txList
.empty() || txList
.front() != index
)
581 txList
.push_back(index
);
582 if (txEnable
&& txState
== txIdle
&& txList
.front() == index
) {
583 txState
= txFifoBlock
;
593 Device::devIntrPost(uint32_t interrupts
)
595 if ((interrupts
& Regs::Intr_Res
))
596 panic("Cannot set a reserved interrupt");
598 regs
.IntrStatus
|= interrupts
;
600 DPRINTF(EthernetIntr
,
601 "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
602 interrupts
, regs
.IntrStatus
, regs
.IntrMask
);
604 interrupts
= regs
.IntrStatus
& regs
.IntrMask
;
606 // Intr_RxHigh is special, we only signal it if we've emptied the fifo
607 // and then filled it above the high watermark
611 interrupts
&= ~Regs::Intr_RxHigh
;
613 // Intr_TxLow is special, we only signal it if we've filled up the fifo
614 // and then dropped below the low watermark
618 interrupts
&= ~Regs::Intr_TxLow
;
622 if ((interrupts
& Regs::Intr_NoDelay
) == 0)
629 Device::devIntrClear(uint32_t interrupts
)
631 if ((interrupts
& Regs::Intr_Res
))
632 panic("Cannot clear a reserved interrupt");
634 regs
.IntrStatus
&= ~interrupts
;
636 DPRINTF(EthernetIntr
,
637 "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
638 interrupts
, regs
.IntrStatus
, regs
.IntrMask
);
640 if (!(regs
.IntrStatus
& regs
.IntrMask
))
645 Device::devIntrChangeMask(uint32_t newmask
)
647 if (regs
.IntrMask
== newmask
)
650 regs
.IntrMask
= newmask
;
652 DPRINTF(EthernetIntr
,
653 "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
654 regs
.IntrStatus
, regs
.IntrMask
, regs
.IntrStatus
& regs
.IntrMask
);
656 if (regs
.IntrStatus
& regs
.IntrMask
)
657 cpuIntrPost(curTick
);
663 Base::cpuIntrPost(Tick when
)
665 // If the interrupt you want to post is later than an interrupt
666 // already scheduled, just let it post in the coming one and don't
668 // HOWEVER, must be sure that the scheduled intrTick is in the
669 // future (this was formerly the source of a bug)
671 * @todo this warning should be removed and the intrTick code should
674 assert(when
>= curTick
);
675 assert(intrTick
>= curTick
|| intrTick
== 0);
676 if (!cpuIntrEnable
) {
677 DPRINTF(EthernetIntr
, "interrupts not enabled.\n",
682 if (when
> intrTick
&& intrTick
!= 0) {
683 DPRINTF(EthernetIntr
, "don't need to schedule event...intrTick=%d\n",
689 if (intrTick
< curTick
) {
694 DPRINTF(EthernetIntr
, "going to schedule an interrupt for intrTick=%d\n",
699 intrEvent
= new IntrEvent(this, true);
700 schedule(intrEvent
, intrTick
);
706 assert(intrTick
== curTick
);
708 // Whether or not there's a pending interrupt, we don't care about
713 // Don't send an interrupt if there's already one
714 if (cpuPendingIntr
) {
715 DPRINTF(EthernetIntr
,
716 "would send an interrupt now, but there's already pending\n");
719 cpuPendingIntr
= true;
721 DPRINTF(EthernetIntr
, "posting interrupt\n");
739 cpuPendingIntr
= false;
741 DPRINTF(EthernetIntr
, "clearing cchip interrupt\n");
746 Base::cpuIntrPending() const
747 { return cpuPendingIntr
; }
750 Device::changeConfig(uint32_t newconf
)
752 uint32_t changed
= regs
.Config
^ newconf
;
756 regs
.Config
= newconf
;
758 if ((changed
& Regs::Config_IntEn
)) {
759 cpuIntrEnable
= regs
.Config
& Regs::Config_IntEn
;
761 if (regs
.IntrStatus
& regs
.IntrMask
)
762 cpuIntrPost(curTick
);
768 if ((changed
& Regs::Config_TxEn
)) {
769 txEnable
= regs
.Config
& Regs::Config_TxEn
;
774 if ((changed
& Regs::Config_RxEn
)) {
775 rxEnable
= regs
.Config
& Regs::Config_RxEn
;
782 Device::command(uint32_t command
)
784 if (command
& Regs::Command_Intr
)
785 devIntrPost(Regs::Intr_Soft
);
787 if (command
& Regs::Command_Reset
)
794 using namespace Regs
;
796 memset(®s
, 0, sizeof(regs
));
799 if (params()->rx_thread
)
800 regs
.Config
|= Config_RxThread
;
801 if (params()->tx_thread
)
802 regs
.Config
|= Config_TxThread
;
804 regs
.Config
|= Config_RSS
;
805 if (params()->zero_copy
)
806 regs
.Config
|= Config_ZeroCopy
;
807 if (params()->delay_copy
)
808 regs
.Config
|= Config_DelayCopy
;
809 if (params()->virtual_addr
)
810 regs
.Config
|= Config_Vaddr
;
812 if (params()->delay_copy
&& params()->zero_copy
)
813 panic("Can't delay copy and zero copy");
815 regs
.IntrMask
= Intr_Soft
| Intr_RxHigh
| Intr_RxPacket
| Intr_TxLow
;
816 regs
.RxMaxCopy
= params()->rx_max_copy
;
817 regs
.TxMaxCopy
= params()->tx_max_copy
;
818 regs
.ZeroCopySize
= params()->zero_copy_size
;
819 regs
.ZeroCopyMark
= params()->zero_copy_threshold
;
820 regs
.VirtualCount
= params()->virtual_count
;
821 regs
.RxMaxIntr
= params()->rx_max_intr
;
822 regs
.RxFifoSize
= params()->rx_fifo_size
;
823 regs
.TxFifoSize
= params()->tx_fifo_size
;
824 regs
.RxFifoLow
= params()->rx_fifo_low_mark
;
825 regs
.TxFifoLow
= params()->tx_fifo_threshold
;
826 regs
.RxFifoHigh
= params()->rx_fifo_threshold
;
827 regs
.TxFifoHigh
= params()->tx_fifo_high_mark
;
828 regs
.HwAddr
= params()->hardware_address
;
830 if (regs
.RxMaxCopy
< regs
.ZeroCopyMark
)
831 panic("Must be able to copy at least as many bytes as the threshold");
833 if (regs
.ZeroCopySize
>= regs
.ZeroCopyMark
)
834 panic("The number of bytes to copy must be less than the threshold");
848 rxFifoPtr
= rxFifo
.end();
854 int size
= virtualRegs
.size();
856 virtualRegs
.resize(size
);
857 for (int i
= 0; i
< size
; ++i
)
858 virtualRegs
[i
].rxIndex
= rxFifo
.end();
864 assert(rxState
== rxCopy
);
865 rxState
= rxCopyDone
;
866 DPRINTF(EthernetDMA
, "end rx dma write paddr=%#x len=%d\n",
867 rxDmaAddr
, rxDmaLen
);
868 DDUMP(EthernetData
, rxDmaData
, rxDmaLen
);
870 // If the transmit state machine has a pending DMA, let it go first
871 if (txState
== txBeginCopy
)
880 VirtualReg
*vnic
= NULL
;
882 DPRINTF(EthernetSM
, "rxKick: rxState=%s (rxFifo.size=%d)\n",
883 RxStateStrings
[rxState
], rxFifo
.size());
885 if (rxKickTick
> curTick
) {
886 DPRINTF(EthernetSM
, "rxKick: exiting, can't run till %d\n",
893 if (rxState
== rxIdle
)
896 if (rxActive
== -1) {
897 if (rxState
!= rxFifoBlock
)
898 panic("no active vnic while in state %s", RxStateStrings
[rxState
]);
900 DPRINTF(EthernetSM
, "processing rxState=%s\n",
901 RxStateStrings
[rxState
]);
903 vnic
= &virtualRegs
[rxActive
];
905 "processing rxState=%s for vnic %d (rxunique %d)\n",
906 RxStateStrings
[rxState
], rxActive
, vnic
->rxUnique
);
911 if (DTRACE(EthernetSM
)) {
912 PacketFifo::iterator end
= rxFifo
.end();
913 int size
= virtualRegs
.size();
914 for (int i
= 0; i
< size
; ++i
) {
915 VirtualReg
*vn
= &virtualRegs
[i
];
916 bool busy
= Regs::get_RxDone_Busy(vn
->RxDone
);
917 if (vn
->rxIndex
!= end
) {
918 bool dirty
= vn
->rxPacketOffset
> 0;
922 status
= "busy,dirty";
931 "vnic %d %s (rxunique %d), packet %d, slack %d\n",
932 i
, status
, vn
->rxUnique
,
933 rxFifo
.countPacketsBefore(vn
->rxIndex
),
936 DPRINTF(EthernetSM
, "vnic %d unmapped (rxunique %d)\n",
942 if (!rxBusy
.empty()) {
943 rxActive
= rxBusy
.front();
945 vnic
= &virtualRegs
[rxActive
];
947 if (vnic
->rxIndex
== rxFifo
.end())
948 panic("continuing vnic without packet\n");
951 "continue processing for vnic %d (rxunique %d)\n",
952 rxActive
, vnic
->rxUnique
);
954 rxState
= rxBeginCopy
;
956 int vnic_distance
= rxFifo
.countPacketsBefore(vnic
->rxIndex
);
957 totalVnicDistance
+= vnic_distance
;
958 numVnicDistance
+= 1;
959 if (vnic_distance
> _maxVnicDistance
) {
960 maxVnicDistance
= vnic_distance
;
961 _maxVnicDistance
= vnic_distance
;
967 if (rxFifoPtr
== rxFifo
.end()) {
968 DPRINTF(EthernetSM
, "receive waiting for data. Nothing to do.\n");
973 panic("Not idle, but nothing to do!");
975 assert(!rxFifo
.empty());
977 rxActive
= rxList
.front();
979 vnic
= &virtualRegs
[rxActive
];
982 "processing new packet for vnic %d (rxunique %d)\n",
983 rxActive
, vnic
->rxUnique
);
985 // Grab a new packet from the fifo.
986 vnic
->rxIndex
= rxFifoPtr
++;
987 vnic
->rxIndex
->priv
= rxActive
;
988 vnic
->rxPacketOffset
= 0;
989 vnic
->rxPacketBytes
= vnic
->rxIndex
->packet
->length
;
990 assert(vnic
->rxPacketBytes
);
993 vnic
->rxDoneData
= 0;
994 /* scope for variables */ {
995 IpPtr
ip(vnic
->rxIndex
->packet
);
997 DPRINTF(Ethernet
, "ID is %d\n", ip
->id());
998 vnic
->rxDoneData
|= Regs::RxDone_IpPacket
;
1000 if (cksum(ip
) != 0) {
1001 DPRINTF(EthernetCksum
, "Rx IP Checksum Error\n");
1002 vnic
->rxDoneData
|= Regs::RxDone_IpError
;
1008 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1009 tcp
->sport(), tcp
->dport(), tcp
->seq(),
1011 vnic
->rxDoneData
|= Regs::RxDone_TcpPacket
;
1013 if (cksum(tcp
) != 0) {
1014 DPRINTF(EthernetCksum
, "Rx TCP Checksum Error\n");
1015 vnic
->rxDoneData
|= Regs::RxDone_TcpError
;
1018 vnic
->rxDoneData
|= Regs::RxDone_UdpPacket
;
1020 if (cksum(udp
) != 0) {
1021 DPRINTF(EthernetCksum
, "Rx UDP Checksum Error\n");
1022 vnic
->rxDoneData
|= Regs::RxDone_UdpError
;
1027 rxState
= rxBeginCopy
;
1031 if (dmaPending() || getState() != Running
)
1034 rxDmaAddr
= params()->platform
->pciToDma(
1035 Regs::get_RxData_Addr(vnic
->RxData
));
1036 rxDmaLen
= min
<unsigned>(Regs::get_RxData_Len(vnic
->RxData
),
1037 vnic
->rxPacketBytes
);
1040 * if we're doing zero/delay copy and we're below the fifo
1041 * threshold, see if we should try to do the zero/defer copy
1043 if ((Regs::get_Config_ZeroCopy(regs
.Config
) ||
1044 Regs::get_Config_DelayCopy(regs
.Config
)) &&
1045 !Regs::get_RxData_NoDelay(vnic
->RxData
) && rxLow
) {
1046 if (rxDmaLen
> regs
.ZeroCopyMark
)
1047 rxDmaLen
= regs
.ZeroCopySize
;
1049 rxDmaData
= vnic
->rxIndex
->packet
->data
+ vnic
->rxPacketOffset
;
1051 if (rxDmaAddr
== 1LL) {
1052 rxState
= rxCopyDone
;
1056 dmaWrite(rxDmaAddr
, rxDmaLen
, &rxDmaEvent
, rxDmaData
);
1060 DPRINTF(EthernetSM
, "receive machine still copying\n");
1064 vnic
->RxDone
= vnic
->rxDoneData
;
1065 vnic
->RxDone
|= Regs::RxDone_Complete
;
1068 if (vnic
->rxPacketBytes
== rxDmaLen
) {
1069 if (vnic
->rxPacketOffset
)
1072 // Packet is complete. Indicate how many bytes were copied
1073 vnic
->RxDone
= Regs::set_RxDone_CopyLen(vnic
->RxDone
, rxDmaLen
);
1076 "rxKick: packet complete on vnic %d (rxunique %d)\n",
1077 rxActive
, vnic
->rxUnique
);
1078 rxFifo
.remove(vnic
->rxIndex
);
1079 vnic
->rxIndex
= rxFifo
.end();
1082 if (!vnic
->rxPacketOffset
)
1085 vnic
->rxPacketBytes
-= rxDmaLen
;
1086 vnic
->rxPacketOffset
+= rxDmaLen
;
1087 vnic
->RxDone
|= Regs::RxDone_More
;
1088 vnic
->RxDone
= Regs::set_RxDone_CopyLen(vnic
->RxDone
,
1089 vnic
->rxPacketBytes
);
1091 "rxKick: packet not complete on vnic %d (rxunique %d): "
1093 rxActive
, vnic
->rxUnique
, vnic
->rxPacketBytes
);
1097 rxState
= rxBusy
.empty() && rxList
.empty() ? rxIdle
: rxFifoBlock
;
1099 if (rxFifo
.empty()) {
1100 devIntrPost(Regs::Intr_RxEmpty
);
1104 if (rxFifo
.size() < regs
.RxFifoLow
)
1107 if (rxFifo
.size() > regs
.RxFifoHigh
)
1110 devIntrPost(Regs::Intr_RxDMA
);
1114 panic("Invalid rxState!");
1117 DPRINTF(EthernetSM
, "entering next rxState=%s\n",
1118 RxStateStrings
[rxState
]);
1124 * @todo do we want to schedule a future kick?
1126 DPRINTF(EthernetSM
, "rx state machine exited rxState=%s\n",
1127 RxStateStrings
[rxState
]);
1133 assert(txState
== txCopy
);
1134 txState
= txCopyDone
;
1135 DPRINTF(EthernetDMA
, "tx dma read paddr=%#x len=%d\n",
1136 txDmaAddr
, txDmaLen
);
1137 DDUMP(EthernetData
, txDmaData
, txDmaLen
);
1139 // If the receive state machine has a pending DMA, let it go first
1140 if (rxState
== rxBeginCopy
)
1149 if (txFifo
.empty()) {
1150 DPRINTF(Ethernet
, "nothing to transmit\n");
1154 uint32_t interrupts
;
1155 EthPacketPtr packet
= txFifo
.front();
1156 if (!interface
->sendPacket(packet
)) {
1157 DPRINTF(Ethernet
, "Packet Transmit: failed txFifo available %d\n",
1164 if (DTRACE(Ethernet
)) {
1167 DPRINTF(Ethernet
, "ID is %d\n", ip
->id());
1171 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1172 tcp
->sport(), tcp
->dport(), tcp
->seq(),
1179 DDUMP(EthernetData
, packet
->data
, packet
->length
);
1180 txBytes
+= packet
->length
;
1183 DPRINTF(Ethernet
, "Packet Transmit: successful txFifo Available %d\n",
1186 interrupts
= Regs::Intr_TxPacket
;
1187 if (txFifo
.size() < regs
.TxFifoLow
)
1188 interrupts
|= Regs::Intr_TxLow
;
1189 devIntrPost(interrupts
);
1196 DPRINTF(EthernetSM
, "txKick: txState=%s (txFifo.size=%d)\n",
1197 TxStateStrings
[txState
], txFifo
.size());
1199 if (txKickTick
> curTick
) {
1200 DPRINTF(EthernetSM
, "txKick: exiting, can't run till %d\n",
1206 if (txState
== txIdle
)
1209 assert(!txList
.empty());
1210 vnic
= &virtualRegs
[txList
.front()];
1214 assert(Regs::get_TxDone_Busy(vnic
->TxDone
));
1216 // Grab a new packet from the fifo.
1217 txPacket
= new EthPacketData(16384);
1221 if (txFifo
.avail() - txPacket
->length
<
1222 Regs::get_TxData_Len(vnic
->TxData
)) {
1223 DPRINTF(EthernetSM
, "transmit fifo full. Nothing to do.\n");
1227 txState
= txBeginCopy
;
1231 if (dmaPending() || getState() != Running
)
1234 txDmaAddr
= params()->platform
->pciToDma(
1235 Regs::get_TxData_Addr(vnic
->TxData
));
1236 txDmaLen
= Regs::get_TxData_Len(vnic
->TxData
);
1237 txDmaData
= txPacket
->data
+ txPacketOffset
;
1240 dmaRead(txDmaAddr
, txDmaLen
, &txDmaEvent
, txDmaData
);
1244 DPRINTF(EthernetSM
, "transmit machine still copying\n");
1248 vnic
->TxDone
= txDmaLen
| Regs::TxDone_Complete
;
1249 txPacket
->length
+= txDmaLen
;
1250 if ((vnic
->TxData
& Regs::TxData_More
)) {
1251 txPacketOffset
+= txDmaLen
;
1253 devIntrPost(Regs::Intr_TxDMA
);
1257 assert(txPacket
->length
<= txFifo
.avail());
1258 if ((vnic
->TxData
& Regs::TxData_Checksum
)) {
1264 tcp
->sum(cksum(tcp
));
1271 udp
->sum(cksum(udp
));
1281 txFifo
.push(txPacket
);
1282 if (txFifo
.avail() < regs
.TxMaxCopy
) {
1283 devIntrPost(Regs::Intr_TxFull
);
1289 txState
= txList
.empty() ? txIdle
: txFifoBlock
;
1290 devIntrPost(Regs::Intr_TxDMA
);
1294 panic("Invalid txState!");
1297 DPRINTF(EthernetSM
, "entering next txState=%s\n",
1298 TxStateStrings
[txState
]);
1304 * @todo do we want to schedule a future kick?
1306 DPRINTF(EthernetSM
, "tx state machine exited txState=%s\n",
1307 TxStateStrings
[txState
]);
1311 Device::transferDone()
1313 if (txFifo
.empty()) {
1314 DPRINTF(Ethernet
, "transfer complete: txFifo empty...nothing to do\n");
1318 DPRINTF(Ethernet
, "transfer complete: data in txFifo...schedule xmit\n");
1320 reschedule(txEvent
, curTick
+ ticks(1), true);
1324 Device::rxFilter(const EthPacketPtr
&packet
)
1326 if (!Regs::get_Config_Filter(regs
.Config
))
1329 panic("receive filter not implemented\n");
1335 EthHdr
*eth
= packet
->eth();
1336 if (eth
->unicast()) {
1337 // If we're accepting all unicast addresses
1341 // If we make a perfect match
1342 if (acceptPerfect
&& params
->eaddr
== eth
.dst())
1345 if (acceptArp
&& eth
->type() == ETH_TYPE_ARP
)
1348 } else if (eth
->broadcast()) {
1349 // if we're accepting broadcasts
1350 if (acceptBroadcast
)
1353 } else if (eth
->multicast()) {
1354 // if we're accepting all multicasts
1355 if (acceptMulticast
)
1361 DPRINTF(Ethernet
, "rxFilter drop\n");
1362 DDUMP(EthernetData
, packet
->data
, packet
->length
);
1369 Device::recvPacket(EthPacketPtr packet
)
1371 rxBytes
+= packet
->length
;
1374 DPRINTF(Ethernet
, "Receiving packet from wire, rxFifo Available is %d\n",
1378 DPRINTF(Ethernet
, "receive disabled...packet dropped\n");
1382 if (rxFilter(packet
)) {
1383 DPRINTF(Ethernet
, "packet filtered...dropped\n");
1387 if (rxFifo
.size() >= regs
.RxFifoHigh
)
1388 devIntrPost(Regs::Intr_RxHigh
);
1390 if (!rxFifo
.push(packet
)) {
1392 "packet will not fit in receive buffer...packet dropped\n");
1396 // If we were at the last element, back up one ot go to the new
1397 // last element of the list.
1398 if (rxFifoPtr
== rxFifo
.end())
1401 devIntrPost(Regs::Intr_RxPacket
);
1409 SimObject::resume();
1411 // During drain we could have left the state machines in a waiting state and
1412 // they wouldn't get out until some other event occured to kick them.
1413 // This way they'll get out immediately
1418 //=====================================================================
1422 Base::serialize(std::ostream
&os
)
1424 // Serialize the PciDev base class
1425 PciDev::serialize(os
);
1427 SERIALIZE_SCALAR(rxEnable
);
1428 SERIALIZE_SCALAR(txEnable
);
1429 SERIALIZE_SCALAR(cpuIntrEnable
);
1432 * Keep track of pending interrupt status.
1434 SERIALIZE_SCALAR(intrTick
);
1435 SERIALIZE_SCALAR(cpuPendingIntr
);
1436 Tick intrEventTick
= 0;
1438 intrEventTick
= intrEvent
->when();
1439 SERIALIZE_SCALAR(intrEventTick
);
1443 Base::unserialize(Checkpoint
*cp
, const std::string
§ion
)
1445 // Unserialize the PciDev base class
1446 PciDev::unserialize(cp
, section
);
1448 UNSERIALIZE_SCALAR(rxEnable
);
1449 UNSERIALIZE_SCALAR(txEnable
);
1450 UNSERIALIZE_SCALAR(cpuIntrEnable
);
1453 * Keep track of pending interrupt status.
1455 UNSERIALIZE_SCALAR(intrTick
);
1456 UNSERIALIZE_SCALAR(cpuPendingIntr
);
1458 UNSERIALIZE_SCALAR(intrEventTick
);
1459 if (intrEventTick
) {
1460 intrEvent
= new IntrEvent(this, true);
1461 schedule(intrEvent
, intrEventTick
);
1466 Device::serialize(std::ostream
&os
)
1470 // Serialize the PciDev base class
1471 Base::serialize(os
);
1473 if (rxState
== rxCopy
)
1474 panic("can't serialize with an in flight dma request rxState=%s",
1475 RxStateStrings
[rxState
]);
1477 if (txState
== txCopy
)
1478 panic("can't serialize with an in flight dma request txState=%s",
1479 TxStateStrings
[txState
]);
1482 * Serialize the device registers that could be modified by the OS.
1484 SERIALIZE_SCALAR(regs
.Config
);
1485 SERIALIZE_SCALAR(regs
.IntrStatus
);
1486 SERIALIZE_SCALAR(regs
.IntrMask
);
1487 SERIALIZE_SCALAR(regs
.RxData
);
1488 SERIALIZE_SCALAR(regs
.TxData
);
1491 * Serialize the virtual nic state
1493 int virtualRegsSize
= virtualRegs
.size();
1494 SERIALIZE_SCALAR(virtualRegsSize
);
1495 for (int i
= 0; i
< virtualRegsSize
; ++i
) {
1496 VirtualReg
*vnic
= &virtualRegs
[i
];
1498 std::string reg
= csprintf("vnic%d", i
);
1499 paramOut(os
, reg
+ ".RxData", vnic
->RxData
);
1500 paramOut(os
, reg
+ ".RxDone", vnic
->RxDone
);
1501 paramOut(os
, reg
+ ".TxData", vnic
->TxData
);
1502 paramOut(os
, reg
+ ".TxDone", vnic
->TxDone
);
1504 bool rxPacketExists
= vnic
->rxIndex
!= rxFifo
.end();
1505 paramOut(os
, reg
+ ".rxPacketExists", rxPacketExists
);
1506 if (rxPacketExists
) {
1508 PacketFifo::iterator i
= rxFifo
.begin();
1509 while (i
!= vnic
->rxIndex
) {
1510 assert(i
!= rxFifo
.end());
1515 paramOut(os
, reg
+ ".rxPacket", rxPacket
);
1516 paramOut(os
, reg
+ ".rxPacketOffset", vnic
->rxPacketOffset
);
1517 paramOut(os
, reg
+ ".rxPacketBytes", vnic
->rxPacketBytes
);
1519 paramOut(os
, reg
+ ".rxDoneData", vnic
->rxDoneData
);
1523 if (this->rxFifoPtr
!= rxFifo
.end())
1524 rxFifoPtr
= rxFifo
.countPacketsBefore(this->rxFifoPtr
);
1525 SERIALIZE_SCALAR(rxFifoPtr
);
1527 SERIALIZE_SCALAR(rxActive
);
1528 SERIALIZE_SCALAR(rxBusyCount
);
1529 SERIALIZE_SCALAR(rxDirtyCount
);
1530 SERIALIZE_SCALAR(rxMappedCount
);
1532 VirtualList::iterator i
, end
;
1533 for (count
= 0, i
= rxList
.begin(), end
= rxList
.end(); i
!= end
; ++i
)
1534 paramOut(os
, csprintf("rxList%d", count
++), *i
);
1535 int rxListSize
= count
;
1536 SERIALIZE_SCALAR(rxListSize
);
1538 for (count
= 0, i
= rxBusy
.begin(), end
= rxBusy
.end(); i
!= end
; ++i
)
1539 paramOut(os
, csprintf("rxBusy%d", count
++), *i
);
1540 int rxBusySize
= count
;
1541 SERIALIZE_SCALAR(rxBusySize
);
1543 for (count
= 0, i
= txList
.begin(), end
= txList
.end(); i
!= end
; ++i
)
1544 paramOut(os
, csprintf("txList%d", count
++), *i
);
1545 int txListSize
= count
;
1546 SERIALIZE_SCALAR(txListSize
);
1549 * Serialize rx state machine
1551 int rxState
= this->rxState
;
1552 SERIALIZE_SCALAR(rxState
);
1553 SERIALIZE_SCALAR(rxEmpty
);
1554 SERIALIZE_SCALAR(rxLow
);
1555 rxFifo
.serialize("rxFifo", os
);
1558 * Serialize tx state machine
1560 int txState
= this->txState
;
1561 SERIALIZE_SCALAR(txState
);
1562 SERIALIZE_SCALAR(txFull
);
1563 txFifo
.serialize("txFifo", os
);
1564 bool txPacketExists
= txPacket
;
1565 SERIALIZE_SCALAR(txPacketExists
);
1566 if (txPacketExists
) {
1567 txPacket
->serialize("txPacket", os
);
1568 SERIALIZE_SCALAR(txPacketOffset
);
1569 SERIALIZE_SCALAR(txPacketBytes
);
1573 * If there's a pending transmit, store the time so we can
1574 * reschedule it later
1576 Tick transmitTick
= txEvent
.scheduled() ? txEvent
.when() - curTick
: 0;
1577 SERIALIZE_SCALAR(transmitTick
);
1581 Device::unserialize(Checkpoint
*cp
, const std::string
§ion
)
1583 // Unserialize the PciDev base class
1584 Base::unserialize(cp
, section
);
1587 * Unserialize the device registers that may have been written by the OS.
1589 UNSERIALIZE_SCALAR(regs
.Config
);
1590 UNSERIALIZE_SCALAR(regs
.IntrStatus
);
1591 UNSERIALIZE_SCALAR(regs
.IntrMask
);
1592 UNSERIALIZE_SCALAR(regs
.RxData
);
1593 UNSERIALIZE_SCALAR(regs
.TxData
);
1595 UNSERIALIZE_SCALAR(rxActive
);
1596 UNSERIALIZE_SCALAR(rxBusyCount
);
1597 UNSERIALIZE_SCALAR(rxDirtyCount
);
1598 UNSERIALIZE_SCALAR(rxMappedCount
);
1601 UNSERIALIZE_SCALAR(rxListSize
);
1603 for (int i
= 0; i
< rxListSize
; ++i
) {
1605 paramIn(cp
, section
, csprintf("rxList%d", i
), value
);
1606 rxList
.push_back(value
);
1610 UNSERIALIZE_SCALAR(rxBusySize
);
1612 for (int i
= 0; i
< rxBusySize
; ++i
) {
1614 paramIn(cp
, section
, csprintf("rxBusy%d", i
), value
);
1615 rxBusy
.push_back(value
);
1619 UNSERIALIZE_SCALAR(txListSize
);
1621 for (int i
= 0; i
< txListSize
; ++i
) {
1623 paramIn(cp
, section
, csprintf("txList%d", i
), value
);
1624 txList
.push_back(value
);
1628 * Unserialize rx state machine
1631 UNSERIALIZE_SCALAR(rxState
);
1632 UNSERIALIZE_SCALAR(rxEmpty
);
1633 UNSERIALIZE_SCALAR(rxLow
);
1634 this->rxState
= (RxState
) rxState
;
1635 rxFifo
.unserialize("rxFifo", cp
, section
);
1638 UNSERIALIZE_SCALAR(rxFifoPtr
);
1639 if (rxFifoPtr
>= 0) {
1640 this->rxFifoPtr
= rxFifo
.begin();
1641 for (int i
= 0; i
< rxFifoPtr
; ++i
)
1644 this->rxFifoPtr
= rxFifo
.end();
1648 * Unserialize tx state machine
1651 UNSERIALIZE_SCALAR(txState
);
1652 UNSERIALIZE_SCALAR(txFull
);
1653 this->txState
= (TxState
) txState
;
1654 txFifo
.unserialize("txFifo", cp
, section
);
1655 bool txPacketExists
;
1656 UNSERIALIZE_SCALAR(txPacketExists
);
1658 if (txPacketExists
) {
1659 txPacket
= new EthPacketData(16384);
1660 txPacket
->unserialize("txPacket", cp
, section
);
1661 UNSERIALIZE_SCALAR(txPacketOffset
);
1662 UNSERIALIZE_SCALAR(txPacketBytes
);
1666 * unserialize the virtual nic registers/state
1668 * this must be done after the unserialization of the rxFifo
1669 * because the packet iterators depend on the fifo being populated
1671 int virtualRegsSize
;
1672 UNSERIALIZE_SCALAR(virtualRegsSize
);
1673 virtualRegs
.clear();
1674 virtualRegs
.resize(virtualRegsSize
);
1675 for (int i
= 0; i
< virtualRegsSize
; ++i
) {
1676 VirtualReg
*vnic
= &virtualRegs
[i
];
1677 std::string reg
= csprintf("vnic%d", i
);
1679 paramIn(cp
, section
, reg
+ ".RxData", vnic
->RxData
);
1680 paramIn(cp
, section
, reg
+ ".RxDone", vnic
->RxDone
);
1681 paramIn(cp
, section
, reg
+ ".TxData", vnic
->TxData
);
1682 paramIn(cp
, section
, reg
+ ".TxDone", vnic
->TxDone
);
1684 vnic
->rxUnique
= rxUnique
++;
1685 vnic
->txUnique
= txUnique
++;
1687 bool rxPacketExists
;
1688 paramIn(cp
, section
, reg
+ ".rxPacketExists", rxPacketExists
);
1689 if (rxPacketExists
) {
1691 paramIn(cp
, section
, reg
+ ".rxPacket", rxPacket
);
1692 vnic
->rxIndex
= rxFifo
.begin();
1696 paramIn(cp
, section
, reg
+ ".rxPacketOffset",
1697 vnic
->rxPacketOffset
);
1698 paramIn(cp
, section
, reg
+ ".rxPacketBytes", vnic
->rxPacketBytes
);
1700 vnic
->rxIndex
= rxFifo
.end();
1702 paramIn(cp
, section
, reg
+ ".rxDoneData", vnic
->rxDoneData
);
1706 * If there's a pending transmit, reschedule it now
1709 UNSERIALIZE_SCALAR(transmitTick
);
1711 schedule(txEvent
, curTick
+ transmitTick
);
1713 pioPort
->sendStatusChange(Port::RangeChange
);
1717 /* namespace Sinic */ }
1720 SinicParams::create()
1722 return new Sinic::Device(this);