11156SN/A/* 21762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 31156SN/A * All rights reserved. 41156SN/A * 51156SN/A * Redistribution and use in source and binary forms, with or without 61156SN/A * modification, are permitted provided that the following conditions are 71156SN/A * met: redistributions of source code must retain the above copyright 81156SN/A * notice, this list of conditions and the following disclaimer; 91156SN/A * redistributions in binary form must reproduce the above copyright 101156SN/A * notice, this list of conditions and the following disclaimer in the 111156SN/A * documentation and/or other materials provided with the distribution; 121156SN/A * neither the name of the copyright holders nor the names of its 131156SN/A * contributors may be used to endorse or promote products derived from 141156SN/A * this software without specific prior written permission. 151156SN/A * 161156SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171156SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181156SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191156SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201156SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211156SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221156SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231156SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241156SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251156SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261156SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665SN/A * 282665SN/A * Authors: Nathan Binkert 291156SN/A */ 301156SN/A 3111263Sandreas.sandberg@arm.com#include "dev/net/sinic.hh" 3211263Sandreas.sandberg@arm.com 331156SN/A#include <deque> 342566SN/A#include <limits> 351156SN/A#include <string> 361156SN/A 379850SN/A#ifdef SINIC_VTOPHYS 384762SN/A#include "arch/vtophys.hh" 3911263Sandreas.sandberg@arm.com 409850SN/A#endif 418641SN/A#include "base/compiler.hh" 425882SN/A#include "base/debug.hh" 431156SN/A#include "base/inet.hh" 446216SN/A#include "base/types.hh" 456658SN/A#include "config/the_isa.hh" 468232SN/A#include "debug/EthernetAll.hh" 4711263Sandreas.sandberg@arm.com#include "dev/net/etherlink.hh" 482566SN/A#include "mem/packet.hh" 493348SN/A#include "mem/packet_access.hh" 501156SN/A#include "sim/eventq.hh" 511157SN/A#include "sim/stats.hh" 521156SN/A 535603SN/Ausing namespace std; 541156SN/Ausing namespace Net; 552107SN/Ausing namespace TheISA; 561156SN/A 571156SN/Anamespace Sinic { 581156SN/A 591156SN/Aconst char *RxStateStrings[] = 601156SN/A{ 611156SN/A "rxIdle", 621156SN/A "rxFifoBlock", 631156SN/A "rxBeginCopy", 641156SN/A "rxCopy", 651156SN/A "rxCopyDone" 661156SN/A}; 671156SN/A 681156SN/Aconst char *TxStateStrings[] = 691156SN/A{ 701156SN/A "txIdle", 711156SN/A "txFifoBlock", 721156SN/A "txBeginCopy", 731156SN/A "txCopy", 741156SN/A "txCopyDone" 751156SN/A}; 761156SN/A 771156SN/A 781156SN/A/////////////////////////////////////////////////////////////////////// 791156SN/A// 801156SN/A// Sinic PCI Device 811156SN/A// 824981SN/ABase::Base(const Params *p) 839339SN/A : EtherDevBase(p), rxEnable(false), txEnable(false), 841634SN/A intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), 851634SN/A cpuPendingIntr(false), intrEvent(0), interface(NULL) 861156SN/A{ 871156SN/A} 881156SN/A 894981SN/ADevice::Device(const Params *p) 902627SN/A : Base(p), rxUnique(0), txUnique(0), 912282SN/A virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count), 922627SN/A rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), 931156SN/A rxKickTick(0), txKickTick(0), 9412087Sspwilson2@wisc.edu txEvent([this]{ txEventTransmit(); }, name()), 9512087Sspwilson2@wisc.edu rxDmaEvent([this]{ rxDmaDone(); }, name()), 9612087Sspwilson2@wisc.edu txDmaEvent([this]{ txDmaDone(); }, name()), 971156SN/A dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), 981156SN/A dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) 991156SN/A{ 1004981SN/A interface = new Interface(name() + ".int0", this); 1011156SN/A reset(); 1021156SN/A 1031156SN/A} 1041156SN/A 1051156SN/ADevice::~Device() 1061156SN/A{} 1071156SN/A 1081156SN/Avoid 1091156SN/ADevice::regStats() 1101156SN/A{ 1119339SN/A Base::regStats(); 1125603SN/A 1135603SN/A _maxVnicDistance = 0; 1145603SN/A 1155603SN/A maxVnicDistance 1165603SN/A .name(name() + ".maxVnicDistance") 1175603SN/A .desc("maximum vnic distance") 1185603SN/A ; 1195603SN/A 1205603SN/A totalVnicDistance 1215603SN/A .name(name() + ".totalVnicDistance") 1225603SN/A .desc("total vnic distance") 1235603SN/A ; 1245603SN/A numVnicDistance 1255603SN/A .name(name() + ".numVnicDistance") 1265603SN/A .desc("number of vnic distance measurements") 1275603SN/A ; 1285603SN/A 1295603SN/A avgVnicDistance 1305603SN/A .name(name() + ".avgVnicDistance") 1315603SN/A .desc("average vnic distance") 1325603SN/A ; 1335603SN/A 1345603SN/A avgVnicDistance = totalVnicDistance / numVnicDistance; 1355603SN/A} 1365603SN/A 1375603SN/Avoid 1385603SN/ADevice::resetStats() 1395603SN/A{ 1409339SN/A Base::resetStats(); 1419339SN/A 1425603SN/A _maxVnicDistance = 0; 1431156SN/A} 1441156SN/A 14513784Sgabeblack@google.comPort & 14613784Sgabeblack@google.comDevice::getPort(const std::string &if_name, PortID idx) 1474981SN/A{ 14813784Sgabeblack@google.com if (if_name == "interface") 14913784Sgabeblack@google.com return *interface; 15013784Sgabeblack@google.com return EtherDevBase::getPort(if_name, idx); 1514981SN/A} 1524981SN/A 1534981SN/A 1541939SN/Avoid 15511005SN/ADevice::prepareIO(ContextID cpu, int index) 1562008SN/A{ 1572008SN/A int size = virtualRegs.size(); 1582282SN/A if (index > size) 1592282SN/A panic("Trying to access a vnic that doesn't exist %d > %d\n", 1602282SN/A index, size); 1612008SN/A} 1622008SN/A 1635603SN/A//add stats for head of line blocking 1645603SN/A//add stats for average fifo length 1655603SN/A//add stats for average number of vnics busy 1665603SN/A 1672008SN/Avoid 16811005SN/ADevice::prepareRead(ContextID cpu, int index) 1692008SN/A{ 1702008SN/A using namespace Regs; 1712008SN/A prepareIO(cpu, index); 1722008SN/A 1732008SN/A VirtualReg &vnic = virtualRegs[index]; 1742008SN/A 1752008SN/A // update rx registers 1762008SN/A uint64_t rxdone = vnic.RxDone; 1772282SN/A rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); 1782282SN/A rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); 1795603SN/A rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh); 1802282SN/A rxdone = set_RxDone_NotHigh(rxdone, rxLow); 1812008SN/A regs.RxData = vnic.RxData; 1822008SN/A regs.RxDone = rxdone; 1832008SN/A regs.RxWait = rxdone; 1842008SN/A 1852008SN/A // update tx regsiters 1862008SN/A uint64_t txdone = vnic.TxDone; 1872008SN/A txdone = set_TxDone_Packets(txdone, txFifo.packets()); 1882008SN/A txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); 1895603SN/A txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow); 1902008SN/A regs.TxData = vnic.TxData; 1912008SN/A regs.TxDone = txdone; 1922008SN/A regs.TxWait = txdone; 1935603SN/A 1945603SN/A int head = 0xffff; 1955603SN/A 1965603SN/A if (!rxFifo.empty()) { 1975603SN/A int vnic = rxFifo.begin()->priv; 1985603SN/A if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0) 1995603SN/A head = vnic; 2005603SN/A } 2015603SN/A 2025603SN/A regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head); 2035603SN/A regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount); 2045603SN/A regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount); 2055603SN/A regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount); 2062008SN/A} 2072008SN/A 2082008SN/Avoid 20911005SN/ADevice::prepareWrite(ContextID cpu, int index) 2101997SN/A{ 2112008SN/A prepareIO(cpu, index); 2121997SN/A} 2131997SN/A 2141156SN/A/** 2151939SN/A * I/O read of device register 2161156SN/A */ 2172566SN/ATick 2183349SN/ADevice::read(PacketPtr pkt) 2191156SN/A{ 2201817SN/A assert(config.command & PCI_CMD_MSE); 2212641SN/A assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 2221156SN/A 22311005SN/A ContextID cpu = pkt->req->contextId(); 2242641SN/A Addr daddr = pkt->getAddr() - BARAddrs[0]; 2252008SN/A Addr index = daddr >> Regs::VirtualShift; 2262008SN/A Addr raddr = daddr & Regs::VirtualMask; 2271997SN/A 2282008SN/A if (!regValid(raddr)) 2292617SN/A panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2302641SN/A cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2311156SN/A 2322008SN/A const Regs::Info &info = regInfo(raddr); 2331939SN/A if (!info.read) 2342279SN/A panic("read %s (write only): " 2352617SN/A "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2362641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2371939SN/A 2382279SN/A panic("read %s (invalid size): " 2392617SN/A "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2402641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2411156SN/A 2422008SN/A prepareRead(cpu, index); 2431156SN/A 2448641SN/A uint64_t value M5_VAR_USED = 0; 2452641SN/A if (pkt->getSize() == 4) { 2462566SN/A uint32_t reg = regData32(raddr); 24713342Sgabeblack@google.com pkt->setLE(reg); 2481939SN/A value = reg; 2491156SN/A } 2501156SN/A 2512641SN/A if (pkt->getSize() == 8) { 2522566SN/A uint64_t reg = regData64(raddr); 25313342Sgabeblack@google.com pkt->setLE(reg); 2541939SN/A value = reg; 2551939SN/A } 2561939SN/A 2571998SN/A DPRINTF(EthernetPIO, 2582617SN/A "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n", 2592641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value); 2601939SN/A 2611939SN/A // reading the interrupt status register has the side effect of 2621939SN/A // clearing it 2632008SN/A if (raddr == Regs::IntrStatus) 2641939SN/A devIntrClear(); 2651156SN/A 2662566SN/A return pioDelay; 2671156SN/A} 2681156SN/A 2691939SN/A/** 2701939SN/A * IPR read of device register 2712566SN/A 2722566SN/A Fault 27311005SN/ADevice::iprRead(Addr daddr, ContextID cpu, uint64_t &result) 2741939SN/A{ 2751939SN/A if (!regValid(daddr)) 2761939SN/A panic("invalid address: da=%#x", daddr); 2771939SN/A 2781939SN/A const Regs::Info &info = regInfo(daddr); 2791939SN/A if (!info.read) 2801998SN/A panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); 2811939SN/A 2821998SN/A DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", 2831998SN/A info.name, cpu, daddr); 2841939SN/A 2852008SN/A prepareRead(cpu, 0); 2861939SN/A 2871939SN/A if (info.size == 4) 2881939SN/A result = regData32(daddr); 2891939SN/A 2901939SN/A if (info.size == 8) 2911939SN/A result = regData64(daddr); 2921939SN/A 2931998SN/A DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", 2941998SN/A info.name, cpu, result); 2951939SN/A 2962090SN/A return NoFault; 2971939SN/A} 2982566SN/A*/ 2991939SN/A/** 3001939SN/A * I/O write of device register 3011939SN/A */ 3022566SN/ATick 3033349SN/ADevice::write(PacketPtr pkt) 3041156SN/A{ 3051817SN/A assert(config.command & PCI_CMD_MSE); 3062641SN/A assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 3071939SN/A 30811005SN/A ContextID cpu = pkt->req->contextId(); 3092641SN/A Addr daddr = pkt->getAddr() - BARAddrs[0]; 3102008SN/A Addr index = daddr >> Regs::VirtualShift; 3112008SN/A Addr raddr = daddr & Regs::VirtualMask; 3121997SN/A 3132008SN/A if (!regValid(raddr)) 3142566SN/A panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", 3152641SN/A cpu, daddr, pkt->getAddr(), pkt->getSize()); 3161156SN/A 3172008SN/A const Regs::Info &info = regInfo(raddr); 3181939SN/A if (!info.write) 3192279SN/A panic("write %s (read only): " 3202617SN/A "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 3212641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 3221939SN/A 3232641SN/A if (pkt->getSize() != info.size) 3242279SN/A panic("write %s (invalid size): " 3252617SN/A "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 3262641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 3271156SN/A 3282176SN/A VirtualReg &vnic = virtualRegs[index]; 3292176SN/A 3301998SN/A DPRINTF(EthernetPIO, 3312617SN/A "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", 33213342Sgabeblack@google.com info.name, index, cpu, info.size == 4 ? 33313342Sgabeblack@google.com pkt->getLE<uint32_t>() : pkt->getLE<uint64_t>(), 33413342Sgabeblack@google.com daddr, pkt->getAddr(), pkt->getSize()); 3351156SN/A 3362008SN/A prepareWrite(cpu, index); 3371156SN/A 3382008SN/A switch (raddr) { 3391156SN/A case Regs::Config: 34013342Sgabeblack@google.com changeConfig(pkt->getLE<uint32_t>()); 3411156SN/A break; 3421156SN/A 3431939SN/A case Regs::Command: 34413342Sgabeblack@google.com command(pkt->getLE<uint32_t>()); 3451156SN/A break; 3461156SN/A 3471939SN/A case Regs::IntrStatus: 34813342Sgabeblack@google.com devIntrClear(regs.IntrStatus & 34913342Sgabeblack@google.com pkt->getLE<uint32_t>()); 3501156SN/A break; 3511156SN/A 3521156SN/A case Regs::IntrMask: 35313342Sgabeblack@google.com devIntrChangeMask(pkt->getLE<uint32_t>()); 3541156SN/A break; 3551156SN/A 3561156SN/A case Regs::RxData: 3572008SN/A if (Regs::get_RxDone_Busy(vnic.RxDone)) 3581939SN/A panic("receive machine busy with another request! rxState=%s", 3591939SN/A RxStateStrings[rxState]); 3601156SN/A 3612282SN/A vnic.rxUnique = rxUnique++; 3622008SN/A vnic.RxDone = Regs::RxDone_Busy; 36313342Sgabeblack@google.com vnic.RxData = pkt->getLE<uint64_t>(); 3645603SN/A rxBusyCount++; 3652282SN/A 36613342Sgabeblack@google.com if (Regs::get_RxData_Vaddr(pkt->getLE<uint64_t>())) { 3672627SN/A panic("vtophys not implemented in newmem"); 3685603SN/A#ifdef SINIC_VTOPHYS 3695603SN/A Addr vaddr = Regs::get_RxData_Addr(reg64); 3702282SN/A Addr paddr = vtophys(req->xc, vaddr); 3712282SN/A DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " 3722282SN/A "vaddr=%#x, paddr=%#x\n", 3732282SN/A index, vnic.rxUnique, vaddr, paddr); 3742282SN/A 3755603SN/A vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr); 3765603SN/A#endif 3772282SN/A } else { 3782282SN/A DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", 3792282SN/A index, vnic.rxUnique); 3802282SN/A } 3812282SN/A 3825603SN/A if (vnic.rxIndex == rxFifo.end()) { 3832282SN/A DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); 3842282SN/A rxList.push_back(index); 3852282SN/A } else { 3862282SN/A DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n"); 3872282SN/A rxBusy.push_back(index); 3882282SN/A } 3892282SN/A 3902282SN/A if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) { 3911156SN/A rxState = rxFifoBlock; 3921156SN/A rxKick(); 3931156SN/A } 3941156SN/A break; 3951156SN/A 3961156SN/A case Regs::TxData: 3972008SN/A if (Regs::get_TxDone_Busy(vnic.TxDone)) 3981939SN/A panic("transmit machine busy with another request! txState=%s", 3991939SN/A TxStateStrings[txState]); 4001156SN/A 4012282SN/A vnic.txUnique = txUnique++; 4022008SN/A vnic.TxDone = Regs::TxDone_Busy; 4032282SN/A 40413342Sgabeblack@google.com if (Regs::get_TxData_Vaddr(pkt->getLE<uint64_t>())) { 4052617SN/A panic("vtophys won't work here in newmem.\n"); 4065603SN/A#ifdef SINIC_VTOPHYS 4075603SN/A Addr vaddr = Regs::get_TxData_Addr(reg64); 4082282SN/A Addr paddr = vtophys(req->xc, vaddr); 4095603SN/A DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): " 4102282SN/A "vaddr=%#x, paddr=%#x\n", 4112282SN/A index, vnic.txUnique, vaddr, paddr); 4122282SN/A 4135603SN/A vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr); 4145603SN/A#endif 4152282SN/A } else { 4165603SN/A DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n", 4172282SN/A index, vnic.txUnique); 4182282SN/A } 4192282SN/A 4202008SN/A if (txList.empty() || txList.front() != index) 4212008SN/A txList.push_back(index); 4222010SN/A if (txEnable && txState == txIdle && txList.front() == index) { 4231156SN/A txState = txFifoBlock; 4241156SN/A txKick(); 4251156SN/A } 4261156SN/A break; 4271156SN/A } 4282176SN/A 4292566SN/A return pioDelay; 4301156SN/A} 4311156SN/A 4321156SN/Avoid 4331156SN/ADevice::devIntrPost(uint32_t interrupts) 4341156SN/A{ 4351156SN/A if ((interrupts & Regs::Intr_Res)) 4361156SN/A panic("Cannot set a reserved interrupt"); 4371156SN/A 4381156SN/A regs.IntrStatus |= interrupts; 4391156SN/A 4401156SN/A DPRINTF(EthernetIntr, 4411156SN/A "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", 4421156SN/A interrupts, regs.IntrStatus, regs.IntrMask); 4431156SN/A 4441939SN/A interrupts = regs.IntrStatus & regs.IntrMask; 4451939SN/A 4461939SN/A // Intr_RxHigh is special, we only signal it if we've emptied the fifo 4471939SN/A // and then filled it above the high watermark 4481939SN/A if (rxEmpty) 4491939SN/A rxEmpty = false; 4501939SN/A else 4511939SN/A interrupts &= ~Regs::Intr_RxHigh; 4521939SN/A 4531939SN/A // Intr_TxLow is special, we only signal it if we've filled up the fifo 4541939SN/A // and then dropped below the low watermark 4551939SN/A if (txFull) 4561939SN/A txFull = false; 4571939SN/A else 4581939SN/A interrupts &= ~Regs::Intr_TxLow; 4591939SN/A 4601939SN/A if (interrupts) { 4617823SN/A Tick when = curTick(); 4621939SN/A if ((interrupts & Regs::Intr_NoDelay) == 0) 4631156SN/A when += intrDelay; 4641156SN/A cpuIntrPost(when); 4651156SN/A } 4661156SN/A} 4671156SN/A 4681156SN/Avoid 4691156SN/ADevice::devIntrClear(uint32_t interrupts) 4701156SN/A{ 4711156SN/A if ((interrupts & Regs::Intr_Res)) 4721156SN/A panic("Cannot clear a reserved interrupt"); 4731156SN/A 4741156SN/A regs.IntrStatus &= ~interrupts; 4751156SN/A 4761156SN/A DPRINTF(EthernetIntr, 4771156SN/A "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", 4781156SN/A interrupts, regs.IntrStatus, regs.IntrMask); 4791156SN/A 4801156SN/A if (!(regs.IntrStatus & regs.IntrMask)) 4811156SN/A cpuIntrClear(); 4821156SN/A} 4831156SN/A 4841156SN/Avoid 4851156SN/ADevice::devIntrChangeMask(uint32_t newmask) 4861156SN/A{ 4871156SN/A if (regs.IntrMask == newmask) 4881156SN/A return; 4891156SN/A 4901156SN/A regs.IntrMask = newmask; 4911156SN/A 4921156SN/A DPRINTF(EthernetIntr, 4931156SN/A "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", 4941156SN/A regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); 4951156SN/A 4961156SN/A if (regs.IntrStatus & regs.IntrMask) 4977823SN/A cpuIntrPost(curTick()); 4981156SN/A else 4991156SN/A cpuIntrClear(); 5001156SN/A} 5011156SN/A 5021156SN/Avoid 5031156SN/ABase::cpuIntrPost(Tick when) 5041156SN/A{ 5051156SN/A // If the interrupt you want to post is later than an interrupt 5061156SN/A // already scheduled, just let it post in the coming one and don't 5071156SN/A // schedule another. 5081156SN/A // HOWEVER, must be sure that the scheduled intrTick is in the 5091156SN/A // future (this was formerly the source of a bug) 5101156SN/A /** 5111156SN/A * @todo this warning should be removed and the intrTick code should 5121156SN/A * be fixed. 5131156SN/A */ 5147823SN/A assert(when >= curTick()); 5157823SN/A assert(intrTick >= curTick() || intrTick == 0); 5161156SN/A if (!cpuIntrEnable) { 5171156SN/A DPRINTF(EthernetIntr, "interrupts not enabled.\n", 5181156SN/A intrTick); 5191156SN/A return; 5201156SN/A } 5211156SN/A 5221156SN/A if (when > intrTick && intrTick != 0) { 5231156SN/A DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 5241156SN/A intrTick); 5251156SN/A return; 5261156SN/A } 5271156SN/A 5281156SN/A intrTick = when; 5297823SN/A if (intrTick < curTick()) { 5307823SN/A intrTick = curTick(); 5311156SN/A } 5321156SN/A 5331156SN/A DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 5341156SN/A intrTick); 5351156SN/A 5361156SN/A if (intrEvent) 5371156SN/A intrEvent->squash(); 53812087Sspwilson2@wisc.edu 53912087Sspwilson2@wisc.edu intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); }, 54012087Sspwilson2@wisc.edu name(), true); 5415606SN/A schedule(intrEvent, intrTick); 5421156SN/A} 5431156SN/A 5441156SN/Avoid 5451156SN/ABase::cpuInterrupt() 5461156SN/A{ 5477823SN/A assert(intrTick == curTick()); 5481156SN/A 5491156SN/A // Whether or not there's a pending interrupt, we don't care about 5501156SN/A // it anymore 5511156SN/A intrEvent = 0; 5521156SN/A intrTick = 0; 5531156SN/A 5541156SN/A // Don't send an interrupt if there's already one 5551156SN/A if (cpuPendingIntr) { 5561156SN/A DPRINTF(EthernetIntr, 5571156SN/A "would send an interrupt now, but there's already pending\n"); 5581156SN/A } else { 5591156SN/A // Send interrupt 5601156SN/A cpuPendingIntr = true; 5611156SN/A 5621156SN/A DPRINTF(EthernetIntr, "posting interrupt\n"); 5631156SN/A intrPost(); 5641156SN/A } 5651156SN/A} 5661156SN/A 5671156SN/Avoid 5681156SN/ABase::cpuIntrClear() 5691156SN/A{ 5701156SN/A if (!cpuPendingIntr) 5711156SN/A return; 5721156SN/A 5731156SN/A if (intrEvent) { 5741156SN/A intrEvent->squash(); 5751156SN/A intrEvent = 0; 5761156SN/A } 5771156SN/A 5781156SN/A intrTick = 0; 5791156SN/A 5801156SN/A cpuPendingIntr = false; 5811156SN/A 5821156SN/A DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 5831156SN/A intrClear(); 5841156SN/A} 5851156SN/A 5861156SN/Abool 5871156SN/ABase::cpuIntrPending() const 5881156SN/A{ return cpuPendingIntr; } 5891156SN/A 5901156SN/Avoid 5911156SN/ADevice::changeConfig(uint32_t newconf) 5921156SN/A{ 5931156SN/A uint32_t changed = regs.Config ^ newconf; 5941156SN/A if (!changed) 5951156SN/A return; 5961156SN/A 5971156SN/A regs.Config = newconf; 5981156SN/A 5991156SN/A if ((changed & Regs::Config_IntEn)) { 6001156SN/A cpuIntrEnable = regs.Config & Regs::Config_IntEn; 6011156SN/A if (cpuIntrEnable) { 6021156SN/A if (regs.IntrStatus & regs.IntrMask) 6037823SN/A cpuIntrPost(curTick()); 6041156SN/A } else { 6051156SN/A cpuIntrClear(); 6061156SN/A } 6071156SN/A } 6081156SN/A 6091156SN/A if ((changed & Regs::Config_TxEn)) { 6101156SN/A txEnable = regs.Config & Regs::Config_TxEn; 6111156SN/A if (txEnable) 6121156SN/A txKick(); 6131156SN/A } 6141156SN/A 6151156SN/A if ((changed & Regs::Config_RxEn)) { 6161156SN/A rxEnable = regs.Config & Regs::Config_RxEn; 6171156SN/A if (rxEnable) 6181156SN/A rxKick(); 6191156SN/A } 6201156SN/A} 6211156SN/A 6221156SN/Avoid 6231939SN/ADevice::command(uint32_t command) 6241939SN/A{ 6252008SN/A if (command & Regs::Command_Intr) 6262008SN/A devIntrPost(Regs::Intr_Soft); 6272008SN/A 6281939SN/A if (command & Regs::Command_Reset) 6291939SN/A reset(); 6301939SN/A} 6311939SN/A 6321939SN/Avoid 6331156SN/ADevice::reset() 6341156SN/A{ 6351156SN/A using namespace Regs; 6361939SN/A 6371156SN/A memset(®s, 0, sizeof(regs)); 6381939SN/A 6391939SN/A regs.Config = 0; 6402008SN/A if (params()->rx_thread) 6412008SN/A regs.Config |= Config_RxThread; 6422008SN/A if (params()->tx_thread) 6432008SN/A regs.Config |= Config_TxThread; 6442210SN/A if (params()->rss) 6452210SN/A regs.Config |= Config_RSS; 6462282SN/A if (params()->zero_copy) 6472282SN/A regs.Config |= Config_ZeroCopy; 6482282SN/A if (params()->delay_copy) 6492282SN/A regs.Config |= Config_DelayCopy; 6502282SN/A if (params()->virtual_addr) 6512282SN/A regs.Config |= Config_Vaddr; 6522282SN/A 6532282SN/A if (params()->delay_copy && params()->zero_copy) 6542282SN/A panic("Can't delay copy and zero copy"); 6552282SN/A 6562008SN/A regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; 6571156SN/A regs.RxMaxCopy = params()->rx_max_copy; 6581156SN/A regs.TxMaxCopy = params()->tx_max_copy; 6595603SN/A regs.ZeroCopySize = params()->zero_copy_size; 6605603SN/A regs.ZeroCopyMark = params()->zero_copy_threshold; 6615603SN/A regs.VirtualCount = params()->virtual_count; 6621939SN/A regs.RxMaxIntr = params()->rx_max_intr; 6631939SN/A regs.RxFifoSize = params()->rx_fifo_size; 6641939SN/A regs.TxFifoSize = params()->tx_fifo_size; 6655603SN/A regs.RxFifoLow = params()->rx_fifo_low_mark; 6665603SN/A regs.TxFifoLow = params()->tx_fifo_threshold; 6675603SN/A regs.RxFifoHigh = params()->rx_fifo_threshold; 6685603SN/A regs.TxFifoHigh = params()->tx_fifo_high_mark; 6694762SN/A regs.HwAddr = params()->hardware_address; 6701156SN/A 6715603SN/A if (regs.RxMaxCopy < regs.ZeroCopyMark) 6725603SN/A panic("Must be able to copy at least as many bytes as the threshold"); 6735603SN/A 6745603SN/A if (regs.ZeroCopySize >= regs.ZeroCopyMark) 6755603SN/A panic("The number of bytes to copy must be less than the threshold"); 6765603SN/A 6772008SN/A rxList.clear(); 6782282SN/A rxBusy.clear(); 6792282SN/A rxActive = -1; 6802008SN/A txList.clear(); 6815603SN/A rxBusyCount = 0; 6825603SN/A rxDirtyCount = 0; 6835603SN/A rxMappedCount = 0; 6842008SN/A 6851156SN/A rxState = rxIdle; 6861156SN/A txState = txIdle; 6871156SN/A 6881156SN/A rxFifo.clear(); 6892008SN/A rxFifoPtr = rxFifo.end(); 6901156SN/A txFifo.clear(); 6911939SN/A rxEmpty = false; 6922282SN/A rxLow = true; 6931939SN/A txFull = false; 6942008SN/A 6952008SN/A int size = virtualRegs.size(); 6962008SN/A virtualRegs.clear(); 6972008SN/A virtualRegs.resize(size); 6982008SN/A for (int i = 0; i < size; ++i) 6995603SN/A virtualRegs[i].rxIndex = rxFifo.end(); 7001156SN/A} 7011156SN/A 7021156SN/Avoid 7032566SN/ADevice::rxDmaDone() 7041156SN/A{ 7051156SN/A assert(rxState == rxCopy); 7061156SN/A rxState = rxCopyDone; 7072280SN/A DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", 7081156SN/A rxDmaAddr, rxDmaLen); 7091939SN/A DDUMP(EthernetData, rxDmaData, rxDmaLen); 7101939SN/A 7111939SN/A // If the transmit state machine has a pending DMA, let it go first 7121939SN/A if (txState == txBeginCopy) 7131939SN/A txKick(); 7141939SN/A 7151156SN/A rxKick(); 7161156SN/A} 7171156SN/A 7181156SN/Avoid 7191156SN/ADevice::rxKick() 7201156SN/A{ 7212282SN/A VirtualReg *vnic = NULL; 7222008SN/A 7232279SN/A DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", 7241156SN/A RxStateStrings[rxState], rxFifo.size()); 7251156SN/A 7267823SN/A if (rxKickTick > curTick()) { 7272279SN/A DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", 7281156SN/A rxKickTick); 7291156SN/A return; 7301156SN/A } 7311156SN/A 7321156SN/A next: 7335603SN/A rxFifo.check(); 7342008SN/A if (rxState == rxIdle) 7351156SN/A goto exit; 7361156SN/A 7372282SN/A if (rxActive == -1) { 7382282SN/A if (rxState != rxFifoBlock) 7392282SN/A panic("no active vnic while in state %s", RxStateStrings[rxState]); 7402008SN/A 7412282SN/A DPRINTF(EthernetSM, "processing rxState=%s\n", 7422282SN/A RxStateStrings[rxState]); 7432282SN/A } else { 7442282SN/A vnic = &virtualRegs[rxActive]; 7452282SN/A DPRINTF(EthernetSM, 7462282SN/A "processing rxState=%s for vnic %d (rxunique %d)\n", 7472282SN/A RxStateStrings[rxState], rxActive, vnic->rxUnique); 7482282SN/A } 7492008SN/A 7502008SN/A switch (rxState) { 7511156SN/A case rxFifoBlock: 7522282SN/A if (DTRACE(EthernetSM)) { 7532282SN/A PacketFifo::iterator end = rxFifo.end(); 7542282SN/A int size = virtualRegs.size(); 7552282SN/A for (int i = 0; i < size; ++i) { 7562282SN/A VirtualReg *vn = &virtualRegs[i]; 7575603SN/A bool busy = Regs::get_RxDone_Busy(vn->RxDone); 7585603SN/A if (vn->rxIndex != end) { 7598641SN/A#ifndef NDEBUG 7605603SN/A bool dirty = vn->rxPacketOffset > 0; 7615603SN/A const char *status; 7625603SN/A 7635603SN/A if (busy && dirty) 7645603SN/A status = "busy,dirty"; 7655603SN/A else if (busy) 7665603SN/A status = "busy"; 7675603SN/A else if (dirty) 7685603SN/A status = "dirty"; 7695603SN/A else 7705603SN/A status = "mapped"; 7715603SN/A 7722282SN/A DPRINTF(EthernetSM, 7735603SN/A "vnic %d %s (rxunique %d), packet %d, slack %d\n", 7745603SN/A i, status, vn->rxUnique, 7755603SN/A rxFifo.countPacketsBefore(vn->rxIndex), 7765603SN/A vn->rxIndex->slack); 7778641SN/A#endif 7785603SN/A } else if (busy) { 7795603SN/A DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n", 7805603SN/A i, vn->rxUnique); 7812282SN/A } 7822282SN/A } 7832282SN/A } 7842282SN/A 7852282SN/A if (!rxBusy.empty()) { 7862282SN/A rxActive = rxBusy.front(); 7872282SN/A rxBusy.pop_front(); 7882282SN/A vnic = &virtualRegs[rxActive]; 7892282SN/A 7905603SN/A if (vnic->rxIndex == rxFifo.end()) 7912282SN/A panic("continuing vnic without packet\n"); 7922282SN/A 7932282SN/A DPRINTF(EthernetSM, 7942282SN/A "continue processing for vnic %d (rxunique %d)\n", 7952282SN/A rxActive, vnic->rxUnique); 7962282SN/A 7971156SN/A rxState = rxBeginCopy; 7982282SN/A 7995603SN/A int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex); 8005603SN/A totalVnicDistance += vnic_distance; 8015603SN/A numVnicDistance += 1; 8025603SN/A if (vnic_distance > _maxVnicDistance) { 8035603SN/A maxVnicDistance = vnic_distance; 8045603SN/A _maxVnicDistance = vnic_distance; 8055603SN/A } 8065603SN/A 8071156SN/A break; 8081156SN/A } 8091156SN/A 8102008SN/A if (rxFifoPtr == rxFifo.end()) { 8111156SN/A DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 8121156SN/A goto exit; 8131156SN/A } 8141156SN/A 8152282SN/A if (rxList.empty()) 8162282SN/A panic("Not idle, but nothing to do!"); 8172282SN/A 8182008SN/A assert(!rxFifo.empty()); 8192008SN/A 8202282SN/A rxActive = rxList.front(); 8212282SN/A rxList.pop_front(); 8222282SN/A vnic = &virtualRegs[rxActive]; 8232282SN/A 8242282SN/A DPRINTF(EthernetSM, 8252282SN/A "processing new packet for vnic %d (rxunique %d)\n", 8262282SN/A rxActive, vnic->rxUnique); 8272282SN/A 8281156SN/A // Grab a new packet from the fifo. 8295603SN/A vnic->rxIndex = rxFifoPtr++; 8305603SN/A vnic->rxIndex->priv = rxActive; 8312008SN/A vnic->rxPacketOffset = 0; 8325603SN/A vnic->rxPacketBytes = vnic->rxIndex->packet->length; 8332008SN/A assert(vnic->rxPacketBytes); 8345603SN/A rxMappedCount++; 8351156SN/A 8362008SN/A vnic->rxDoneData = 0; 8371156SN/A /* scope for variables */ { 8385603SN/A IpPtr ip(vnic->rxIndex->packet); 8391156SN/A if (ip) { 8402280SN/A DPRINTF(Ethernet, "ID is %d\n", ip->id()); 8412008SN/A vnic->rxDoneData |= Regs::RxDone_IpPacket; 8421156SN/A rxIpChecksums++; 8431156SN/A if (cksum(ip) != 0) { 8441156SN/A DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 8452008SN/A vnic->rxDoneData |= Regs::RxDone_IpError; 8461156SN/A } 8471156SN/A TcpPtr tcp(ip); 8481156SN/A UdpPtr udp(ip); 8491156SN/A if (tcp) { 8502279SN/A DPRINTF(Ethernet, 8512279SN/A "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 8522279SN/A tcp->sport(), tcp->dport(), tcp->seq(), 8532279SN/A tcp->ack()); 8542008SN/A vnic->rxDoneData |= Regs::RxDone_TcpPacket; 8551156SN/A rxTcpChecksums++; 8561156SN/A if (cksum(tcp) != 0) { 8571156SN/A DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 8582008SN/A vnic->rxDoneData |= Regs::RxDone_TcpError; 8591156SN/A } 8601156SN/A } else if (udp) { 8612008SN/A vnic->rxDoneData |= Regs::RxDone_UdpPacket; 8621156SN/A rxUdpChecksums++; 8631156SN/A if (cksum(udp) != 0) { 8641156SN/A DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 8652008SN/A vnic->rxDoneData |= Regs::RxDone_UdpError; 8661156SN/A } 8671156SN/A } 8681156SN/A } 8691156SN/A } 8701156SN/A rxState = rxBeginCopy; 8711156SN/A break; 8721156SN/A 8731156SN/A case rxBeginCopy: 87410913SN/A if (dmaPending() || drainState() != DrainState::Running) 8751939SN/A goto exit; 8761939SN/A 87711202SN/A rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData)); 8786227SN/A rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData), 8796227SN/A vnic->rxPacketBytes); 8805603SN/A 8815603SN/A /* 8825603SN/A * if we're doing zero/delay copy and we're below the fifo 8835603SN/A * threshold, see if we should try to do the zero/defer copy 8845603SN/A */ 8855603SN/A if ((Regs::get_Config_ZeroCopy(regs.Config) || 8865603SN/A Regs::get_Config_DelayCopy(regs.Config)) && 8875603SN/A !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) { 8885603SN/A if (rxDmaLen > regs.ZeroCopyMark) 8895603SN/A rxDmaLen = regs.ZeroCopySize; 8905603SN/A } 8915603SN/A rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset; 8921939SN/A rxState = rxCopy; 8932282SN/A if (rxDmaAddr == 1LL) { 8942282SN/A rxState = rxCopyDone; 8952282SN/A break; 8962282SN/A } 8972282SN/A 8982566SN/A dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); 8991156SN/A break; 9001156SN/A 9011156SN/A case rxCopy: 9021156SN/A DPRINTF(EthernetSM, "receive machine still copying\n"); 9031156SN/A goto exit; 9041156SN/A 9051156SN/A case rxCopyDone: 9062282SN/A vnic->RxDone = vnic->rxDoneData; 9072008SN/A vnic->RxDone |= Regs::RxDone_Complete; 9085603SN/A rxBusyCount--; 9091156SN/A 9102008SN/A if (vnic->rxPacketBytes == rxDmaLen) { 9115603SN/A if (vnic->rxPacketOffset) 9125603SN/A rxDirtyCount--; 9135603SN/A 9142282SN/A // Packet is complete. Indicate how many bytes were copied 9152282SN/A vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); 9162282SN/A 9172282SN/A DPRINTF(EthernetSM, 9182282SN/A "rxKick: packet complete on vnic %d (rxunique %d)\n", 9192282SN/A rxActive, vnic->rxUnique); 9205603SN/A rxFifo.remove(vnic->rxIndex); 9215603SN/A vnic->rxIndex = rxFifo.end(); 9225603SN/A rxMappedCount--; 9231156SN/A } else { 9245603SN/A if (!vnic->rxPacketOffset) 9255603SN/A rxDirtyCount++; 9265603SN/A 9272008SN/A vnic->rxPacketBytes -= rxDmaLen; 9282008SN/A vnic->rxPacketOffset += rxDmaLen; 9292282SN/A vnic->RxDone |= Regs::RxDone_More; 9302282SN/A vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, 9312282SN/A vnic->rxPacketBytes); 9322010SN/A DPRINTF(EthernetSM, 9332282SN/A "rxKick: packet not complete on vnic %d (rxunique %d): " 9342282SN/A "%d bytes left\n", 9352282SN/A rxActive, vnic->rxUnique, vnic->rxPacketBytes); 9361156SN/A } 9371156SN/A 9382282SN/A rxActive = -1; 9392282SN/A rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; 9402008SN/A 9412008SN/A if (rxFifo.empty()) { 9422008SN/A devIntrPost(Regs::Intr_RxEmpty); 9432008SN/A rxEmpty = true; 9442008SN/A } 9452008SN/A 9465603SN/A if (rxFifo.size() < regs.RxFifoLow) 9472282SN/A rxLow = true; 9482282SN/A 9495603SN/A if (rxFifo.size() > regs.RxFifoHigh) 9502282SN/A rxLow = false; 9512282SN/A 9521939SN/A devIntrPost(Regs::Intr_RxDMA); 9531156SN/A break; 9541156SN/A 9551156SN/A default: 9561156SN/A panic("Invalid rxState!"); 9571156SN/A } 9581156SN/A 9591156SN/A DPRINTF(EthernetSM, "entering next rxState=%s\n", 9601156SN/A RxStateStrings[rxState]); 9611156SN/A 9621156SN/A goto next; 9631156SN/A 9641156SN/A exit: 9651156SN/A /** 9661156SN/A * @todo do we want to schedule a future kick? 9671156SN/A */ 9681156SN/A DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 9691156SN/A RxStateStrings[rxState]); 9701156SN/A} 9711156SN/A 9721156SN/Avoid 9732566SN/ADevice::txDmaDone() 9741156SN/A{ 9751156SN/A assert(txState == txCopy); 9761156SN/A txState = txCopyDone; 9771156SN/A DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 9781156SN/A txDmaAddr, txDmaLen); 9791939SN/A DDUMP(EthernetData, txDmaData, txDmaLen); 9801939SN/A 9811939SN/A // If the receive state machine has a pending DMA, let it go first 9821939SN/A if (rxState == rxBeginCopy) 9831939SN/A rxKick(); 9841939SN/A 9851156SN/A txKick(); 9861156SN/A} 9871156SN/A 9881156SN/Avoid 9891156SN/ADevice::transmit() 9901156SN/A{ 9911156SN/A if (txFifo.empty()) { 9921156SN/A DPRINTF(Ethernet, "nothing to transmit\n"); 9931156SN/A return; 9941156SN/A } 9951156SN/A 9961939SN/A uint32_t interrupts; 9972566SN/A EthPacketPtr packet = txFifo.front(); 9981156SN/A if (!interface->sendPacket(packet)) { 9991156SN/A DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 10001156SN/A txFifo.avail()); 10015603SN/A return; 10021156SN/A } 10031156SN/A 10041156SN/A txFifo.pop(); 10051156SN/A#if TRACING_ON 10061156SN/A if (DTRACE(Ethernet)) { 10071156SN/A IpPtr ip(packet); 10081156SN/A if (ip) { 10091156SN/A DPRINTF(Ethernet, "ID is %d\n", ip->id()); 10101156SN/A TcpPtr tcp(ip); 10111156SN/A if (tcp) { 10122280SN/A DPRINTF(Ethernet, 10132280SN/A "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 10142280SN/A tcp->sport(), tcp->dport(), tcp->seq(), 10152280SN/A tcp->ack()); 10161156SN/A } 10171156SN/A } 10181156SN/A } 10191156SN/A#endif 10201156SN/A 10211939SN/A DDUMP(EthernetData, packet->data, packet->length); 10221156SN/A txBytes += packet->length; 10231156SN/A txPackets++; 10241156SN/A 10251156SN/A DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 10261156SN/A txFifo.avail()); 10271156SN/A 10281939SN/A interrupts = Regs::Intr_TxPacket; 10295603SN/A if (txFifo.size() < regs.TxFifoLow) 10301939SN/A interrupts |= Regs::Intr_TxLow; 10311939SN/A devIntrPost(interrupts); 10321156SN/A} 10331156SN/A 10341156SN/Avoid 10351156SN/ADevice::txKick() 10361156SN/A{ 10372008SN/A VirtualReg *vnic; 10382279SN/A DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", 10391156SN/A TxStateStrings[txState], txFifo.size()); 10401156SN/A 10417823SN/A if (txKickTick > curTick()) { 10422279SN/A DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", 10431156SN/A txKickTick); 10441156SN/A return; 10451156SN/A } 10461156SN/A 10471156SN/A next: 10482008SN/A if (txState == txIdle) 10491156SN/A goto exit; 10501156SN/A 10512008SN/A assert(!txList.empty()); 10522008SN/A vnic = &virtualRegs[txList.front()]; 10532008SN/A 10542008SN/A switch (txState) { 10551156SN/A case txFifoBlock: 10562280SN/A assert(Regs::get_TxDone_Busy(vnic->TxDone)); 10571156SN/A if (!txPacket) { 10581156SN/A // Grab a new packet from the fifo. 105910469SN/A txPacket = make_shared<EthPacketData>(16384); 10602008SN/A txPacketOffset = 0; 10611156SN/A } 10621156SN/A 10631156SN/A if (txFifo.avail() - txPacket->length < 10642008SN/A Regs::get_TxData_Len(vnic->TxData)) { 10651156SN/A DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 10661156SN/A goto exit; 10671156SN/A } 10681156SN/A 10691156SN/A txState = txBeginCopy; 10701156SN/A break; 10711156SN/A 10721156SN/A case txBeginCopy: 107310913SN/A if (dmaPending() || drainState() != DrainState::Running) 10741939SN/A goto exit; 10751939SN/A 107611202SN/A txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData)); 10772008SN/A txDmaLen = Regs::get_TxData_Len(vnic->TxData); 10782008SN/A txDmaData = txPacket->data + txPacketOffset; 10791939SN/A txState = txCopy; 10801156SN/A 10812566SN/A dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); 10821156SN/A break; 10831156SN/A 10841156SN/A case txCopy: 10851156SN/A DPRINTF(EthernetSM, "transmit machine still copying\n"); 10861156SN/A goto exit; 10871156SN/A 10881156SN/A case txCopyDone: 10892008SN/A vnic->TxDone = txDmaLen | Regs::TxDone_Complete; 109011701Smichael.lebeane@amd.com txPacket->simLength += txDmaLen; 10911156SN/A txPacket->length += txDmaLen; 10922008SN/A if ((vnic->TxData & Regs::TxData_More)) { 10932008SN/A txPacketOffset += txDmaLen; 10942008SN/A txState = txIdle; 10952008SN/A devIntrPost(Regs::Intr_TxDMA); 10962008SN/A break; 10971156SN/A } 10981156SN/A 10992008SN/A assert(txPacket->length <= txFifo.avail()); 11002008SN/A if ((vnic->TxData & Regs::TxData_Checksum)) { 11012008SN/A IpPtr ip(txPacket); 11022008SN/A if (ip) { 11032008SN/A TcpPtr tcp(ip); 11042008SN/A if (tcp) { 11052008SN/A tcp->sum(0); 11062008SN/A tcp->sum(cksum(tcp)); 11072008SN/A txTcpChecksums++; 11082008SN/A } 11092008SN/A 11102008SN/A UdpPtr udp(ip); 11112008SN/A if (udp) { 11122008SN/A udp->sum(0); 11132008SN/A udp->sum(cksum(udp)); 11142008SN/A txUdpChecksums++; 11152008SN/A } 11162008SN/A 11172008SN/A ip->sum(0); 11182008SN/A ip->sum(cksum(ip)); 11192008SN/A txIpChecksums++; 11202008SN/A } 11212008SN/A } 11222008SN/A 11232008SN/A txFifo.push(txPacket); 11242008SN/A if (txFifo.avail() < regs.TxMaxCopy) { 11252008SN/A devIntrPost(Regs::Intr_TxFull); 11262008SN/A txFull = true; 11272008SN/A } 11282008SN/A txPacket = 0; 11292008SN/A transmit(); 11302008SN/A txList.pop_front(); 11312008SN/A txState = txList.empty() ? txIdle : txFifoBlock; 11321939SN/A devIntrPost(Regs::Intr_TxDMA); 11331156SN/A break; 11341156SN/A 11351156SN/A default: 11361156SN/A panic("Invalid txState!"); 11371156SN/A } 11381156SN/A 11391156SN/A DPRINTF(EthernetSM, "entering next txState=%s\n", 11401156SN/A TxStateStrings[txState]); 11411156SN/A 11421156SN/A goto next; 11431156SN/A 11441156SN/A exit: 11451156SN/A /** 11461156SN/A * @todo do we want to schedule a future kick? 11471156SN/A */ 11481156SN/A DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 11491156SN/A TxStateStrings[txState]); 11501156SN/A} 11511156SN/A 11521156SN/Avoid 11531156SN/ADevice::transferDone() 11541156SN/A{ 11551156SN/A if (txFifo.empty()) { 11561156SN/A DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 11571156SN/A return; 11581156SN/A } 11591156SN/A 11601156SN/A DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 11611156SN/A 11629417SN/A reschedule(txEvent, clockEdge(Cycles(1)), true); 11631156SN/A} 11641156SN/A 11651156SN/Abool 11662566SN/ADevice::rxFilter(const EthPacketPtr &packet) 11671156SN/A{ 11681156SN/A if (!Regs::get_Config_Filter(regs.Config)) 11691156SN/A return false; 11701156SN/A 11711156SN/A panic("receive filter not implemented\n"); 11721156SN/A bool drop = true; 11731156SN/A return drop; 11741156SN/A} 11751156SN/A 11761156SN/Abool 11772566SN/ADevice::recvPacket(EthPacketPtr packet) 11781156SN/A{ 11791156SN/A rxBytes += packet->length; 11801156SN/A rxPackets++; 11811156SN/A 11821156SN/A DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 11831156SN/A rxFifo.avail()); 11841156SN/A 11851156SN/A if (!rxEnable) { 11861156SN/A DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 11871156SN/A return true; 11881156SN/A } 11891156SN/A 11901156SN/A if (rxFilter(packet)) { 11911156SN/A DPRINTF(Ethernet, "packet filtered...dropped\n"); 11921156SN/A return true; 11931156SN/A } 11941156SN/A 11955603SN/A if (rxFifo.size() >= regs.RxFifoHigh) 11961939SN/A devIntrPost(Regs::Intr_RxHigh); 11971156SN/A 11981156SN/A if (!rxFifo.push(packet)) { 11991156SN/A DPRINTF(Ethernet, 12001156SN/A "packet will not fit in receive buffer...packet dropped\n"); 12011156SN/A return false; 12021156SN/A } 12031156SN/A 12042008SN/A // If we were at the last element, back up one ot go to the new 12052008SN/A // last element of the list. 12062008SN/A if (rxFifoPtr == rxFifo.end()) 12072008SN/A --rxFifoPtr; 12082008SN/A 12091939SN/A devIntrPost(Regs::Intr_RxPacket); 12101156SN/A rxKick(); 12111156SN/A return true; 12121156SN/A} 12131156SN/A 12142901SN/Avoid 12159342SN/ADevice::drainResume() 12162901SN/A{ 12179342SN/A Drainable::drainResume(); 12182901SN/A 12192901SN/A // During drain we could have left the state machines in a waiting state and 12202901SN/A // they wouldn't get out until some other event occured to kick them. 12212901SN/A // This way they'll get out immediately 12222901SN/A txKick(); 12232901SN/A rxKick(); 12242901SN/A} 12252901SN/A 12261156SN/A//===================================================================== 12271156SN/A// 12281156SN/A// 12291156SN/Avoid 123010905SN/ABase::serialize(CheckpointOut &cp) const 12311156SN/A{ 12329807SN/A // Serialize the PciDevice base class 123310905SN/A PciDevice::serialize(cp); 12341156SN/A 12351156SN/A SERIALIZE_SCALAR(rxEnable); 12361156SN/A SERIALIZE_SCALAR(txEnable); 12371156SN/A SERIALIZE_SCALAR(cpuIntrEnable); 12381156SN/A 12391156SN/A /* 12401156SN/A * Keep track of pending interrupt status. 12411156SN/A */ 12421156SN/A SERIALIZE_SCALAR(intrTick); 12431156SN/A SERIALIZE_SCALAR(cpuPendingIntr); 12441156SN/A Tick intrEventTick = 0; 12451156SN/A if (intrEvent) 12461156SN/A intrEventTick = intrEvent->when(); 12471156SN/A SERIALIZE_SCALAR(intrEventTick); 12481156SN/A} 12491156SN/A 12501156SN/Avoid 125110905SN/ABase::unserialize(CheckpointIn &cp) 12521156SN/A{ 12539807SN/A // Unserialize the PciDevice base class 125410905SN/A PciDevice::unserialize(cp); 12551156SN/A 12561156SN/A UNSERIALIZE_SCALAR(rxEnable); 12571156SN/A UNSERIALIZE_SCALAR(txEnable); 12581156SN/A UNSERIALIZE_SCALAR(cpuIntrEnable); 12591156SN/A 12601156SN/A /* 12611156SN/A * Keep track of pending interrupt status. 12621156SN/A */ 12631156SN/A UNSERIALIZE_SCALAR(intrTick); 12641156SN/A UNSERIALIZE_SCALAR(cpuPendingIntr); 12651156SN/A Tick intrEventTick; 12661156SN/A UNSERIALIZE_SCALAR(intrEventTick); 12671156SN/A if (intrEventTick) { 126812087Sspwilson2@wisc.edu intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); }, 126912087Sspwilson2@wisc.edu name(), true); 12705606SN/A schedule(intrEvent, intrEventTick); 12711156SN/A } 12721156SN/A} 12731156SN/A 12741156SN/Avoid 127511006SN/ADevice::serialize(CheckpointOut &cp) const 12761156SN/A{ 12772287SN/A int count; 12782287SN/A 12799807SN/A // Serialize the PciDevice base class 128010905SN/A Base::serialize(cp); 12811156SN/A 12821939SN/A if (rxState == rxCopy) 12831939SN/A panic("can't serialize with an in flight dma request rxState=%s", 12841939SN/A RxStateStrings[rxState]); 12851156SN/A 12861939SN/A if (txState == txCopy) 12871939SN/A panic("can't serialize with an in flight dma request txState=%s", 12881939SN/A TxStateStrings[txState]); 12891156SN/A 12901156SN/A /* 12915603SN/A * Serialize the device registers that could be modified by the OS. 12921156SN/A */ 12931156SN/A SERIALIZE_SCALAR(regs.Config); 12941939SN/A SERIALIZE_SCALAR(regs.IntrStatus); 12951939SN/A SERIALIZE_SCALAR(regs.IntrMask); 12961156SN/A SERIALIZE_SCALAR(regs.RxData); 12971156SN/A SERIALIZE_SCALAR(regs.TxData); 12981156SN/A 12991156SN/A /* 13002008SN/A * Serialize the virtual nic state 13012008SN/A */ 13022008SN/A int virtualRegsSize = virtualRegs.size(); 13032008SN/A SERIALIZE_SCALAR(virtualRegsSize); 13042008SN/A for (int i = 0; i < virtualRegsSize; ++i) { 130510905SN/A const VirtualReg *vnic = &virtualRegs[i]; 13062008SN/A 13072566SN/A std::string reg = csprintf("vnic%d", i); 130810905SN/A paramOut(cp, reg + ".RxData", vnic->RxData); 130910905SN/A paramOut(cp, reg + ".RxDone", vnic->RxDone); 131010905SN/A paramOut(cp, reg + ".TxData", vnic->TxData); 131110905SN/A paramOut(cp, reg + ".TxDone", vnic->TxDone); 13122008SN/A 13135603SN/A bool rxPacketExists = vnic->rxIndex != rxFifo.end(); 131410905SN/A paramOut(cp, reg + ".rxPacketExists", rxPacketExists); 13152008SN/A if (rxPacketExists) { 13162008SN/A int rxPacket = 0; 131711006SN/A auto i = rxFifo.begin(); 13185603SN/A while (i != vnic->rxIndex) { 13192008SN/A assert(i != rxFifo.end()); 13202008SN/A ++i; 13212008SN/A ++rxPacket; 13222008SN/A } 13232008SN/A 132410905SN/A paramOut(cp, reg + ".rxPacket", rxPacket); 132510905SN/A paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset); 132610905SN/A paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 13272008SN/A } 132810905SN/A paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData); 13292008SN/A } 13302008SN/A 13315603SN/A int rxFifoPtr = -1; 13325603SN/A if (this->rxFifoPtr != rxFifo.end()) 13335603SN/A rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); 13342282SN/A SERIALIZE_SCALAR(rxFifoPtr); 13352282SN/A 13362282SN/A SERIALIZE_SCALAR(rxActive); 13375603SN/A SERIALIZE_SCALAR(rxBusyCount); 13385603SN/A SERIALIZE_SCALAR(rxDirtyCount); 13395603SN/A SERIALIZE_SCALAR(rxMappedCount); 13402282SN/A 134111006SN/A VirtualList::const_iterator i, end; 13422008SN/A for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) 134310905SN/A paramOut(cp, csprintf("rxList%d", count++), *i); 13442282SN/A int rxListSize = count; 13452282SN/A SERIALIZE_SCALAR(rxListSize); 13462008SN/A 13472282SN/A for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) 134810905SN/A paramOut(cp, csprintf("rxBusy%d", count++), *i); 13492282SN/A int rxBusySize = count; 13502282SN/A SERIALIZE_SCALAR(rxBusySize); 13512282SN/A 13522008SN/A for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) 135310905SN/A paramOut(cp, csprintf("txList%d", count++), *i); 13542282SN/A int txListSize = count; 13552282SN/A SERIALIZE_SCALAR(txListSize); 13562008SN/A 13572008SN/A /* 13581156SN/A * Serialize rx state machine 13591156SN/A */ 13601156SN/A int rxState = this->rxState; 13611156SN/A SERIALIZE_SCALAR(rxState); 13621939SN/A SERIALIZE_SCALAR(rxEmpty); 13632282SN/A SERIALIZE_SCALAR(rxLow); 136410905SN/A rxFifo.serialize("rxFifo", cp); 13651156SN/A 13661156SN/A /* 13671156SN/A * Serialize tx state machine 13681156SN/A */ 13691156SN/A int txState = this->txState; 13701156SN/A SERIALIZE_SCALAR(txState); 13711939SN/A SERIALIZE_SCALAR(txFull); 137210905SN/A txFifo.serialize("txFifo", cp); 137310469SN/A bool txPacketExists = txPacket != nullptr; 13741156SN/A SERIALIZE_SCALAR(txPacketExists); 13751156SN/A if (txPacketExists) { 137610905SN/A txPacket->serialize("txPacket", cp); 13772008SN/A SERIALIZE_SCALAR(txPacketOffset); 13782008SN/A SERIALIZE_SCALAR(txPacketBytes); 13791156SN/A } 13801156SN/A 13811156SN/A /* 13821156SN/A * If there's a pending transmit, store the time so we can 13831156SN/A * reschedule it later 13841156SN/A */ 13857823SN/A Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 13861156SN/A SERIALIZE_SCALAR(transmitTick); 13871156SN/A} 13881156SN/A 13891156SN/Avoid 139010905SN/ADevice::unserialize(CheckpointIn &cp) 13911156SN/A{ 13929807SN/A // Unserialize the PciDevice base class 139310905SN/A Base::unserialize(cp); 13941156SN/A 13951156SN/A /* 13965603SN/A * Unserialize the device registers that may have been written by the OS. 13971156SN/A */ 13981156SN/A UNSERIALIZE_SCALAR(regs.Config); 13991939SN/A UNSERIALIZE_SCALAR(regs.IntrStatus); 14001939SN/A UNSERIALIZE_SCALAR(regs.IntrMask); 14011156SN/A UNSERIALIZE_SCALAR(regs.RxData); 14021156SN/A UNSERIALIZE_SCALAR(regs.TxData); 14031156SN/A 14042282SN/A UNSERIALIZE_SCALAR(rxActive); 14055603SN/A UNSERIALIZE_SCALAR(rxBusyCount); 14065603SN/A UNSERIALIZE_SCALAR(rxDirtyCount); 14075603SN/A UNSERIALIZE_SCALAR(rxMappedCount); 14082282SN/A 14092008SN/A int rxListSize; 14102008SN/A UNSERIALIZE_SCALAR(rxListSize); 14112008SN/A rxList.clear(); 14122008SN/A for (int i = 0; i < rxListSize; ++i) { 14132008SN/A int value; 141410905SN/A paramIn(cp, csprintf("rxList%d", i), value); 14152008SN/A rxList.push_back(value); 14162008SN/A } 14172008SN/A 14182282SN/A int rxBusySize; 14192282SN/A UNSERIALIZE_SCALAR(rxBusySize); 14202282SN/A rxBusy.clear(); 14212282SN/A for (int i = 0; i < rxBusySize; ++i) { 14222282SN/A int value; 142310905SN/A paramIn(cp, csprintf("rxBusy%d", i), value); 14242282SN/A rxBusy.push_back(value); 14252282SN/A } 14262282SN/A 14272008SN/A int txListSize; 14282008SN/A UNSERIALIZE_SCALAR(txListSize); 14292008SN/A txList.clear(); 14302008SN/A for (int i = 0; i < txListSize; ++i) { 14312008SN/A int value; 143210905SN/A paramIn(cp, csprintf("txList%d", i), value); 14332008SN/A txList.push_back(value); 14342008SN/A } 14352008SN/A 14361156SN/A /* 14371156SN/A * Unserialize rx state machine 14381156SN/A */ 14391156SN/A int rxState; 14401156SN/A UNSERIALIZE_SCALAR(rxState); 14411939SN/A UNSERIALIZE_SCALAR(rxEmpty); 14422282SN/A UNSERIALIZE_SCALAR(rxLow); 14431156SN/A this->rxState = (RxState) rxState; 144410905SN/A rxFifo.unserialize("rxFifo", cp); 14451156SN/A 14462282SN/A int rxFifoPtr; 14472282SN/A UNSERIALIZE_SCALAR(rxFifoPtr); 14485603SN/A if (rxFifoPtr >= 0) { 14495603SN/A this->rxFifoPtr = rxFifo.begin(); 14505603SN/A for (int i = 0; i < rxFifoPtr; ++i) 14515603SN/A ++this->rxFifoPtr; 14525603SN/A } else { 14535603SN/A this->rxFifoPtr = rxFifo.end(); 14545603SN/A } 14552282SN/A 14561156SN/A /* 14571156SN/A * Unserialize tx state machine 14581156SN/A */ 14591156SN/A int txState; 14601156SN/A UNSERIALIZE_SCALAR(txState); 14611939SN/A UNSERIALIZE_SCALAR(txFull); 14621156SN/A this->txState = (TxState) txState; 146310905SN/A txFifo.unserialize("txFifo", cp); 14641156SN/A bool txPacketExists; 14651156SN/A UNSERIALIZE_SCALAR(txPacketExists); 14661156SN/A txPacket = 0; 14671156SN/A if (txPacketExists) { 146811719Smichael.lebeane@amd.com txPacket = make_shared<EthPacketData>(16384); 146910905SN/A txPacket->unserialize("txPacket", cp); 14702008SN/A UNSERIALIZE_SCALAR(txPacketOffset); 14712008SN/A UNSERIALIZE_SCALAR(txPacketBytes); 14722008SN/A } 14732008SN/A 14742008SN/A /* 14752008SN/A * unserialize the virtual nic registers/state 14762008SN/A * 14772008SN/A * this must be done after the unserialization of the rxFifo 14782008SN/A * because the packet iterators depend on the fifo being populated 14792008SN/A */ 14802008SN/A int virtualRegsSize; 14812008SN/A UNSERIALIZE_SCALAR(virtualRegsSize); 14822008SN/A virtualRegs.clear(); 14832008SN/A virtualRegs.resize(virtualRegsSize); 14842008SN/A for (int i = 0; i < virtualRegsSize; ++i) { 14852008SN/A VirtualReg *vnic = &virtualRegs[i]; 14862566SN/A std::string reg = csprintf("vnic%d", i); 14872008SN/A 148810905SN/A paramIn(cp, reg + ".RxData", vnic->RxData); 148910905SN/A paramIn(cp, reg + ".RxDone", vnic->RxDone); 149010905SN/A paramIn(cp, reg + ".TxData", vnic->TxData); 149110905SN/A paramIn(cp, reg + ".TxDone", vnic->TxDone); 14922008SN/A 14932282SN/A vnic->rxUnique = rxUnique++; 14942282SN/A vnic->txUnique = txUnique++; 14952282SN/A 14962008SN/A bool rxPacketExists; 149710905SN/A paramIn(cp, reg + ".rxPacketExists", rxPacketExists); 14982008SN/A if (rxPacketExists) { 14992008SN/A int rxPacket; 150010905SN/A paramIn(cp, reg + ".rxPacket", rxPacket); 15015603SN/A vnic->rxIndex = rxFifo.begin(); 15022008SN/A while (rxPacket--) 15035603SN/A ++vnic->rxIndex; 15042008SN/A 150510905SN/A paramIn(cp, reg + ".rxPacketOffset", 15062008SN/A vnic->rxPacketOffset); 150710905SN/A paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 15082008SN/A } else { 15095603SN/A vnic->rxIndex = rxFifo.end(); 15102008SN/A } 151110905SN/A paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData); 15121156SN/A } 15131156SN/A 15141156SN/A /* 15151156SN/A * If there's a pending transmit, reschedule it now 15161156SN/A */ 15171156SN/A Tick transmitTick; 15181156SN/A UNSERIALIZE_SCALAR(transmitTick); 15191156SN/A if (transmitTick) 15207823SN/A schedule(txEvent, curTick() + transmitTick); 15211156SN/A 15228851SN/A pioPort.sendRangeChange(); 15232566SN/A 15241156SN/A} 15251156SN/A 15267811SN/A} // namespace Sinic 15271156SN/A 15284762SN/ASinic::Device * 15294762SN/ASinicParams::create() 15301156SN/A{ 15314762SN/A return new Sinic::Device(this); 15321156SN/A} 1533