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/inet.hh"
37 #include "cpu/thread_context.hh"
38 #include "cpu/intr_control.hh"
39 #include "dev/etherlink.hh"
40 #include "dev/sinic.hh"
41 #include "mem/packet.hh"
42 #include "mem/packet_access.hh"
43 #include "sim/debug.hh"
44 #include "sim/eventq.hh"
45 #include "sim/host.hh"
46 #include "sim/stats.hh"
49 using namespace TheISA
;
53 const char *RxStateStrings
[] =
62 const char *TxStateStrings
[] =
72 ///////////////////////////////////////////////////////////////////////
76 Base::Base(const Params
*p
)
77 : PciDev(p
), rxEnable(false), txEnable(false), clock(p
->clock
),
78 intrDelay(p
->intr_delay
), intrTick(0), cpuIntrEnable(false),
79 cpuPendingIntr(false), intrEvent(0), interface(NULL
)
83 Device::Device(const Params
*p
)
84 : Base(p
), rxUnique(0), txUnique(0),
85 virtualRegs(p
->virtual_count
< 1 ? 1 : p
->virtual_count
),
86 rxFifo(p
->rx_fifo_size
), txFifo(p
->tx_fifo_size
),
87 rxKickTick(0), txKickTick(0),
88 txEvent(this), rxDmaEvent(this), txDmaEvent(this),
89 dmaReadDelay(p
->dma_read_delay
), dmaReadFactor(p
->dma_read_factor
),
90 dmaWriteDelay(p
->dma_write_delay
), dmaWriteFactor(p
->dma_write_factor
)
92 interface
= new Interface(name() + ".int0", this);
104 .name(name() + ".rxBytes")
105 .desc("Bytes Received")
110 .name(name() + ".rxBandwidth")
111 .desc("Receive Bandwidth (bits/s)")
117 .name(name() + ".rxPackets")
118 .desc("Number of Packets Received")
123 .name(name() + ".rxPPS")
124 .desc("Packet Reception Rate (packets/s)")
130 .name(name() + ".rxIpPackets")
131 .desc("Number of IP Packets Received")
136 .name(name() + ".rxTcpPackets")
137 .desc("Number of Packets Received")
142 .name(name() + ".rxUdpPackets")
143 .desc("Number of UDP Packets Received")
148 .name(name() + ".rxIpChecksums")
149 .desc("Number of rx IP Checksums done by device")
155 .name(name() + ".rxTcpChecksums")
156 .desc("Number of rx TCP Checksums done by device")
162 .name(name() + ".rxUdpChecksums")
163 .desc("Number of rx UDP Checksums done by device")
169 .name(name() + ".totBandwidth")
170 .desc("Total Bandwidth (bits/s)")
176 .name(name() + ".totPackets")
177 .desc("Total Packets")
183 .name(name() + ".totBytes")
190 .name(name() + ".totPPS")
191 .desc("Total Tranmission Rate (packets/s)")
197 .name(name() + ".txBytes")
198 .desc("Bytes Transmitted")
203 .name(name() + ".txBandwidth")
204 .desc("Transmit Bandwidth (bits/s)")
210 .name(name() + ".txPackets")
211 .desc("Number of Packets Transmitted")
216 .name(name() + ".txPPS")
217 .desc("Packet Tranmission Rate (packets/s)")
223 .name(name() + ".txIpPackets")
224 .desc("Number of IP Packets Transmitted")
229 .name(name() + ".txTcpPackets")
230 .desc("Number of TCP Packets Transmitted")
235 .name(name() + ".txUdpPackets")
236 .desc("Number of Packets Transmitted")
241 .name(name() + ".txIpChecksums")
242 .desc("Number of tx IP Checksums done by device")
248 .name(name() + ".txTcpChecksums")
249 .desc("Number of tx TCP Checksums done by device")
255 .name(name() + ".txUdpChecksums")
256 .desc("Number of tx UDP Checksums done by device")
261 txBandwidth
= txBytes
* Stats::constant(8) / simSeconds
;
262 rxBandwidth
= rxBytes
* Stats::constant(8) / simSeconds
;
263 totBandwidth
= txBandwidth
+ rxBandwidth
;
264 totBytes
= txBytes
+ rxBytes
;
265 totPackets
= txPackets
+ rxPackets
;
266 txPacketRate
= txPackets
/ simSeconds
;
267 rxPacketRate
= rxPackets
/ simSeconds
;
271 Device::getEthPort(const std::string
&if_name
, int idx
)
273 if (if_name
== "interface") {
274 if (interface
->getPeer())
275 panic("interface already connected to\n");
284 Device::prepareIO(int cpu
, int index
)
286 int size
= virtualRegs
.size();
288 panic("Trying to access a vnic that doesn't exist %d > %d\n",
293 Device::prepareRead(int cpu
, int index
)
295 using namespace Regs
;
296 prepareIO(cpu
, index
);
298 VirtualReg
&vnic
= virtualRegs
[index
];
300 // update rx registers
301 uint64_t rxdone
= vnic
.RxDone
;
302 rxdone
= set_RxDone_Packets(rxdone
, rxFifo
.countPacketsAfter(rxFifoPtr
));
303 rxdone
= set_RxDone_Empty(rxdone
, rxFifo
.empty());
304 rxdone
= set_RxDone_High(rxdone
, rxFifo
.size() > regs
.RxFifoMark
);
305 rxdone
= set_RxDone_NotHigh(rxdone
, rxLow
);
306 regs
.RxData
= vnic
.RxData
;
307 regs
.RxDone
= rxdone
;
308 regs
.RxWait
= rxdone
;
310 // update tx regsiters
311 uint64_t txdone
= vnic
.TxDone
;
312 txdone
= set_TxDone_Packets(txdone
, txFifo
.packets());
313 txdone
= set_TxDone_Full(txdone
, txFifo
.avail() < regs
.TxMaxCopy
);
314 txdone
= set_TxDone_Low(txdone
, txFifo
.size() < regs
.TxFifoMark
);
315 regs
.TxData
= vnic
.TxData
;
316 regs
.TxDone
= txdone
;
317 regs
.TxWait
= txdone
;
321 Device::prepareWrite(int cpu
, int index
)
323 prepareIO(cpu
, index
);
327 * I/O read of device register
330 Device::read(PacketPtr pkt
)
332 assert(config
.command
& PCI_CMD_MSE
);
333 assert(pkt
->getAddr() >= BARAddrs
[0] && pkt
->getSize() < BARSize
[0]);
335 int cpu
= pkt
->req
->getCpuNum();
336 Addr daddr
= pkt
->getAddr() - BARAddrs
[0];
337 Addr index
= daddr
>> Regs::VirtualShift
;
338 Addr raddr
= daddr
& Regs::VirtualMask
;
342 if (!regValid(raddr
))
343 panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
344 cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
346 const Regs::Info
&info
= regInfo(raddr
);
348 panic("read %s (write only): "
349 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
350 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
352 panic("read %s (invalid size): "
353 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
354 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
356 prepareRead(cpu
, index
);
359 if (pkt
->getSize() == 4) {
360 uint32_t reg
= regData32(raddr
);
365 if (pkt
->getSize() == 8) {
366 uint64_t reg
= regData64(raddr
);
372 "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
373 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize(), value
);
375 // reading the interrupt status register has the side effect of
377 if (raddr
== Regs::IntrStatus
)
384 * IPR read of device register
387 Device::iprRead(Addr daddr, int cpu, uint64_t &result)
389 if (!regValid(daddr))
390 panic("invalid address: da=%#x", daddr);
392 const Regs::Info &info = regInfo(daddr);
394 panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
396 DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
397 info.name, cpu, daddr);
402 result = regData32(daddr);
405 result = regData64(daddr);
407 DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
408 info.name, cpu, result);
414 * I/O write of device register
417 Device::write(PacketPtr pkt
)
419 assert(config
.command
& PCI_CMD_MSE
);
420 assert(pkt
->getAddr() >= BARAddrs
[0] && pkt
->getSize() < BARSize
[0]);
422 int cpu
= pkt
->req
->getCpuNum();
423 Addr daddr
= pkt
->getAddr() - BARAddrs
[0];
424 Addr index
= daddr
>> Regs::VirtualShift
;
425 Addr raddr
= daddr
& Regs::VirtualMask
;
427 if (!regValid(raddr
))
428 panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
429 cpu
, daddr
, pkt
->getAddr(), pkt
->getSize());
431 const Regs::Info
&info
= regInfo(raddr
);
433 panic("write %s (read only): "
434 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
435 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
437 if (pkt
->getSize() != info
.size
)
438 panic("write %s (invalid size): "
439 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
440 info
.name
, cpu
, index
, daddr
, pkt
->getAddr(), pkt
->getSize());
442 VirtualReg
&vnic
= virtualRegs
[index
];
445 "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
446 info
.name
, index
, cpu
, info
.size
== 4 ? pkt
->get
<uint32_t>() :
447 pkt
->get
<uint64_t>(), daddr
, pkt
->getAddr(), pkt
->getSize());
449 prepareWrite(cpu
, index
);
453 changeConfig(pkt
->get
<uint32_t>());
457 command(pkt
->get
<uint32_t>());
460 case Regs::IntrStatus
:
461 devIntrClear(regs
.IntrStatus
& pkt
->get
<uint32_t>());
465 devIntrChangeMask(pkt
->get
<uint32_t>());
469 if (Regs::get_RxDone_Busy(vnic
.RxDone
))
470 panic("receive machine busy with another request! rxState=%s",
471 RxStateStrings
[rxState
]);
473 vnic
.rxUnique
= rxUnique
++;
474 vnic
.RxDone
= Regs::RxDone_Busy
;
475 vnic
.RxData
= pkt
->get
<uint64_t>();
477 if (Regs::get_RxData_Vaddr(pkt
->get
<uint64_t>())) {
478 panic("vtophys not implemented in newmem");
479 /* Addr vaddr = Regs::get_RxData_Addr(reg64);
480 Addr paddr = vtophys(req->xc, vaddr);
481 DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
482 "vaddr=%#x, paddr=%#x\n",
483 index, vnic.rxUnique, vaddr, paddr);
485 vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/
487 DPRINTF(EthernetPIO
, "write RxData vnic %d (rxunique %d)\n",
488 index
, vnic
.rxUnique
);
491 if (vnic
.rxPacket
== rxFifo
.end()) {
492 DPRINTF(EthernetPIO
, "request new packet...appending to rxList\n");
493 rxList
.push_back(index
);
495 DPRINTF(EthernetPIO
, "packet exists...appending to rxBusy\n");
496 rxBusy
.push_back(index
);
499 if (rxEnable
&& (rxState
== rxIdle
|| rxState
== rxFifoBlock
)) {
500 rxState
= rxFifoBlock
;
506 if (Regs::get_TxDone_Busy(vnic
.TxDone
))
507 panic("transmit machine busy with another request! txState=%s",
508 TxStateStrings
[txState
]);
510 vnic
.txUnique
= txUnique
++;
511 vnic
.TxDone
= Regs::TxDone_Busy
;
513 if (Regs::get_TxData_Vaddr(pkt
->get
<uint64_t>())) {
514 panic("vtophys won't work here in newmem.\n");
515 /*Addr vaddr = Regs::get_TxData_Addr(reg64);
516 Addr paddr = vtophys(req->xc, vaddr);
517 DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
518 "vaddr=%#x, paddr=%#x\n",
519 index, vnic.txUnique, vaddr, paddr);
521 vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
523 DPRINTF(EthernetPIO
, "write TxData vnic %d (rxunique %d)\n",
524 index
, vnic
.txUnique
);
527 if (txList
.empty() || txList
.front() != index
)
528 txList
.push_back(index
);
529 if (txEnable
&& txState
== txIdle
&& txList
.front() == index
) {
530 txState
= txFifoBlock
;
540 Device::devIntrPost(uint32_t interrupts
)
542 if ((interrupts
& Regs::Intr_Res
))
543 panic("Cannot set a reserved interrupt");
545 regs
.IntrStatus
|= interrupts
;
547 DPRINTF(EthernetIntr
,
548 "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
549 interrupts
, regs
.IntrStatus
, regs
.IntrMask
);
551 interrupts
= regs
.IntrStatus
& regs
.IntrMask
;
553 // Intr_RxHigh is special, we only signal it if we've emptied the fifo
554 // and then filled it above the high watermark
558 interrupts
&= ~Regs::Intr_RxHigh
;
560 // Intr_TxLow is special, we only signal it if we've filled up the fifo
561 // and then dropped below the low watermark
565 interrupts
&= ~Regs::Intr_TxLow
;
569 if ((interrupts
& Regs::Intr_NoDelay
) == 0)
576 Device::devIntrClear(uint32_t interrupts
)
578 if ((interrupts
& Regs::Intr_Res
))
579 panic("Cannot clear a reserved interrupt");
581 regs
.IntrStatus
&= ~interrupts
;
583 DPRINTF(EthernetIntr
,
584 "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
585 interrupts
, regs
.IntrStatus
, regs
.IntrMask
);
587 if (!(regs
.IntrStatus
& regs
.IntrMask
))
592 Device::devIntrChangeMask(uint32_t newmask
)
594 if (regs
.IntrMask
== newmask
)
597 regs
.IntrMask
= newmask
;
599 DPRINTF(EthernetIntr
,
600 "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
601 regs
.IntrStatus
, regs
.IntrMask
, regs
.IntrStatus
& regs
.IntrMask
);
603 if (regs
.IntrStatus
& regs
.IntrMask
)
604 cpuIntrPost(curTick
);
610 Base::cpuIntrPost(Tick when
)
612 // If the interrupt you want to post is later than an interrupt
613 // already scheduled, just let it post in the coming one and don't
615 // HOWEVER, must be sure that the scheduled intrTick is in the
616 // future (this was formerly the source of a bug)
618 * @todo this warning should be removed and the intrTick code should
621 assert(when
>= curTick
);
622 assert(intrTick
>= curTick
|| intrTick
== 0);
623 if (!cpuIntrEnable
) {
624 DPRINTF(EthernetIntr
, "interrupts not enabled.\n",
629 if (when
> intrTick
&& intrTick
!= 0) {
630 DPRINTF(EthernetIntr
, "don't need to schedule event...intrTick=%d\n",
636 if (intrTick
< curTick
) {
641 DPRINTF(EthernetIntr
, "going to schedule an interrupt for intrTick=%d\n",
646 intrEvent
= new IntrEvent(this, intrTick
, true);
652 assert(intrTick
== curTick
);
654 // Whether or not there's a pending interrupt, we don't care about
659 // Don't send an interrupt if there's already one
660 if (cpuPendingIntr
) {
661 DPRINTF(EthernetIntr
,
662 "would send an interrupt now, but there's already pending\n");
665 cpuPendingIntr
= true;
667 DPRINTF(EthernetIntr
, "posting interrupt\n");
685 cpuPendingIntr
= false;
687 DPRINTF(EthernetIntr
, "clearing cchip interrupt\n");
692 Base::cpuIntrPending() const
693 { return cpuPendingIntr
; }
696 Device::changeConfig(uint32_t newconf
)
698 uint32_t changed
= regs
.Config
^ newconf
;
702 regs
.Config
= newconf
;
704 if ((changed
& Regs::Config_IntEn
)) {
705 cpuIntrEnable
= regs
.Config
& Regs::Config_IntEn
;
707 if (regs
.IntrStatus
& regs
.IntrMask
)
708 cpuIntrPost(curTick
);
714 if ((changed
& Regs::Config_TxEn
)) {
715 txEnable
= regs
.Config
& Regs::Config_TxEn
;
720 if ((changed
& Regs::Config_RxEn
)) {
721 rxEnable
= regs
.Config
& Regs::Config_RxEn
;
728 Device::command(uint32_t command
)
730 if (command
& Regs::Command_Intr
)
731 devIntrPost(Regs::Intr_Soft
);
733 if (command
& Regs::Command_Reset
)
740 using namespace Regs
;
742 memset(®s
, 0, sizeof(regs
));
745 if (params()->rx_thread
)
746 regs
.Config
|= Config_RxThread
;
747 if (params()->tx_thread
)
748 regs
.Config
|= Config_TxThread
;
750 regs
.Config
|= Config_RSS
;
751 if (params()->zero_copy
)
752 regs
.Config
|= Config_ZeroCopy
;
753 if (params()->delay_copy
)
754 regs
.Config
|= Config_DelayCopy
;
755 if (params()->virtual_addr
)
756 regs
.Config
|= Config_Vaddr
;
758 if (params()->delay_copy
&& params()->zero_copy
)
759 panic("Can't delay copy and zero copy");
761 regs
.IntrMask
= Intr_Soft
| Intr_RxHigh
| Intr_RxPacket
| Intr_TxLow
;
762 regs
.RxMaxCopy
= params()->rx_max_copy
;
763 regs
.TxMaxCopy
= params()->tx_max_copy
;
764 regs
.RxMaxIntr
= params()->rx_max_intr
;
765 regs
.VirtualCount
= params()->virtual_count
;
766 regs
.RxFifoSize
= params()->rx_fifo_size
;
767 regs
.TxFifoSize
= params()->tx_fifo_size
;
768 regs
.RxFifoMark
= params()->rx_fifo_threshold
;
769 regs
.TxFifoMark
= params()->tx_fifo_threshold
;
770 regs
.HwAddr
= params()->hardware_address
;
781 rxFifoPtr
= rxFifo
.end();
787 int size
= virtualRegs
.size();
789 virtualRegs
.resize(size
);
790 for (int i
= 0; i
< size
; ++i
)
791 virtualRegs
[i
].rxPacket
= rxFifo
.end();
797 assert(rxState
== rxCopy
);
798 rxState
= rxCopyDone
;
799 DPRINTF(EthernetDMA
, "end rx dma write paddr=%#x len=%d\n",
800 rxDmaAddr
, rxDmaLen
);
801 DDUMP(EthernetData
, rxDmaData
, rxDmaLen
);
803 // If the transmit state machine has a pending DMA, let it go first
804 if (txState
== txBeginCopy
)
813 VirtualReg
*vnic
= NULL
;
815 DPRINTF(EthernetSM
, "rxKick: rxState=%s (rxFifo.size=%d)\n",
816 RxStateStrings
[rxState
], rxFifo
.size());
818 if (rxKickTick
> curTick
) {
819 DPRINTF(EthernetSM
, "rxKick: exiting, can't run till %d\n",
825 if (rxState
== rxIdle
)
828 if (rxActive
== -1) {
829 if (rxState
!= rxFifoBlock
)
830 panic("no active vnic while in state %s", RxStateStrings
[rxState
]);
832 DPRINTF(EthernetSM
, "processing rxState=%s\n",
833 RxStateStrings
[rxState
]);
835 vnic
= &virtualRegs
[rxActive
];
837 "processing rxState=%s for vnic %d (rxunique %d)\n",
838 RxStateStrings
[rxState
], rxActive
, vnic
->rxUnique
);
843 if (DTRACE(EthernetSM
)) {
844 PacketFifo::iterator end
= rxFifo
.end();
845 int size
= virtualRegs
.size();
846 for (int i
= 0; i
< size
; ++i
) {
847 VirtualReg
*vn
= &virtualRegs
[i
];
848 if (vn
->rxPacket
!= end
&&
849 !Regs::get_RxDone_Busy(vn
->RxDone
)) {
851 "vnic %d (rxunique %d), has outstanding packet %d\n",
853 rxFifo
.countPacketsBefore(vn
->rxPacket
));
858 if (!rxBusy
.empty()) {
859 rxActive
= rxBusy
.front();
861 vnic
= &virtualRegs
[rxActive
];
863 if (vnic
->rxPacket
== rxFifo
.end())
864 panic("continuing vnic without packet\n");
867 "continue processing for vnic %d (rxunique %d)\n",
868 rxActive
, vnic
->rxUnique
);
870 rxState
= rxBeginCopy
;
875 if (rxFifoPtr
== rxFifo
.end()) {
876 DPRINTF(EthernetSM
, "receive waiting for data. Nothing to do.\n");
881 panic("Not idle, but nothing to do!");
883 assert(!rxFifo
.empty());
885 rxActive
= rxList
.front();
887 vnic
= &virtualRegs
[rxActive
];
890 "processing new packet for vnic %d (rxunique %d)\n",
891 rxActive
, vnic
->rxUnique
);
893 // Grab a new packet from the fifo.
894 vnic
->rxPacket
= rxFifoPtr
++;
895 vnic
->rxPacketOffset
= 0;
896 vnic
->rxPacketBytes
= (*vnic
->rxPacket
)->length
;
897 assert(vnic
->rxPacketBytes
);
899 vnic
->rxDoneData
= 0;
900 /* scope for variables */ {
901 IpPtr
ip(*vnic
->rxPacket
);
903 DPRINTF(Ethernet
, "ID is %d\n", ip
->id());
904 vnic
->rxDoneData
|= Regs::RxDone_IpPacket
;
906 if (cksum(ip
) != 0) {
907 DPRINTF(EthernetCksum
, "Rx IP Checksum Error\n");
908 vnic
->rxDoneData
|= Regs::RxDone_IpError
;
914 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
915 tcp
->sport(), tcp
->dport(), tcp
->seq(),
917 vnic
->rxDoneData
|= Regs::RxDone_TcpPacket
;
919 if (cksum(tcp
) != 0) {
920 DPRINTF(EthernetCksum
, "Rx TCP Checksum Error\n");
921 vnic
->rxDoneData
|= Regs::RxDone_TcpError
;
924 vnic
->rxDoneData
|= Regs::RxDone_UdpPacket
;
926 if (cksum(udp
) != 0) {
927 DPRINTF(EthernetCksum
, "Rx UDP Checksum Error\n");
928 vnic
->rxDoneData
|= Regs::RxDone_UdpError
;
933 rxState
= rxBeginCopy
;
937 if (dmaPending() || getState() != Running
)
940 rxDmaAddr
= params()->platform
->pciToDma(
941 Regs::get_RxData_Addr(vnic
->RxData
));
942 rxDmaLen
= std::min
<int>(Regs::get_RxData_Len(vnic
->RxData
),
943 vnic
->rxPacketBytes
);
944 rxDmaData
= (*vnic
->rxPacket
)->data
+ vnic
->rxPacketOffset
;
946 if (rxDmaAddr
== 1LL) {
947 rxState
= rxCopyDone
;
952 dmaWrite(rxDmaAddr
, rxDmaLen
, &rxDmaEvent
, rxDmaData
);
956 DPRINTF(EthernetSM
, "receive machine still copying\n");
960 vnic
->RxDone
= vnic
->rxDoneData
;
961 vnic
->RxDone
|= Regs::RxDone_Complete
;
963 if (vnic
->rxPacketBytes
== rxDmaLen
) {
964 // Packet is complete. Indicate how many bytes were copied
965 vnic
->RxDone
= Regs::set_RxDone_CopyLen(vnic
->RxDone
, rxDmaLen
);
968 "rxKick: packet complete on vnic %d (rxunique %d)\n",
969 rxActive
, vnic
->rxUnique
);
970 rxFifo
.remove(vnic
->rxPacket
);
971 vnic
->rxPacket
= rxFifo
.end();
973 vnic
->rxPacketBytes
-= rxDmaLen
;
974 vnic
->rxPacketOffset
+= rxDmaLen
;
975 vnic
->RxDone
|= Regs::RxDone_More
;
976 vnic
->RxDone
= Regs::set_RxDone_CopyLen(vnic
->RxDone
,
977 vnic
->rxPacketBytes
);
979 "rxKick: packet not complete on vnic %d (rxunique %d): "
981 rxActive
, vnic
->rxUnique
, vnic
->rxPacketBytes
);
985 rxState
= rxBusy
.empty() && rxList
.empty() ? rxIdle
: rxFifoBlock
;
987 if (rxFifo
.empty()) {
988 devIntrPost(Regs::Intr_RxEmpty
);
992 if (rxFifo
.size() < params()->rx_fifo_low_mark
)
995 if (rxFifo
.size() > params()->rx_fifo_threshold
)
998 devIntrPost(Regs::Intr_RxDMA
);
1002 panic("Invalid rxState!");
1005 DPRINTF(EthernetSM
, "entering next rxState=%s\n",
1006 RxStateStrings
[rxState
]);
1012 * @todo do we want to schedule a future kick?
1014 DPRINTF(EthernetSM
, "rx state machine exited rxState=%s\n",
1015 RxStateStrings
[rxState
]);
1021 assert(txState
== txCopy
);
1022 txState
= txCopyDone
;
1023 DPRINTF(EthernetDMA
, "tx dma read paddr=%#x len=%d\n",
1024 txDmaAddr
, txDmaLen
);
1025 DDUMP(EthernetData
, txDmaData
, txDmaLen
);
1027 // If the receive state machine has a pending DMA, let it go first
1028 if (rxState
== rxBeginCopy
)
1037 if (txFifo
.empty()) {
1038 DPRINTF(Ethernet
, "nothing to transmit\n");
1042 uint32_t interrupts
;
1043 EthPacketPtr packet
= txFifo
.front();
1044 if (!interface
->sendPacket(packet
)) {
1045 DPRINTF(Ethernet
, "Packet Transmit: failed txFifo available %d\n",
1052 if (DTRACE(Ethernet
)) {
1055 DPRINTF(Ethernet
, "ID is %d\n", ip
->id());
1059 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1060 tcp
->sport(), tcp
->dport(), tcp
->seq(),
1067 DDUMP(EthernetData
, packet
->data
, packet
->length
);
1068 txBytes
+= packet
->length
;
1071 DPRINTF(Ethernet
, "Packet Transmit: successful txFifo Available %d\n",
1074 interrupts
= Regs::Intr_TxPacket
;
1075 if (txFifo
.size() < regs
.TxFifoMark
)
1076 interrupts
|= Regs::Intr_TxLow
;
1077 devIntrPost(interrupts
);
1080 if (!txFifo
.empty() && !txEvent
.scheduled()) {
1081 DPRINTF(Ethernet
, "reschedule transmit\n");
1082 txEvent
.schedule(curTick
+ retryTime
);
1090 DPRINTF(EthernetSM
, "txKick: txState=%s (txFifo.size=%d)\n",
1091 TxStateStrings
[txState
], txFifo
.size());
1093 if (txKickTick
> curTick
) {
1094 DPRINTF(EthernetSM
, "txKick: exiting, can't run till %d\n",
1100 if (txState
== txIdle
)
1103 assert(!txList
.empty());
1104 vnic
= &virtualRegs
[txList
.front()];
1108 assert(Regs::get_TxDone_Busy(vnic
->TxDone
));
1110 // Grab a new packet from the fifo.
1111 txPacket
= new EthPacketData(16384);
1115 if (txFifo
.avail() - txPacket
->length
<
1116 Regs::get_TxData_Len(vnic
->TxData
)) {
1117 DPRINTF(EthernetSM
, "transmit fifo full. Nothing to do.\n");
1121 txState
= txBeginCopy
;
1125 if (dmaPending() || getState() != Running
)
1128 txDmaAddr
= params()->platform
->pciToDma(
1129 Regs::get_TxData_Addr(vnic
->TxData
));
1130 txDmaLen
= Regs::get_TxData_Len(vnic
->TxData
);
1131 txDmaData
= txPacket
->data
+ txPacketOffset
;
1134 dmaRead(txDmaAddr
, txDmaLen
, &txDmaEvent
, txDmaData
);
1138 DPRINTF(EthernetSM
, "transmit machine still copying\n");
1142 vnic
->TxDone
= txDmaLen
| Regs::TxDone_Complete
;
1143 txPacket
->length
+= txDmaLen
;
1144 if ((vnic
->TxData
& Regs::TxData_More
)) {
1145 txPacketOffset
+= txDmaLen
;
1147 devIntrPost(Regs::Intr_TxDMA
);
1151 assert(txPacket
->length
<= txFifo
.avail());
1152 if ((vnic
->TxData
& Regs::TxData_Checksum
)) {
1158 tcp
->sum(cksum(tcp
));
1165 udp
->sum(cksum(udp
));
1175 txFifo
.push(txPacket
);
1176 if (txFifo
.avail() < regs
.TxMaxCopy
) {
1177 devIntrPost(Regs::Intr_TxFull
);
1183 txState
= txList
.empty() ? txIdle
: txFifoBlock
;
1184 devIntrPost(Regs::Intr_TxDMA
);
1188 panic("Invalid txState!");
1191 DPRINTF(EthernetSM
, "entering next txState=%s\n",
1192 TxStateStrings
[txState
]);
1198 * @todo do we want to schedule a future kick?
1200 DPRINTF(EthernetSM
, "tx state machine exited txState=%s\n",
1201 TxStateStrings
[txState
]);
1205 Device::transferDone()
1207 if (txFifo
.empty()) {
1208 DPRINTF(Ethernet
, "transfer complete: txFifo empty...nothing to do\n");
1212 DPRINTF(Ethernet
, "transfer complete: data in txFifo...schedule xmit\n");
1214 txEvent
.reschedule(curTick
+ ticks(1), true);
1218 Device::rxFilter(const EthPacketPtr
&packet
)
1220 if (!Regs::get_Config_Filter(regs
.Config
))
1223 panic("receive filter not implemented\n");
1229 EthHdr
*eth
= packet
->eth();
1230 if (eth
->unicast()) {
1231 // If we're accepting all unicast addresses
1235 // If we make a perfect match
1236 if (acceptPerfect
&& params
->eaddr
== eth
.dst())
1239 if (acceptArp
&& eth
->type() == ETH_TYPE_ARP
)
1242 } else if (eth
->broadcast()) {
1243 // if we're accepting broadcasts
1244 if (acceptBroadcast
)
1247 } else if (eth
->multicast()) {
1248 // if we're accepting all multicasts
1249 if (acceptMulticast
)
1255 DPRINTF(Ethernet
, "rxFilter drop\n");
1256 DDUMP(EthernetData
, packet
->data
, packet
->length
);
1263 Device::recvPacket(EthPacketPtr packet
)
1265 rxBytes
+= packet
->length
;
1268 DPRINTF(Ethernet
, "Receiving packet from wire, rxFifo Available is %d\n",
1272 DPRINTF(Ethernet
, "receive disabled...packet dropped\n");
1276 if (rxFilter(packet
)) {
1277 DPRINTF(Ethernet
, "packet filtered...dropped\n");
1281 if (rxFifo
.size() >= regs
.RxFifoMark
)
1282 devIntrPost(Regs::Intr_RxHigh
);
1284 if (!rxFifo
.push(packet
)) {
1286 "packet will not fit in receive buffer...packet dropped\n");
1290 // If we were at the last element, back up one ot go to the new
1291 // last element of the list.
1292 if (rxFifoPtr
== rxFifo
.end())
1295 devIntrPost(Regs::Intr_RxPacket
);
1303 SimObject::resume();
1305 // During drain we could have left the state machines in a waiting state and
1306 // they wouldn't get out until some other event occured to kick them.
1307 // This way they'll get out immediately
1312 //=====================================================================
1316 Base::serialize(std::ostream
&os
)
1318 // Serialize the PciDev base class
1319 PciDev::serialize(os
);
1321 SERIALIZE_SCALAR(rxEnable
);
1322 SERIALIZE_SCALAR(txEnable
);
1323 SERIALIZE_SCALAR(cpuIntrEnable
);
1326 * Keep track of pending interrupt status.
1328 SERIALIZE_SCALAR(intrTick
);
1329 SERIALIZE_SCALAR(cpuPendingIntr
);
1330 Tick intrEventTick
= 0;
1332 intrEventTick
= intrEvent
->when();
1333 SERIALIZE_SCALAR(intrEventTick
);
1337 Base::unserialize(Checkpoint
*cp
, const std::string
§ion
)
1339 // Unserialize the PciDev base class
1340 PciDev::unserialize(cp
, section
);
1342 UNSERIALIZE_SCALAR(rxEnable
);
1343 UNSERIALIZE_SCALAR(txEnable
);
1344 UNSERIALIZE_SCALAR(cpuIntrEnable
);
1347 * Keep track of pending interrupt status.
1349 UNSERIALIZE_SCALAR(intrTick
);
1350 UNSERIALIZE_SCALAR(cpuPendingIntr
);
1352 UNSERIALIZE_SCALAR(intrEventTick
);
1353 if (intrEventTick
) {
1354 intrEvent
= new IntrEvent(this, intrEventTick
, true);
1359 Device::serialize(std::ostream
&os
)
1363 // Serialize the PciDev base class
1364 Base::serialize(os
);
1366 if (rxState
== rxCopy
)
1367 panic("can't serialize with an in flight dma request rxState=%s",
1368 RxStateStrings
[rxState
]);
1370 if (txState
== txCopy
)
1371 panic("can't serialize with an in flight dma request txState=%s",
1372 TxStateStrings
[txState
]);
1375 * Serialize the device registers
1377 SERIALIZE_SCALAR(regs
.Config
);
1378 SERIALIZE_SCALAR(regs
.IntrStatus
);
1379 SERIALIZE_SCALAR(regs
.IntrMask
);
1380 SERIALIZE_SCALAR(regs
.RxMaxCopy
);
1381 SERIALIZE_SCALAR(regs
.TxMaxCopy
);
1382 SERIALIZE_SCALAR(regs
.RxMaxIntr
);
1383 SERIALIZE_SCALAR(regs
.VirtualCount
);
1384 SERIALIZE_SCALAR(regs
.RxData
);
1385 SERIALIZE_SCALAR(regs
.RxDone
);
1386 SERIALIZE_SCALAR(regs
.TxData
);
1387 SERIALIZE_SCALAR(regs
.TxDone
);
1390 * Serialize the virtual nic state
1392 int virtualRegsSize
= virtualRegs
.size();
1393 SERIALIZE_SCALAR(virtualRegsSize
);
1394 for (int i
= 0; i
< virtualRegsSize
; ++i
) {
1395 VirtualReg
*vnic
= &virtualRegs
[i
];
1397 std::string reg
= csprintf("vnic%d", i
);
1398 paramOut(os
, reg
+ ".RxData", vnic
->RxData
);
1399 paramOut(os
, reg
+ ".RxDone", vnic
->RxDone
);
1400 paramOut(os
, reg
+ ".TxData", vnic
->TxData
);
1401 paramOut(os
, reg
+ ".TxDone", vnic
->TxDone
);
1403 bool rxPacketExists
= vnic
->rxPacket
!= rxFifo
.end();
1404 paramOut(os
, reg
+ ".rxPacketExists", rxPacketExists
);
1405 if (rxPacketExists
) {
1407 PacketFifo::iterator i
= rxFifo
.begin();
1408 while (i
!= vnic
->rxPacket
) {
1409 assert(i
!= rxFifo
.end());
1414 paramOut(os
, reg
+ ".rxPacket", rxPacket
);
1415 paramOut(os
, reg
+ ".rxPacketOffset", vnic
->rxPacketOffset
);
1416 paramOut(os
, reg
+ ".rxPacketBytes", vnic
->rxPacketBytes
);
1418 paramOut(os
, reg
+ ".rxDoneData", vnic
->rxDoneData
);
1421 int rxFifoPtr
= rxFifo
.countPacketsBefore(this->rxFifoPtr
);
1422 SERIALIZE_SCALAR(rxFifoPtr
);
1424 SERIALIZE_SCALAR(rxActive
);
1426 VirtualList::iterator i
, end
;
1427 for (count
= 0, i
= rxList
.begin(), end
= rxList
.end(); i
!= end
; ++i
)
1428 paramOut(os
, csprintf("rxList%d", count
++), *i
);
1429 int rxListSize
= count
;
1430 SERIALIZE_SCALAR(rxListSize
);
1432 for (count
= 0, i
= rxBusy
.begin(), end
= rxBusy
.end(); i
!= end
; ++i
)
1433 paramOut(os
, csprintf("rxBusy%d", count
++), *i
);
1434 int rxBusySize
= count
;
1435 SERIALIZE_SCALAR(rxBusySize
);
1437 for (count
= 0, i
= txList
.begin(), end
= txList
.end(); i
!= end
; ++i
)
1438 paramOut(os
, csprintf("txList%d", count
++), *i
);
1439 int txListSize
= count
;
1440 SERIALIZE_SCALAR(txListSize
);
1443 * Serialize rx state machine
1445 int rxState
= this->rxState
;
1446 SERIALIZE_SCALAR(rxState
);
1447 SERIALIZE_SCALAR(rxEmpty
);
1448 SERIALIZE_SCALAR(rxLow
);
1449 rxFifo
.serialize("rxFifo", os
);
1452 * Serialize tx state machine
1454 int txState
= this->txState
;
1455 SERIALIZE_SCALAR(txState
);
1456 SERIALIZE_SCALAR(txFull
);
1457 txFifo
.serialize("txFifo", os
);
1458 bool txPacketExists
= txPacket
;
1459 SERIALIZE_SCALAR(txPacketExists
);
1460 if (txPacketExists
) {
1461 txPacket
->serialize("txPacket", os
);
1462 SERIALIZE_SCALAR(txPacketOffset
);
1463 SERIALIZE_SCALAR(txPacketBytes
);
1467 * If there's a pending transmit, store the time so we can
1468 * reschedule it later
1470 Tick transmitTick
= txEvent
.scheduled() ? txEvent
.when() - curTick
: 0;
1471 SERIALIZE_SCALAR(transmitTick
);
1475 Device::unserialize(Checkpoint
*cp
, const std::string
§ion
)
1477 // Unserialize the PciDev base class
1478 Base::unserialize(cp
, section
);
1481 * Unserialize the device registers
1483 UNSERIALIZE_SCALAR(regs
.Config
);
1484 UNSERIALIZE_SCALAR(regs
.IntrStatus
);
1485 UNSERIALIZE_SCALAR(regs
.IntrMask
);
1486 UNSERIALIZE_SCALAR(regs
.RxMaxCopy
);
1487 UNSERIALIZE_SCALAR(regs
.TxMaxCopy
);
1488 UNSERIALIZE_SCALAR(regs
.RxMaxIntr
);
1489 UNSERIALIZE_SCALAR(regs
.VirtualCount
);
1490 UNSERIALIZE_SCALAR(regs
.RxData
);
1491 UNSERIALIZE_SCALAR(regs
.RxDone
);
1492 UNSERIALIZE_SCALAR(regs
.TxData
);
1493 UNSERIALIZE_SCALAR(regs
.TxDone
);
1495 UNSERIALIZE_SCALAR(rxActive
);
1498 UNSERIALIZE_SCALAR(rxListSize
);
1500 for (int i
= 0; i
< rxListSize
; ++i
) {
1502 paramIn(cp
, section
, csprintf("rxList%d", i
), value
);
1503 rxList
.push_back(value
);
1507 UNSERIALIZE_SCALAR(rxBusySize
);
1509 for (int i
= 0; i
< rxBusySize
; ++i
) {
1511 paramIn(cp
, section
, csprintf("rxBusy%d", i
), value
);
1512 rxBusy
.push_back(value
);
1516 UNSERIALIZE_SCALAR(txListSize
);
1518 for (int i
= 0; i
< txListSize
; ++i
) {
1520 paramIn(cp
, section
, csprintf("txList%d", i
), value
);
1521 txList
.push_back(value
);
1525 * Unserialize rx state machine
1528 UNSERIALIZE_SCALAR(rxState
);
1529 UNSERIALIZE_SCALAR(rxEmpty
);
1530 UNSERIALIZE_SCALAR(rxLow
);
1531 this->rxState
= (RxState
) rxState
;
1532 rxFifo
.unserialize("rxFifo", cp
, section
);
1535 UNSERIALIZE_SCALAR(rxFifoPtr
);
1536 this->rxFifoPtr
= rxFifo
.begin();
1537 for (int i
= 0; i
< rxFifoPtr
; ++i
)
1541 * Unserialize tx state machine
1544 UNSERIALIZE_SCALAR(txState
);
1545 UNSERIALIZE_SCALAR(txFull
);
1546 this->txState
= (TxState
) txState
;
1547 txFifo
.unserialize("txFifo", cp
, section
);
1548 bool txPacketExists
;
1549 UNSERIALIZE_SCALAR(txPacketExists
);
1551 if (txPacketExists
) {
1552 txPacket
= new EthPacketData(16384);
1553 txPacket
->unserialize("txPacket", cp
, section
);
1554 UNSERIALIZE_SCALAR(txPacketOffset
);
1555 UNSERIALIZE_SCALAR(txPacketBytes
);
1559 * unserialize the virtual nic registers/state
1561 * this must be done after the unserialization of the rxFifo
1562 * because the packet iterators depend on the fifo being populated
1564 int virtualRegsSize
;
1565 UNSERIALIZE_SCALAR(virtualRegsSize
);
1566 virtualRegs
.clear();
1567 virtualRegs
.resize(virtualRegsSize
);
1568 for (int i
= 0; i
< virtualRegsSize
; ++i
) {
1569 VirtualReg
*vnic
= &virtualRegs
[i
];
1570 std::string reg
= csprintf("vnic%d", i
);
1572 paramIn(cp
, section
, reg
+ ".RxData", vnic
->RxData
);
1573 paramIn(cp
, section
, reg
+ ".RxDone", vnic
->RxDone
);
1574 paramIn(cp
, section
, reg
+ ".TxData", vnic
->TxData
);
1575 paramIn(cp
, section
, reg
+ ".TxDone", vnic
->TxDone
);
1577 vnic
->rxUnique
= rxUnique
++;
1578 vnic
->txUnique
= txUnique
++;
1580 bool rxPacketExists
;
1581 paramIn(cp
, section
, reg
+ ".rxPacketExists", rxPacketExists
);
1582 if (rxPacketExists
) {
1584 paramIn(cp
, section
, reg
+ ".rxPacket", rxPacket
);
1585 vnic
->rxPacket
= rxFifo
.begin();
1589 paramIn(cp
, section
, reg
+ ".rxPacketOffset",
1590 vnic
->rxPacketOffset
);
1591 paramIn(cp
, section
, reg
+ ".rxPacketBytes", vnic
->rxPacketBytes
);
1593 vnic
->rxPacket
= rxFifo
.end();
1595 paramIn(cp
, section
, reg
+ ".rxDoneData", vnic
->rxDoneData
);
1599 * If there's a pending transmit, reschedule it now
1602 UNSERIALIZE_SCALAR(transmitTick
);
1604 txEvent
.schedule(curTick
+ transmitTick
);
1606 pioPort
->sendStatusChange(Port::RangeChange
);
1610 /* namespace Sinic */ }
1613 SinicParams::create()
1615 return new Sinic::Device(this);