39#include "debug/EthernetAll.hh"
49using namespace networking;
79 intrDelay(
p.intr_delay), intrTick(0), cpuIntrEnable(false),
80 cpuPendingIntr(false), intrEvent(0), interface(NULL)
85 :
Base(
p), rxUnique(0), txUnique(0),
86 virtualRegs(
p.virtual_count < 1 ? 1 :
p.virtual_count),
87 rxFifo(
p.rx_fifo_size), txFifo(
p.tx_fifo_size),
88 rxKickTick(0), txKickTick(0),
90 rxDmaEvent([
this]{ rxDmaDone(); },
name()),
91 txDmaEvent([
this]{ txDmaDone(); },
name()),
92 dmaReadDelay(
p.dma_read_delay), dmaReadFactor(
p.dma_read_factor),
93 dmaWriteDelay(
p.dma_write_delay), dmaWriteFactor(
p.dma_write_factor),
94 sinicDeviceStats(
this)
96 interface = new Interface(
name() +
".int0", this);
104 : statistics::
Group(parent,
"SinicDevice"),
105 ADD_STAT(totalVnicDistance, statistics::units::Count::get(),
106 "Total vnic distance"),
107 ADD_STAT(numVnicDistance, statistics::units::Count::get(),
108 "Number of vnic distance measurements"),
109 ADD_STAT(maxVnicDistance, statistics::units::Count::get(),
110 "Maximum vnic distance"),
111 ADD_STAT(avgVnicDistance, statistics::units::Rate<
112 statistics::units::Count, statistics::units::Count>::get(),
113 "Average vnic distance", totalVnicDistance / numVnicDistance),
129 if (if_name ==
"interface")
140 panic(
"Trying to access a vnic that doesn't exist %d > %d\n",
151 using namespace registers;
157 uint64_t rxdone = vnic.
RxDone;
160 rxdone = set_RxDone_High(rxdone,
rxFifo.
size() >
regs.RxFifoHigh);
161 rxdone = set_RxDone_NotHigh(rxdone,
rxLow);
163 regs.RxDone = rxdone;
164 regs.RxWait = rxdone;
167 uint64_t txdone = vnic.
TxDone;
172 regs.TxDone = txdone;
173 regs.TxWait = txdone;
179 if (vnic != -1 &&
virtualRegs[vnic].rxPacketOffset > 0)
183 regs.RxStatus = set_RxStatus_Head(
regs.RxStatus, head);
204 assert(
BARs[0]->range().contains(daddr));
205 daddr -=
BARs[0]->addr();
212 panic(
"invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
218 panic(
"read %s (write only): "
219 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
224 panic(
"read %s (invalid size): "
225 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
231 [[maybe_unused]] uint64_t value = 0;
245 "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
250 if (raddr == registers::IntrStatus)
295 assert(
BARs[0]->range().contains(daddr));
296 daddr -=
BARs[0]->addr();
303 panic(
"invalid register: cpu=%d, da=%#x pa=%#x size=%d",
308 panic(
"write %s (read only): "
309 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
313 panic(
"write %s (invalid size): "
314 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
320 "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
322 pkt->
getLE<uint32_t>() : pkt->
getLE<uint64_t>(),
328 case registers::Config:
332 case registers::Command:
336 case registers::IntrStatus:
338 pkt->
getLE<uint32_t>());
341 case registers::IntrMask:
345 case registers::RxData:
346 if (registers::get_RxDone_Busy(vnic.
RxDone))
347 panic(
"receive machine busy with another request! rxState=%s",
351 vnic.
RxDone = registers::RxDone_Busy;
355 if (registers::get_RxData_Vaddr(pkt->
getLE<uint64_t>())) {
356 panic(
"vtophys not implemented in newmem");
358 DPRINTF(EthernetPIO,
"write RxData vnic %d (rxunique %d)\n",
363 DPRINTF(EthernetPIO,
"request new packet...appending to rxList\n");
366 DPRINTF(EthernetPIO,
"packet exists...appending to rxBusy\n");
376 case registers::TxData:
377 if (registers::get_TxDone_Busy(vnic.
TxDone))
378 panic(
"transmit machine busy with another request! txState=%s",
382 vnic.
TxDone = registers::TxDone_Busy;
384 if (registers::get_TxData_Vaddr(pkt->
getLE<uint64_t>())) {
385 panic(
"vtophys won't work here in newmem.\n");
387 DPRINTF(EthernetPIO,
"write TxData vnic %d (txunique %d)\n",
406 if ((interrupts & registers::Intr_Res))
407 panic(
"Cannot set a reserved interrupt");
409 regs.IntrStatus |= interrupts;
412 "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
413 interrupts,
regs.IntrStatus,
regs.IntrMask);
415 interrupts =
regs.IntrStatus &
regs.IntrMask;
422 interrupts &= ~registers::Intr_RxHigh;
429 interrupts &= ~registers::Intr_TxLow;
433 if ((interrupts & registers::Intr_NoDelay) == 0)
442 if ((interrupts & registers::Intr_Res))
443 panic(
"Cannot clear a reserved interrupt");
445 regs.IntrStatus &= ~interrupts;
448 "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
449 interrupts,
regs.IntrStatus,
regs.IntrMask);
451 if (!(
regs.IntrStatus &
regs.IntrMask))
458 if (
regs.IntrMask == newmask)
461 regs.IntrMask = newmask;
464 "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
467 if (
regs.IntrStatus &
regs.IntrMask)
488 DPRINTF(EthernetIntr,
"interrupts not enabled.\n",
494 DPRINTF(EthernetIntr,
"don't need to schedule event...intrTick=%d\n",
504 DPRINTF(EthernetIntr,
"going to schedule an interrupt for intrTick=%d\n",
528 "would send an interrupt now, but there's already pending\n");
533 DPRINTF(EthernetIntr,
"posting interrupt\n");
553 DPRINTF(EthernetIntr,
"clearing cchip interrupt\n");
564 uint32_t changed =
regs.Config ^ newconf;
568 regs.Config = newconf;
570 if ((changed & registers::Config_IntEn)) {
573 if (
regs.IntrStatus &
regs.IntrMask)
580 if ((changed & registers::Config_TxEn)) {
586 if ((changed & registers::Config_RxEn)) {
596 if (
command & registers::Command_Intr)
599 if (
command & registers::Command_Reset)
606 using namespace registers;
612 regs.Config |= Config_RxThread;
614 regs.Config |= Config_TxThread;
616 regs.Config |= Config_RSS;
618 regs.Config |= Config_ZeroCopy;
620 regs.Config |= Config_DelayCopy;
621 if (
params().virtual_addr)
622 regs.Config |= Config_Vaddr;
625 panic(
"Can't delay copy and zero copy");
627 regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
631 regs.ZeroCopyMark =
params().zero_copy_threshold;
642 if (
regs.RxMaxCopy <
regs.ZeroCopyMark)
643 panic(
"Must be able to copy at least as many bytes as the threshold");
645 if (
regs.ZeroCopySize >=
regs.ZeroCopyMark)
646 panic(
"The number of bytes to copy must be less than the threshold");
669 for (
int i = 0;
i < size; ++
i)
678 DPRINTF(EthernetDMA,
"end rx dma write paddr=%#x len=%d\n",
694 DPRINTF(EthernetSM,
"rxKick: rxState=%s (rxFifo.size=%d)\n",
698 DPRINTF(EthernetSM,
"rxKick: exiting, can't run till %d\n",
712 DPRINTF(EthernetSM,
"processing rxState=%s\n",
717 "processing rxState=%s for vnic %d (rxunique %d)\n",
723 if (debug::EthernetSM) {
726 for (
int i = 0;
i < size; ++
i) {
728 bool busy = registers::get_RxDone_Busy(vn->
RxDone);
744 "vnic %d %s (rxunique %d), packet %d, slack %d\n",
750 DPRINTF(EthernetSM,
"vnic %d unmapped (rxunique %d)\n",
762 panic(
"continuing vnic without packet\n");
765 "continue processing for vnic %d (rxunique %d)\n",
782 DPRINTF(EthernetSM,
"receive waiting for data. Nothing to do.\n");
787 panic(
"Not idle, but nothing to do!");
796 "processing new packet for vnic %d (rxunique %d)\n",
811 DPRINTF(Ethernet,
"ID is %d\n", ip->id());
812 vnic->
rxDoneData |= registers::RxDone_IpPacket;
814 if (
cksum(ip) != 0) {
815 DPRINTF(EthernetCksum,
"Rx IP Checksum Error\n");
816 vnic->
rxDoneData |= registers::RxDone_IpError;
822 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
823 tcp->sport(), tcp->dport(), tcp->seq(),
825 vnic->
rxDoneData |= registers::RxDone_TcpPacket;
827 if (
cksum(tcp) != 0) {
828 DPRINTF(EthernetCksum,
"Rx TCP Checksum Error\n");
829 vnic->
rxDoneData |= registers::RxDone_TcpError;
832 vnic->
rxDoneData |= registers::RxDone_UdpPacket;
834 if (
cksum(udp) != 0) {
835 DPRINTF(EthernetCksum,
"Rx UDP Checksum Error\n");
836 vnic->
rxDoneData |= registers::RxDone_UdpError;
849 rxDmaLen = std::min<unsigned>(registers::get_RxData_Len(vnic->
RxData),
856 if ((registers::get_Config_ZeroCopy(
regs.Config) ||
857 registers::get_Config_DelayCopy(
regs.Config)) &&
858 !registers::get_RxData_NoDelay(vnic->
RxData) &&
rxLow) {
873 DPRINTF(EthernetSM,
"receive machine still copying\n");
878 vnic->
RxDone |= registers::RxDone_Complete;
890 "rxKick: packet complete on vnic %d (rxunique %d)\n",
901 vnic->
RxDone |= registers::RxDone_More;
902 vnic->
RxDone = registers::set_RxDone_CopyLen(vnic->
RxDone,
905 "rxKick: packet not complete on vnic %d (rxunique %d): "
928 panic(
"Invalid rxState!");
931 DPRINTF(EthernetSM,
"entering next rxState=%s\n",
940 DPRINTF(EthernetSM,
"rx state machine exited rxState=%s\n",
949 DPRINTF(EthernetDMA,
"tx dma read paddr=%#x len=%d\n",
964 DPRINTF(Ethernet,
"nothing to transmit\n");
971 DPRINTF(Ethernet,
"Packet Transmit: failed txFifo available %d\n",
978 if (debug::Ethernet) {
981 DPRINTF(Ethernet,
"ID is %d\n", ip->id());
985 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
986 tcp->sport(), tcp->dport(), tcp->seq(),
993 DDUMP(EthernetData, packet->data, packet->length);
997 DPRINTF(Ethernet,
"Packet Transmit: successful txFifo Available %d\n",
1000 interrupts = registers::Intr_TxPacket;
1002 interrupts |= registers::Intr_TxLow;
1010 DPRINTF(EthernetSM,
"txKick: txState=%s (txFifo.size=%d)\n",
1014 DPRINTF(EthernetSM,
"txKick: exiting, can't run till %d\n",
1028 assert(registers::get_TxDone_Busy(vnic->
TxDone));
1031 txPacket = std::make_shared<EthPacketData>(16384);
1036 registers::get_TxData_Len(vnic->
TxData)) {
1037 DPRINTF(EthernetSM,
"transmit fifo full. Nothing to do.\n");
1057 DPRINTF(EthernetSM,
"transmit machine still copying\n");
1064 if ((vnic->
TxData & registers::TxData_More)) {
1072 if ((vnic->
TxData & registers::TxData_Checksum)) {
1078 tcp->sum(
cksum(tcp));
1108 panic(
"Invalid txState!");
1111 DPRINTF(EthernetSM,
"entering next txState=%s\n",
1120 DPRINTF(EthernetSM,
"tx state machine exited txState=%s\n",
1128 DPRINTF(Ethernet,
"transfer complete: txFifo empty...nothing to do\n");
1132 DPRINTF(Ethernet,
"transfer complete: data in txFifo...schedule xmit\n");
1140 if (!registers::get_Config_Filter(
regs.Config))
1143 panic(
"receive filter not implemented\n");
1154 DPRINTF(Ethernet,
"Receiving packet from wire, rxFifo Available is %d\n",
1158 DPRINTF(Ethernet,
"receive disabled...packet dropped\n");
1163 DPRINTF(Ethernet,
"packet filtered...dropped\n");
1172 "packet will not fit in receive buffer...packet dropped\n");
1216 Tick intrEventTick = 0;
1239 if (intrEventTick) {
1255 panic(
"can't serialize with an in flight dma request rxState=%s",
1259 panic(
"can't serialize with an in flight dma request txState=%s",
1276 for (
int i = 0;
i < virtualRegsSize; ++
i) {
1286 paramOut(cp,
reg +
".rxPacketExists", rxPacketExists);
1287 if (rxPacketExists) {
1313 VirtualList::const_iterator
i, end;
1316 int rxListSize =
count;
1321 int rxBusySize =
count;
1326 int txListSize =
count;
1345 bool txPacketExists =
txPacket !=
nullptr;
1347 if (txPacketExists) {
1348 txPacket->serialize(
"txPacket", cp);
1384 for (
int i = 0;
i < rxListSize; ++
i) {
1393 for (
int i = 0;
i < rxBusySize; ++
i) {
1402 for (
int i = 0;
i < txListSize; ++
i) {
1436 bool txPacketExists;
1439 if (txPacketExists) {
1440 txPacket = std::make_shared<EthPacketData>(16384);
1441 txPacket->unserialize(
"txPacket", cp);
1452 int virtualRegsSize;
1456 for (
int i = 0;
i < virtualRegsSize; ++
i) {
1468 bool rxPacketExists;
1469 paramIn(cp,
reg +
".rxPacketExists", rxPacketExists);
1470 if (rxPacketExists) {
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Cycles is a wrapper class for representing cycle counts, i.e.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
void dmaRead(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Dummy class to keep the Python class hierarchy in sync with the C++ object hierarchy.
EtherDevBaseParams Params
gem5::EtherDevice::EtherDeviceStats etherDeviceStats
bool sendPacket(EthPacketPtr packet)
void serialize(const std::string &base, CheckpointOut &cp) const
Serialization stuff.
void unserialize(const std::string &base, CheckpointIn &cp)
bool push(EthPacketPtr ptr)
int countPacketsBefore(const_iterator i) const
int countPacketsAfter(const_iterator i) const
fifo_list::iterator iterator
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
void setLE(T v)
Set the value in the data pointer to v as little endian.
RequestPtr req
A pointer to the original request.
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
PCIConfig config
The current config space.
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Addr pciToDma(Addr pci_addr) const
std::array< PciBar *, 6 > BARs
PioPort< PioDevice > pioPort
The pioPort that handles the requests for us and provides us requests that it sees.
Ports are used to interface objects to each other.
void cpuIntrPost(Tick when)
EventFunctionWrapper * intrEvent
void serialize(CheckpointOut &cp) const override
Serialization stuff.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
bool cpuIntrPending() const
EventFunctionWrapper txEvent
void transmit()
Retransmit event.
bool rxFilter(const EthPacketPtr &packet)
receive address filter
void prepareRead(ContextID cpu, int index)
Tick write(PacketPtr pkt) override
IPR read of device register.
PacketFifo::iterator rxFifoPtr
uint64_t & regData64(Addr daddr)
void changeConfig(uint32_t newconfig)
device configuration
struct gem5::sinic::Device::@349 regs
device register file
bool recvPacket(EthPacketPtr packet)
device ethernet interface
void devIntrPost(uint32_t interrupts)
Interrupt management.
EventFunctionWrapper txDmaEvent
void devIntrChangeMask(uint32_t newmask)
void prepareWrite(ContextID cpu, int index)
void rxDmaDone()
DMA parameters.
RxState
Receive State Machine States.
Tick read(PacketPtr pkt) override
Memory Interface.
TxState
Transmit State Machine states.
EventFunctionWrapper rxDmaEvent
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void serialize(CheckpointOut &cp) const override
Serialization stuff.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
void command(uint32_t command)
void resetStats() override
Callback to reset stats.
virtual void drainResume() override
Resume execution after a successful drain.
gem5::sinic::Device::DeviceStats sinicDeviceStats
uint32_t & regData32(Addr daddr)
void prepareIO(ContextID cpu, int index)
void devIntrClear(uint32_t interrupts=registers::Intr_All)
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
virtual void drainResume()
Resume execution after a successful drain.
DrainState drainState() const
Return the current drain state of an object.
@ Running
Running normally.
bool scheduled() const
Determine if the current event is scheduled.
void squash()
Squash the current event.
void schedule(Event &event, Tick when)
void reschedule(Event &event, Tick when, bool always=false)
Tick when() const
Get the time that the event is scheduled.
uint16_t cksum(const IpPtr &ptr)
#define panic(...)
This implements a cprintf based panic() function.
const Params & params() const
virtual void resetStats()
Callback to reset stats.
static const int VirtualMask
static const int VirtualShift
const char * TxStateStrings[]
const char * RxStateStrings[]
const registers::Info & regInfo(Addr daddr)
bool regValid(Addr daddr)
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Tick curTick()
The universal simulation clock.
std::ostream CheckpointOut
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
uint64_t Tick
Tick count type.
int ContextID
Globally unique thread context ID.
std::string csprintf(const char *format, const Args &...args)
std::shared_ptr< EthPacketData > EthPacketPtr
Declaration of the Packet class.
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
statistics::Scalar txPackets
statistics::Scalar txIpChecksums
statistics::Scalar txBytes
statistics::Scalar rxTcpChecksums
statistics::Scalar rxPackets
statistics::Scalar txUdpChecksums
statistics::Scalar rxUdpChecksums
statistics::Scalar rxIpChecksums
statistics::Scalar txTcpChecksums
statistics::Scalar rxBytes
statistics::Scalar totalVnicDistance
statistics::Scalar maxVnicDistance
statistics::Scalar numVnicDistance
DeviceStats(statistics::Group *parent)
PacketFifo::iterator rxIndex
const std::string & name()