sinic.cc revision 11263
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), 941156SN/A txEvent(this), rxDmaEvent(this), txDmaEvent(this), 951156SN/A dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), 961156SN/A dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) 971156SN/A{ 984981SN/A interface = new Interface(name() + ".int0", this); 991156SN/A reset(); 1001156SN/A 1011156SN/A} 1021156SN/A 1031156SN/ADevice::~Device() 1041156SN/A{} 1051156SN/A 1061156SN/Avoid 1071156SN/ADevice::regStats() 1081156SN/A{ 1099339SN/A Base::regStats(); 1105603SN/A 1115603SN/A _maxVnicDistance = 0; 1125603SN/A 1135603SN/A maxVnicDistance 1145603SN/A .name(name() + ".maxVnicDistance") 1155603SN/A .desc("maximum vnic distance") 1165603SN/A ; 1175603SN/A 1185603SN/A totalVnicDistance 1195603SN/A .name(name() + ".totalVnicDistance") 1205603SN/A .desc("total vnic distance") 1215603SN/A ; 1225603SN/A numVnicDistance 1235603SN/A .name(name() + ".numVnicDistance") 1245603SN/A .desc("number of vnic distance measurements") 1255603SN/A ; 1265603SN/A 1275603SN/A avgVnicDistance 1285603SN/A .name(name() + ".avgVnicDistance") 1295603SN/A .desc("average vnic distance") 1305603SN/A ; 1315603SN/A 1325603SN/A avgVnicDistance = totalVnicDistance / numVnicDistance; 1335603SN/A} 1345603SN/A 1355603SN/Avoid 1365603SN/ADevice::resetStats() 1375603SN/A{ 1389339SN/A Base::resetStats(); 1399339SN/A 1405603SN/A _maxVnicDistance = 0; 1411156SN/A} 1421156SN/A 1434981SN/AEtherInt* 1444981SN/ADevice::getEthPort(const std::string &if_name, int idx) 1454981SN/A{ 1464981SN/A if (if_name == "interface") { 1474981SN/A if (interface->getPeer()) 1484981SN/A panic("interface already connected to\n"); 1494981SN/A 1504981SN/A return interface; 1514981SN/A } 1524981SN/A return NULL; 1534981SN/A} 1544981SN/A 1554981SN/A 1561939SN/Avoid 15711005SN/ADevice::prepareIO(ContextID cpu, int index) 1582008SN/A{ 1592008SN/A int size = virtualRegs.size(); 1602282SN/A if (index > size) 1612282SN/A panic("Trying to access a vnic that doesn't exist %d > %d\n", 1622282SN/A index, size); 1632008SN/A} 1642008SN/A 1655603SN/A//add stats for head of line blocking 1665603SN/A//add stats for average fifo length 1675603SN/A//add stats for average number of vnics busy 1685603SN/A 1692008SN/Avoid 17011005SN/ADevice::prepareRead(ContextID cpu, int index) 1712008SN/A{ 1722008SN/A using namespace Regs; 1732008SN/A prepareIO(cpu, index); 1742008SN/A 1752008SN/A VirtualReg &vnic = virtualRegs[index]; 1762008SN/A 1772008SN/A // update rx registers 1782008SN/A uint64_t rxdone = vnic.RxDone; 1792282SN/A rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); 1802282SN/A rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); 1815603SN/A rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh); 1822282SN/A rxdone = set_RxDone_NotHigh(rxdone, rxLow); 1832008SN/A regs.RxData = vnic.RxData; 1842008SN/A regs.RxDone = rxdone; 1852008SN/A regs.RxWait = rxdone; 1862008SN/A 1872008SN/A // update tx regsiters 1882008SN/A uint64_t txdone = vnic.TxDone; 1892008SN/A txdone = set_TxDone_Packets(txdone, txFifo.packets()); 1902008SN/A txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); 1915603SN/A txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow); 1922008SN/A regs.TxData = vnic.TxData; 1932008SN/A regs.TxDone = txdone; 1942008SN/A regs.TxWait = txdone; 1955603SN/A 1965603SN/A int head = 0xffff; 1975603SN/A 1985603SN/A if (!rxFifo.empty()) { 1995603SN/A int vnic = rxFifo.begin()->priv; 2005603SN/A if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0) 2015603SN/A head = vnic; 2025603SN/A } 2035603SN/A 2045603SN/A regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head); 2055603SN/A regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount); 2065603SN/A regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount); 2075603SN/A regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount); 2082008SN/A} 2092008SN/A 2102008SN/Avoid 21111005SN/ADevice::prepareWrite(ContextID cpu, int index) 2121997SN/A{ 2132008SN/A prepareIO(cpu, index); 2141997SN/A} 2151997SN/A 2161156SN/A/** 2171939SN/A * I/O read of device register 2181156SN/A */ 2192566SN/ATick 2203349SN/ADevice::read(PacketPtr pkt) 2211156SN/A{ 2221817SN/A assert(config.command & PCI_CMD_MSE); 2232641SN/A assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 2241156SN/A 22511005SN/A ContextID cpu = pkt->req->contextId(); 2262641SN/A Addr daddr = pkt->getAddr() - BARAddrs[0]; 2272008SN/A Addr index = daddr >> Regs::VirtualShift; 2282008SN/A Addr raddr = daddr & Regs::VirtualMask; 2291997SN/A 2302008SN/A if (!regValid(raddr)) 2312617SN/A panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2322641SN/A cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2331156SN/A 2342008SN/A const Regs::Info &info = regInfo(raddr); 2351939SN/A if (!info.read) 2362279SN/A panic("read %s (write only): " 2372617SN/A "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2382641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2391939SN/A 2402279SN/A panic("read %s (invalid size): " 2412617SN/A "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2422641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2431156SN/A 2442008SN/A prepareRead(cpu, index); 2451156SN/A 2468641SN/A uint64_t value M5_VAR_USED = 0; 2472641SN/A if (pkt->getSize() == 4) { 2482566SN/A uint32_t reg = regData32(raddr); 2492630SN/A pkt->set(reg); 2501939SN/A value = reg; 2511156SN/A } 2521156SN/A 2532641SN/A if (pkt->getSize() == 8) { 2542566SN/A uint64_t reg = regData64(raddr); 2552630SN/A pkt->set(reg); 2561939SN/A value = reg; 2571939SN/A } 2581939SN/A 2591998SN/A DPRINTF(EthernetPIO, 2602617SN/A "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n", 2612641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value); 2621939SN/A 2631939SN/A // reading the interrupt status register has the side effect of 2641939SN/A // clearing it 2652008SN/A if (raddr == Regs::IntrStatus) 2661939SN/A devIntrClear(); 2671156SN/A 2682566SN/A return pioDelay; 2691156SN/A} 2701156SN/A 2711939SN/A/** 2721939SN/A * IPR read of device register 2732566SN/A 2742566SN/A Fault 27511005SN/ADevice::iprRead(Addr daddr, ContextID cpu, uint64_t &result) 2761939SN/A{ 2771939SN/A if (!regValid(daddr)) 2781939SN/A panic("invalid address: da=%#x", daddr); 2791939SN/A 2801939SN/A const Regs::Info &info = regInfo(daddr); 2811939SN/A if (!info.read) 2821998SN/A panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); 2831939SN/A 2841998SN/A DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", 2851998SN/A info.name, cpu, daddr); 2861939SN/A 2872008SN/A prepareRead(cpu, 0); 2881939SN/A 2891939SN/A if (info.size == 4) 2901939SN/A result = regData32(daddr); 2911939SN/A 2921939SN/A if (info.size == 8) 2931939SN/A result = regData64(daddr); 2941939SN/A 2951998SN/A DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", 2961998SN/A info.name, cpu, result); 2971939SN/A 2982090SN/A return NoFault; 2991939SN/A} 3002566SN/A*/ 3011939SN/A/** 3021939SN/A * I/O write of device register 3031939SN/A */ 3042566SN/ATick 3053349SN/ADevice::write(PacketPtr pkt) 3061156SN/A{ 3071817SN/A assert(config.command & PCI_CMD_MSE); 3082641SN/A assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 3091939SN/A 31011005SN/A ContextID cpu = pkt->req->contextId(); 3112641SN/A Addr daddr = pkt->getAddr() - BARAddrs[0]; 3122008SN/A Addr index = daddr >> Regs::VirtualShift; 3132008SN/A Addr raddr = daddr & Regs::VirtualMask; 3141997SN/A 3152008SN/A if (!regValid(raddr)) 3162566SN/A panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", 3172641SN/A cpu, daddr, pkt->getAddr(), pkt->getSize()); 3181156SN/A 3192008SN/A const Regs::Info &info = regInfo(raddr); 3201939SN/A if (!info.write) 3212279SN/A panic("write %s (read only): " 3222617SN/A "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 3232641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 3241939SN/A 3252641SN/A if (pkt->getSize() != info.size) 3262279SN/A panic("write %s (invalid size): " 3272617SN/A "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 3282641SN/A info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 3291156SN/A 3302176SN/A VirtualReg &vnic = virtualRegs[index]; 3312176SN/A 3321998SN/A DPRINTF(EthernetPIO, 3332617SN/A "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", 3342630SN/A info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() : 3352641SN/A pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize()); 3361156SN/A 3372008SN/A prepareWrite(cpu, index); 3381156SN/A 3392008SN/A switch (raddr) { 3401156SN/A case Regs::Config: 3412630SN/A changeConfig(pkt->get<uint32_t>()); 3421156SN/A break; 3431156SN/A 3441939SN/A case Regs::Command: 3452630SN/A command(pkt->get<uint32_t>()); 3461156SN/A break; 3471156SN/A 3481939SN/A case Regs::IntrStatus: 3492630SN/A devIntrClear(regs.IntrStatus & pkt->get<uint32_t>()); 3501156SN/A break; 3511156SN/A 3521156SN/A case Regs::IntrMask: 3532630SN/A devIntrChangeMask(pkt->get<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; 3632630SN/A vnic.RxData = pkt->get<uint64_t>(); 3645603SN/A rxBusyCount++; 3652282SN/A 3662630SN/A if (Regs::get_RxData_Vaddr(pkt->get<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 4042630SN/A if (Regs::get_TxData_Vaddr(pkt->get<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()) { 5308231SN/A Debug::breakpoint(); 5317823SN/A intrTick = curTick(); 5321156SN/A } 5331156SN/A 5341156SN/A DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 5351156SN/A intrTick); 5361156SN/A 5371156SN/A if (intrEvent) 5381156SN/A intrEvent->squash(); 5395606SN/A intrEvent = new IntrEvent(this, true); 5405606SN/A schedule(intrEvent, intrTick); 5411156SN/A} 5421156SN/A 5431156SN/Avoid 5441156SN/ABase::cpuInterrupt() 5451156SN/A{ 5467823SN/A assert(intrTick == curTick()); 5471156SN/A 5481156SN/A // Whether or not there's a pending interrupt, we don't care about 5491156SN/A // it anymore 5501156SN/A intrEvent = 0; 5511156SN/A intrTick = 0; 5521156SN/A 5531156SN/A // Don't send an interrupt if there's already one 5541156SN/A if (cpuPendingIntr) { 5551156SN/A DPRINTF(EthernetIntr, 5561156SN/A "would send an interrupt now, but there's already pending\n"); 5571156SN/A } else { 5581156SN/A // Send interrupt 5591156SN/A cpuPendingIntr = true; 5601156SN/A 5611156SN/A DPRINTF(EthernetIntr, "posting interrupt\n"); 5621156SN/A intrPost(); 5631156SN/A } 5641156SN/A} 5651156SN/A 5661156SN/Avoid 5671156SN/ABase::cpuIntrClear() 5681156SN/A{ 5691156SN/A if (!cpuPendingIntr) 5701156SN/A return; 5711156SN/A 5721156SN/A if (intrEvent) { 5731156SN/A intrEvent->squash(); 5741156SN/A intrEvent = 0; 5751156SN/A } 5761156SN/A 5771156SN/A intrTick = 0; 5781156SN/A 5791156SN/A cpuPendingIntr = false; 5801156SN/A 5811156SN/A DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 5821156SN/A intrClear(); 5831156SN/A} 5841156SN/A 5851156SN/Abool 5861156SN/ABase::cpuIntrPending() const 5871156SN/A{ return cpuPendingIntr; } 5881156SN/A 5891156SN/Avoid 5901156SN/ADevice::changeConfig(uint32_t newconf) 5911156SN/A{ 5921156SN/A uint32_t changed = regs.Config ^ newconf; 5931156SN/A if (!changed) 5941156SN/A return; 5951156SN/A 5961156SN/A regs.Config = newconf; 5971156SN/A 5981156SN/A if ((changed & Regs::Config_IntEn)) { 5991156SN/A cpuIntrEnable = regs.Config & Regs::Config_IntEn; 6001156SN/A if (cpuIntrEnable) { 6011156SN/A if (regs.IntrStatus & regs.IntrMask) 6027823SN/A cpuIntrPost(curTick()); 6031156SN/A } else { 6041156SN/A cpuIntrClear(); 6051156SN/A } 6061156SN/A } 6071156SN/A 6081156SN/A if ((changed & Regs::Config_TxEn)) { 6091156SN/A txEnable = regs.Config & Regs::Config_TxEn; 6101156SN/A if (txEnable) 6111156SN/A txKick(); 6121156SN/A } 6131156SN/A 6141156SN/A if ((changed & Regs::Config_RxEn)) { 6151156SN/A rxEnable = regs.Config & Regs::Config_RxEn; 6161156SN/A if (rxEnable) 6171156SN/A rxKick(); 6181156SN/A } 6191156SN/A} 6201156SN/A 6211156SN/Avoid 6221939SN/ADevice::command(uint32_t command) 6231939SN/A{ 6242008SN/A if (command & Regs::Command_Intr) 6252008SN/A devIntrPost(Regs::Intr_Soft); 6262008SN/A 6271939SN/A if (command & Regs::Command_Reset) 6281939SN/A reset(); 6291939SN/A} 6301939SN/A 6311939SN/Avoid 6321156SN/ADevice::reset() 6331156SN/A{ 6341156SN/A using namespace Regs; 6351939SN/A 6361156SN/A memset(®s, 0, sizeof(regs)); 6371939SN/A 6381939SN/A regs.Config = 0; 6392008SN/A if (params()->rx_thread) 6402008SN/A regs.Config |= Config_RxThread; 6412008SN/A if (params()->tx_thread) 6422008SN/A regs.Config |= Config_TxThread; 6432210SN/A if (params()->rss) 6442210SN/A regs.Config |= Config_RSS; 6452282SN/A if (params()->zero_copy) 6462282SN/A regs.Config |= Config_ZeroCopy; 6472282SN/A if (params()->delay_copy) 6482282SN/A regs.Config |= Config_DelayCopy; 6492282SN/A if (params()->virtual_addr) 6502282SN/A regs.Config |= Config_Vaddr; 6512282SN/A 6522282SN/A if (params()->delay_copy && params()->zero_copy) 6532282SN/A panic("Can't delay copy and zero copy"); 6542282SN/A 6552008SN/A regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; 6561156SN/A regs.RxMaxCopy = params()->rx_max_copy; 6571156SN/A regs.TxMaxCopy = params()->tx_max_copy; 6585603SN/A regs.ZeroCopySize = params()->zero_copy_size; 6595603SN/A regs.ZeroCopyMark = params()->zero_copy_threshold; 6605603SN/A regs.VirtualCount = params()->virtual_count; 6611939SN/A regs.RxMaxIntr = params()->rx_max_intr; 6621939SN/A regs.RxFifoSize = params()->rx_fifo_size; 6631939SN/A regs.TxFifoSize = params()->tx_fifo_size; 6645603SN/A regs.RxFifoLow = params()->rx_fifo_low_mark; 6655603SN/A regs.TxFifoLow = params()->tx_fifo_threshold; 6665603SN/A regs.RxFifoHigh = params()->rx_fifo_threshold; 6675603SN/A regs.TxFifoHigh = params()->tx_fifo_high_mark; 6684762SN/A regs.HwAddr = params()->hardware_address; 6691156SN/A 6705603SN/A if (regs.RxMaxCopy < regs.ZeroCopyMark) 6715603SN/A panic("Must be able to copy at least as many bytes as the threshold"); 6725603SN/A 6735603SN/A if (regs.ZeroCopySize >= regs.ZeroCopyMark) 6745603SN/A panic("The number of bytes to copy must be less than the threshold"); 6755603SN/A 6762008SN/A rxList.clear(); 6772282SN/A rxBusy.clear(); 6782282SN/A rxActive = -1; 6792008SN/A txList.clear(); 6805603SN/A rxBusyCount = 0; 6815603SN/A rxDirtyCount = 0; 6825603SN/A rxMappedCount = 0; 6832008SN/A 6841156SN/A rxState = rxIdle; 6851156SN/A txState = txIdle; 6861156SN/A 6871156SN/A rxFifo.clear(); 6882008SN/A rxFifoPtr = rxFifo.end(); 6891156SN/A txFifo.clear(); 6901939SN/A rxEmpty = false; 6912282SN/A rxLow = true; 6921939SN/A txFull = false; 6932008SN/A 6942008SN/A int size = virtualRegs.size(); 6952008SN/A virtualRegs.clear(); 6962008SN/A virtualRegs.resize(size); 6972008SN/A for (int i = 0; i < size; ++i) 6985603SN/A virtualRegs[i].rxIndex = rxFifo.end(); 6991156SN/A} 7001156SN/A 7011156SN/Avoid 7022566SN/ADevice::rxDmaDone() 7031156SN/A{ 7041156SN/A assert(rxState == rxCopy); 7051156SN/A rxState = rxCopyDone; 7062280SN/A DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", 7071156SN/A rxDmaAddr, rxDmaLen); 7081939SN/A DDUMP(EthernetData, rxDmaData, rxDmaLen); 7091939SN/A 7101939SN/A // If the transmit state machine has a pending DMA, let it go first 7111939SN/A if (txState == txBeginCopy) 7121939SN/A txKick(); 7131939SN/A 7141156SN/A rxKick(); 7151156SN/A} 7161156SN/A 7171156SN/Avoid 7181156SN/ADevice::rxKick() 7191156SN/A{ 7202282SN/A VirtualReg *vnic = NULL; 7212008SN/A 7222279SN/A DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", 7231156SN/A RxStateStrings[rxState], rxFifo.size()); 7241156SN/A 7257823SN/A if (rxKickTick > curTick()) { 7262279SN/A DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", 7271156SN/A rxKickTick); 7281156SN/A return; 7291156SN/A } 7301156SN/A 7311156SN/A next: 7325603SN/A rxFifo.check(); 7332008SN/A if (rxState == rxIdle) 7341156SN/A goto exit; 7351156SN/A 7362282SN/A if (rxActive == -1) { 7372282SN/A if (rxState != rxFifoBlock) 7382282SN/A panic("no active vnic while in state %s", RxStateStrings[rxState]); 7392008SN/A 7402282SN/A DPRINTF(EthernetSM, "processing rxState=%s\n", 7412282SN/A RxStateStrings[rxState]); 7422282SN/A } else { 7432282SN/A vnic = &virtualRegs[rxActive]; 7442282SN/A DPRINTF(EthernetSM, 7452282SN/A "processing rxState=%s for vnic %d (rxunique %d)\n", 7462282SN/A RxStateStrings[rxState], rxActive, vnic->rxUnique); 7472282SN/A } 7482008SN/A 7492008SN/A switch (rxState) { 7501156SN/A case rxFifoBlock: 7512282SN/A if (DTRACE(EthernetSM)) { 7522282SN/A PacketFifo::iterator end = rxFifo.end(); 7532282SN/A int size = virtualRegs.size(); 7542282SN/A for (int i = 0; i < size; ++i) { 7552282SN/A VirtualReg *vn = &virtualRegs[i]; 7565603SN/A bool busy = Regs::get_RxDone_Busy(vn->RxDone); 7575603SN/A if (vn->rxIndex != end) { 7588641SN/A#ifndef NDEBUG 7595603SN/A bool dirty = vn->rxPacketOffset > 0; 7605603SN/A const char *status; 7615603SN/A 7625603SN/A if (busy && dirty) 7635603SN/A status = "busy,dirty"; 7645603SN/A else if (busy) 7655603SN/A status = "busy"; 7665603SN/A else if (dirty) 7675603SN/A status = "dirty"; 7685603SN/A else 7695603SN/A status = "mapped"; 7705603SN/A 7712282SN/A DPRINTF(EthernetSM, 7725603SN/A "vnic %d %s (rxunique %d), packet %d, slack %d\n", 7735603SN/A i, status, vn->rxUnique, 7745603SN/A rxFifo.countPacketsBefore(vn->rxIndex), 7755603SN/A vn->rxIndex->slack); 7768641SN/A#endif 7775603SN/A } else if (busy) { 7785603SN/A DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n", 7795603SN/A i, vn->rxUnique); 7802282SN/A } 7812282SN/A } 7822282SN/A } 7832282SN/A 7842282SN/A if (!rxBusy.empty()) { 7852282SN/A rxActive = rxBusy.front(); 7862282SN/A rxBusy.pop_front(); 7872282SN/A vnic = &virtualRegs[rxActive]; 7882282SN/A 7895603SN/A if (vnic->rxIndex == rxFifo.end()) 7902282SN/A panic("continuing vnic without packet\n"); 7912282SN/A 7922282SN/A DPRINTF(EthernetSM, 7932282SN/A "continue processing for vnic %d (rxunique %d)\n", 7942282SN/A rxActive, vnic->rxUnique); 7952282SN/A 7961156SN/A rxState = rxBeginCopy; 7972282SN/A 7985603SN/A int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex); 7995603SN/A totalVnicDistance += vnic_distance; 8005603SN/A numVnicDistance += 1; 8015603SN/A if (vnic_distance > _maxVnicDistance) { 8025603SN/A maxVnicDistance = vnic_distance; 8035603SN/A _maxVnicDistance = vnic_distance; 8045603SN/A } 8055603SN/A 8061156SN/A break; 8071156SN/A } 8081156SN/A 8092008SN/A if (rxFifoPtr == rxFifo.end()) { 8101156SN/A DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 8111156SN/A goto exit; 8121156SN/A } 8131156SN/A 8142282SN/A if (rxList.empty()) 8152282SN/A panic("Not idle, but nothing to do!"); 8162282SN/A 8172008SN/A assert(!rxFifo.empty()); 8182008SN/A 8192282SN/A rxActive = rxList.front(); 8202282SN/A rxList.pop_front(); 8212282SN/A vnic = &virtualRegs[rxActive]; 8222282SN/A 8232282SN/A DPRINTF(EthernetSM, 8242282SN/A "processing new packet for vnic %d (rxunique %d)\n", 8252282SN/A rxActive, vnic->rxUnique); 8262282SN/A 8271156SN/A // Grab a new packet from the fifo. 8285603SN/A vnic->rxIndex = rxFifoPtr++; 8295603SN/A vnic->rxIndex->priv = rxActive; 8302008SN/A vnic->rxPacketOffset = 0; 8315603SN/A vnic->rxPacketBytes = vnic->rxIndex->packet->length; 8322008SN/A assert(vnic->rxPacketBytes); 8335603SN/A rxMappedCount++; 8341156SN/A 8352008SN/A vnic->rxDoneData = 0; 8361156SN/A /* scope for variables */ { 8375603SN/A IpPtr ip(vnic->rxIndex->packet); 8381156SN/A if (ip) { 8392280SN/A DPRINTF(Ethernet, "ID is %d\n", ip->id()); 8402008SN/A vnic->rxDoneData |= Regs::RxDone_IpPacket; 8411156SN/A rxIpChecksums++; 8421156SN/A if (cksum(ip) != 0) { 8431156SN/A DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 8442008SN/A vnic->rxDoneData |= Regs::RxDone_IpError; 8451156SN/A } 8461156SN/A TcpPtr tcp(ip); 8471156SN/A UdpPtr udp(ip); 8481156SN/A if (tcp) { 8492279SN/A DPRINTF(Ethernet, 8502279SN/A "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 8512279SN/A tcp->sport(), tcp->dport(), tcp->seq(), 8522279SN/A tcp->ack()); 8532008SN/A vnic->rxDoneData |= Regs::RxDone_TcpPacket; 8541156SN/A rxTcpChecksums++; 8551156SN/A if (cksum(tcp) != 0) { 8561156SN/A DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 8572008SN/A vnic->rxDoneData |= Regs::RxDone_TcpError; 8581156SN/A } 8591156SN/A } else if (udp) { 8602008SN/A vnic->rxDoneData |= Regs::RxDone_UdpPacket; 8611156SN/A rxUdpChecksums++; 8621156SN/A if (cksum(udp) != 0) { 8631156SN/A DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 8642008SN/A vnic->rxDoneData |= Regs::RxDone_UdpError; 8651156SN/A } 8661156SN/A } 8671156SN/A } 8681156SN/A } 8691156SN/A rxState = rxBeginCopy; 8701156SN/A break; 8711156SN/A 8721156SN/A case rxBeginCopy: 87310913SN/A if (dmaPending() || drainState() != DrainState::Running) 8741939SN/A goto exit; 8751939SN/A 87611202SN/A rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData)); 8776227SN/A rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData), 8786227SN/A vnic->rxPacketBytes); 8795603SN/A 8805603SN/A /* 8815603SN/A * if we're doing zero/delay copy and we're below the fifo 8825603SN/A * threshold, see if we should try to do the zero/defer copy 8835603SN/A */ 8845603SN/A if ((Regs::get_Config_ZeroCopy(regs.Config) || 8855603SN/A Regs::get_Config_DelayCopy(regs.Config)) && 8865603SN/A !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) { 8875603SN/A if (rxDmaLen > regs.ZeroCopyMark) 8885603SN/A rxDmaLen = regs.ZeroCopySize; 8895603SN/A } 8905603SN/A rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset; 8911939SN/A rxState = rxCopy; 8922282SN/A if (rxDmaAddr == 1LL) { 8932282SN/A rxState = rxCopyDone; 8942282SN/A break; 8952282SN/A } 8962282SN/A 8972566SN/A dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); 8981156SN/A break; 8991156SN/A 9001156SN/A case rxCopy: 9011156SN/A DPRINTF(EthernetSM, "receive machine still copying\n"); 9021156SN/A goto exit; 9031156SN/A 9041156SN/A case rxCopyDone: 9052282SN/A vnic->RxDone = vnic->rxDoneData; 9062008SN/A vnic->RxDone |= Regs::RxDone_Complete; 9075603SN/A rxBusyCount--; 9081156SN/A 9092008SN/A if (vnic->rxPacketBytes == rxDmaLen) { 9105603SN/A if (vnic->rxPacketOffset) 9115603SN/A rxDirtyCount--; 9125603SN/A 9132282SN/A // Packet is complete. Indicate how many bytes were copied 9142282SN/A vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); 9152282SN/A 9162282SN/A DPRINTF(EthernetSM, 9172282SN/A "rxKick: packet complete on vnic %d (rxunique %d)\n", 9182282SN/A rxActive, vnic->rxUnique); 9195603SN/A rxFifo.remove(vnic->rxIndex); 9205603SN/A vnic->rxIndex = rxFifo.end(); 9215603SN/A rxMappedCount--; 9221156SN/A } else { 9235603SN/A if (!vnic->rxPacketOffset) 9245603SN/A rxDirtyCount++; 9255603SN/A 9262008SN/A vnic->rxPacketBytes -= rxDmaLen; 9272008SN/A vnic->rxPacketOffset += rxDmaLen; 9282282SN/A vnic->RxDone |= Regs::RxDone_More; 9292282SN/A vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, 9302282SN/A vnic->rxPacketBytes); 9312010SN/A DPRINTF(EthernetSM, 9322282SN/A "rxKick: packet not complete on vnic %d (rxunique %d): " 9332282SN/A "%d bytes left\n", 9342282SN/A rxActive, vnic->rxUnique, vnic->rxPacketBytes); 9351156SN/A } 9361156SN/A 9372282SN/A rxActive = -1; 9382282SN/A rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; 9392008SN/A 9402008SN/A if (rxFifo.empty()) { 9412008SN/A devIntrPost(Regs::Intr_RxEmpty); 9422008SN/A rxEmpty = true; 9432008SN/A } 9442008SN/A 9455603SN/A if (rxFifo.size() < regs.RxFifoLow) 9462282SN/A rxLow = true; 9472282SN/A 9485603SN/A if (rxFifo.size() > regs.RxFifoHigh) 9492282SN/A rxLow = false; 9502282SN/A 9511939SN/A devIntrPost(Regs::Intr_RxDMA); 9521156SN/A break; 9531156SN/A 9541156SN/A default: 9551156SN/A panic("Invalid rxState!"); 9561156SN/A } 9571156SN/A 9581156SN/A DPRINTF(EthernetSM, "entering next rxState=%s\n", 9591156SN/A RxStateStrings[rxState]); 9601156SN/A 9611156SN/A goto next; 9621156SN/A 9631156SN/A exit: 9641156SN/A /** 9651156SN/A * @todo do we want to schedule a future kick? 9661156SN/A */ 9671156SN/A DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 9681156SN/A RxStateStrings[rxState]); 9691156SN/A} 9701156SN/A 9711156SN/Avoid 9722566SN/ADevice::txDmaDone() 9731156SN/A{ 9741156SN/A assert(txState == txCopy); 9751156SN/A txState = txCopyDone; 9761156SN/A DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 9771156SN/A txDmaAddr, txDmaLen); 9781939SN/A DDUMP(EthernetData, txDmaData, txDmaLen); 9791939SN/A 9801939SN/A // If the receive state machine has a pending DMA, let it go first 9811939SN/A if (rxState == rxBeginCopy) 9821939SN/A rxKick(); 9831939SN/A 9841156SN/A txKick(); 9851156SN/A} 9861156SN/A 9871156SN/Avoid 9881156SN/ADevice::transmit() 9891156SN/A{ 9901156SN/A if (txFifo.empty()) { 9911156SN/A DPRINTF(Ethernet, "nothing to transmit\n"); 9921156SN/A return; 9931156SN/A } 9941156SN/A 9951939SN/A uint32_t interrupts; 9962566SN/A EthPacketPtr packet = txFifo.front(); 9971156SN/A if (!interface->sendPacket(packet)) { 9981156SN/A DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 9991156SN/A txFifo.avail()); 10005603SN/A return; 10011156SN/A } 10021156SN/A 10031156SN/A txFifo.pop(); 10041156SN/A#if TRACING_ON 10051156SN/A if (DTRACE(Ethernet)) { 10061156SN/A IpPtr ip(packet); 10071156SN/A if (ip) { 10081156SN/A DPRINTF(Ethernet, "ID is %d\n", ip->id()); 10091156SN/A TcpPtr tcp(ip); 10101156SN/A if (tcp) { 10112280SN/A DPRINTF(Ethernet, 10122280SN/A "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 10132280SN/A tcp->sport(), tcp->dport(), tcp->seq(), 10142280SN/A tcp->ack()); 10151156SN/A } 10161156SN/A } 10171156SN/A } 10181156SN/A#endif 10191156SN/A 10201939SN/A DDUMP(EthernetData, packet->data, packet->length); 10211156SN/A txBytes += packet->length; 10221156SN/A txPackets++; 10231156SN/A 10241156SN/A DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 10251156SN/A txFifo.avail()); 10261156SN/A 10271939SN/A interrupts = Regs::Intr_TxPacket; 10285603SN/A if (txFifo.size() < regs.TxFifoLow) 10291939SN/A interrupts |= Regs::Intr_TxLow; 10301939SN/A devIntrPost(interrupts); 10311156SN/A} 10321156SN/A 10331156SN/Avoid 10341156SN/ADevice::txKick() 10351156SN/A{ 10362008SN/A VirtualReg *vnic; 10372279SN/A DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", 10381156SN/A TxStateStrings[txState], txFifo.size()); 10391156SN/A 10407823SN/A if (txKickTick > curTick()) { 10412279SN/A DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", 10421156SN/A txKickTick); 10431156SN/A return; 10441156SN/A } 10451156SN/A 10461156SN/A next: 10472008SN/A if (txState == txIdle) 10481156SN/A goto exit; 10491156SN/A 10502008SN/A assert(!txList.empty()); 10512008SN/A vnic = &virtualRegs[txList.front()]; 10522008SN/A 10532008SN/A switch (txState) { 10541156SN/A case txFifoBlock: 10552280SN/A assert(Regs::get_TxDone_Busy(vnic->TxDone)); 10561156SN/A if (!txPacket) { 10571156SN/A // Grab a new packet from the fifo. 105810469SN/A txPacket = make_shared<EthPacketData>(16384); 10592008SN/A txPacketOffset = 0; 10601156SN/A } 10611156SN/A 10621156SN/A if (txFifo.avail() - txPacket->length < 10632008SN/A Regs::get_TxData_Len(vnic->TxData)) { 10641156SN/A DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 10651156SN/A goto exit; 10661156SN/A } 10671156SN/A 10681156SN/A txState = txBeginCopy; 10691156SN/A break; 10701156SN/A 10711156SN/A case txBeginCopy: 107210913SN/A if (dmaPending() || drainState() != DrainState::Running) 10731939SN/A goto exit; 10741939SN/A 107511202SN/A txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData)); 10762008SN/A txDmaLen = Regs::get_TxData_Len(vnic->TxData); 10772008SN/A txDmaData = txPacket->data + txPacketOffset; 10781939SN/A txState = txCopy; 10791156SN/A 10802566SN/A dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); 10811156SN/A break; 10821156SN/A 10831156SN/A case txCopy: 10841156SN/A DPRINTF(EthernetSM, "transmit machine still copying\n"); 10851156SN/A goto exit; 10861156SN/A 10871156SN/A case txCopyDone: 10882008SN/A vnic->TxDone = txDmaLen | Regs::TxDone_Complete; 10891156SN/A txPacket->length += txDmaLen; 10902008SN/A if ((vnic->TxData & Regs::TxData_More)) { 10912008SN/A txPacketOffset += txDmaLen; 10922008SN/A txState = txIdle; 10932008SN/A devIntrPost(Regs::Intr_TxDMA); 10942008SN/A break; 10951156SN/A } 10961156SN/A 10972008SN/A assert(txPacket->length <= txFifo.avail()); 10982008SN/A if ((vnic->TxData & Regs::TxData_Checksum)) { 10992008SN/A IpPtr ip(txPacket); 11002008SN/A if (ip) { 11012008SN/A TcpPtr tcp(ip); 11022008SN/A if (tcp) { 11032008SN/A tcp->sum(0); 11042008SN/A tcp->sum(cksum(tcp)); 11052008SN/A txTcpChecksums++; 11062008SN/A } 11072008SN/A 11082008SN/A UdpPtr udp(ip); 11092008SN/A if (udp) { 11102008SN/A udp->sum(0); 11112008SN/A udp->sum(cksum(udp)); 11122008SN/A txUdpChecksums++; 11132008SN/A } 11142008SN/A 11152008SN/A ip->sum(0); 11162008SN/A ip->sum(cksum(ip)); 11172008SN/A txIpChecksums++; 11182008SN/A } 11192008SN/A } 11202008SN/A 11212008SN/A txFifo.push(txPacket); 11222008SN/A if (txFifo.avail() < regs.TxMaxCopy) { 11232008SN/A devIntrPost(Regs::Intr_TxFull); 11242008SN/A txFull = true; 11252008SN/A } 11262008SN/A txPacket = 0; 11272008SN/A transmit(); 11282008SN/A txList.pop_front(); 11292008SN/A txState = txList.empty() ? txIdle : txFifoBlock; 11301939SN/A devIntrPost(Regs::Intr_TxDMA); 11311156SN/A break; 11321156SN/A 11331156SN/A default: 11341156SN/A panic("Invalid txState!"); 11351156SN/A } 11361156SN/A 11371156SN/A DPRINTF(EthernetSM, "entering next txState=%s\n", 11381156SN/A TxStateStrings[txState]); 11391156SN/A 11401156SN/A goto next; 11411156SN/A 11421156SN/A exit: 11431156SN/A /** 11441156SN/A * @todo do we want to schedule a future kick? 11451156SN/A */ 11461156SN/A DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 11471156SN/A TxStateStrings[txState]); 11481156SN/A} 11491156SN/A 11501156SN/Avoid 11511156SN/ADevice::transferDone() 11521156SN/A{ 11531156SN/A if (txFifo.empty()) { 11541156SN/A DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 11551156SN/A return; 11561156SN/A } 11571156SN/A 11581156SN/A DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 11591156SN/A 11609417SN/A reschedule(txEvent, clockEdge(Cycles(1)), true); 11611156SN/A} 11621156SN/A 11631156SN/Abool 11642566SN/ADevice::rxFilter(const EthPacketPtr &packet) 11651156SN/A{ 11661156SN/A if (!Regs::get_Config_Filter(regs.Config)) 11671156SN/A return false; 11681156SN/A 11691156SN/A panic("receive filter not implemented\n"); 11701156SN/A bool drop = true; 11711156SN/A 11721156SN/A#if 0 11731156SN/A string type; 11741156SN/A 11751156SN/A EthHdr *eth = packet->eth(); 11761156SN/A if (eth->unicast()) { 11771156SN/A // If we're accepting all unicast addresses 11781156SN/A if (acceptUnicast) 11791156SN/A drop = false; 11801156SN/A 11811156SN/A // If we make a perfect match 11821156SN/A if (acceptPerfect && params->eaddr == eth.dst()) 11831156SN/A drop = false; 11841156SN/A 11851156SN/A if (acceptArp && eth->type() == ETH_TYPE_ARP) 11861156SN/A drop = false; 11871156SN/A 11881156SN/A } else if (eth->broadcast()) { 11891156SN/A // if we're accepting broadcasts 11901156SN/A if (acceptBroadcast) 11911156SN/A drop = false; 11921156SN/A 11931156SN/A } else if (eth->multicast()) { 11941156SN/A // if we're accepting all multicasts 11951156SN/A if (acceptMulticast) 11961156SN/A drop = false; 11971156SN/A 11981156SN/A } 11991156SN/A 12001156SN/A if (drop) { 12011156SN/A DPRINTF(Ethernet, "rxFilter drop\n"); 12021156SN/A DDUMP(EthernetData, packet->data, packet->length); 12031156SN/A } 12041156SN/A#endif 12051156SN/A return drop; 12061156SN/A} 12071156SN/A 12081156SN/Abool 12092566SN/ADevice::recvPacket(EthPacketPtr packet) 12101156SN/A{ 12111156SN/A rxBytes += packet->length; 12121156SN/A rxPackets++; 12131156SN/A 12141156SN/A DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 12151156SN/A rxFifo.avail()); 12161156SN/A 12171156SN/A if (!rxEnable) { 12181156SN/A DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 12191156SN/A return true; 12201156SN/A } 12211156SN/A 12221156SN/A if (rxFilter(packet)) { 12231156SN/A DPRINTF(Ethernet, "packet filtered...dropped\n"); 12241156SN/A return true; 12251156SN/A } 12261156SN/A 12275603SN/A if (rxFifo.size() >= regs.RxFifoHigh) 12281939SN/A devIntrPost(Regs::Intr_RxHigh); 12291156SN/A 12301156SN/A if (!rxFifo.push(packet)) { 12311156SN/A DPRINTF(Ethernet, 12321156SN/A "packet will not fit in receive buffer...packet dropped\n"); 12331156SN/A return false; 12341156SN/A } 12351156SN/A 12362008SN/A // If we were at the last element, back up one ot go to the new 12372008SN/A // last element of the list. 12382008SN/A if (rxFifoPtr == rxFifo.end()) 12392008SN/A --rxFifoPtr; 12402008SN/A 12411939SN/A devIntrPost(Regs::Intr_RxPacket); 12421156SN/A rxKick(); 12431156SN/A return true; 12441156SN/A} 12451156SN/A 12462901SN/Avoid 12479342SN/ADevice::drainResume() 12482901SN/A{ 12499342SN/A Drainable::drainResume(); 12502901SN/A 12512901SN/A // During drain we could have left the state machines in a waiting state and 12522901SN/A // they wouldn't get out until some other event occured to kick them. 12532901SN/A // This way they'll get out immediately 12542901SN/A txKick(); 12552901SN/A rxKick(); 12562901SN/A} 12572901SN/A 12581156SN/A//===================================================================== 12591156SN/A// 12601156SN/A// 12611156SN/Avoid 126210905SN/ABase::serialize(CheckpointOut &cp) const 12631156SN/A{ 12649807SN/A // Serialize the PciDevice base class 126510905SN/A PciDevice::serialize(cp); 12661156SN/A 12671156SN/A SERIALIZE_SCALAR(rxEnable); 12681156SN/A SERIALIZE_SCALAR(txEnable); 12691156SN/A SERIALIZE_SCALAR(cpuIntrEnable); 12701156SN/A 12711156SN/A /* 12721156SN/A * Keep track of pending interrupt status. 12731156SN/A */ 12741156SN/A SERIALIZE_SCALAR(intrTick); 12751156SN/A SERIALIZE_SCALAR(cpuPendingIntr); 12761156SN/A Tick intrEventTick = 0; 12771156SN/A if (intrEvent) 12781156SN/A intrEventTick = intrEvent->when(); 12791156SN/A SERIALIZE_SCALAR(intrEventTick); 12801156SN/A} 12811156SN/A 12821156SN/Avoid 128310905SN/ABase::unserialize(CheckpointIn &cp) 12841156SN/A{ 12859807SN/A // Unserialize the PciDevice base class 128610905SN/A PciDevice::unserialize(cp); 12871156SN/A 12881156SN/A UNSERIALIZE_SCALAR(rxEnable); 12891156SN/A UNSERIALIZE_SCALAR(txEnable); 12901156SN/A UNSERIALIZE_SCALAR(cpuIntrEnable); 12911156SN/A 12921156SN/A /* 12931156SN/A * Keep track of pending interrupt status. 12941156SN/A */ 12951156SN/A UNSERIALIZE_SCALAR(intrTick); 12961156SN/A UNSERIALIZE_SCALAR(cpuPendingIntr); 12971156SN/A Tick intrEventTick; 12981156SN/A UNSERIALIZE_SCALAR(intrEventTick); 12991156SN/A if (intrEventTick) { 13005606SN/A intrEvent = new IntrEvent(this, true); 13015606SN/A schedule(intrEvent, intrEventTick); 13021156SN/A } 13031156SN/A} 13041156SN/A 13051156SN/Avoid 130611006SN/ADevice::serialize(CheckpointOut &cp) const 13071156SN/A{ 13082287SN/A int count; 13092287SN/A 13109807SN/A // Serialize the PciDevice base class 131110905SN/A Base::serialize(cp); 13121156SN/A 13131939SN/A if (rxState == rxCopy) 13141939SN/A panic("can't serialize with an in flight dma request rxState=%s", 13151939SN/A RxStateStrings[rxState]); 13161156SN/A 13171939SN/A if (txState == txCopy) 13181939SN/A panic("can't serialize with an in flight dma request txState=%s", 13191939SN/A TxStateStrings[txState]); 13201156SN/A 13211156SN/A /* 13225603SN/A * Serialize the device registers that could be modified by the OS. 13231156SN/A */ 13241156SN/A SERIALIZE_SCALAR(regs.Config); 13251939SN/A SERIALIZE_SCALAR(regs.IntrStatus); 13261939SN/A SERIALIZE_SCALAR(regs.IntrMask); 13271156SN/A SERIALIZE_SCALAR(regs.RxData); 13281156SN/A SERIALIZE_SCALAR(regs.TxData); 13291156SN/A 13301156SN/A /* 13312008SN/A * Serialize the virtual nic state 13322008SN/A */ 13332008SN/A int virtualRegsSize = virtualRegs.size(); 13342008SN/A SERIALIZE_SCALAR(virtualRegsSize); 13352008SN/A for (int i = 0; i < virtualRegsSize; ++i) { 133610905SN/A const VirtualReg *vnic = &virtualRegs[i]; 13372008SN/A 13382566SN/A std::string reg = csprintf("vnic%d", i); 133910905SN/A paramOut(cp, reg + ".RxData", vnic->RxData); 134010905SN/A paramOut(cp, reg + ".RxDone", vnic->RxDone); 134110905SN/A paramOut(cp, reg + ".TxData", vnic->TxData); 134210905SN/A paramOut(cp, reg + ".TxDone", vnic->TxDone); 13432008SN/A 13445603SN/A bool rxPacketExists = vnic->rxIndex != rxFifo.end(); 134510905SN/A paramOut(cp, reg + ".rxPacketExists", rxPacketExists); 13462008SN/A if (rxPacketExists) { 13472008SN/A int rxPacket = 0; 134811006SN/A auto i = rxFifo.begin(); 13495603SN/A while (i != vnic->rxIndex) { 13502008SN/A assert(i != rxFifo.end()); 13512008SN/A ++i; 13522008SN/A ++rxPacket; 13532008SN/A } 13542008SN/A 135510905SN/A paramOut(cp, reg + ".rxPacket", rxPacket); 135610905SN/A paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset); 135710905SN/A paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 13582008SN/A } 135910905SN/A paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData); 13602008SN/A } 13612008SN/A 13625603SN/A int rxFifoPtr = -1; 13635603SN/A if (this->rxFifoPtr != rxFifo.end()) 13645603SN/A rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); 13652282SN/A SERIALIZE_SCALAR(rxFifoPtr); 13662282SN/A 13672282SN/A SERIALIZE_SCALAR(rxActive); 13685603SN/A SERIALIZE_SCALAR(rxBusyCount); 13695603SN/A SERIALIZE_SCALAR(rxDirtyCount); 13705603SN/A SERIALIZE_SCALAR(rxMappedCount); 13712282SN/A 137211006SN/A VirtualList::const_iterator i, end; 13732008SN/A for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) 137410905SN/A paramOut(cp, csprintf("rxList%d", count++), *i); 13752282SN/A int rxListSize = count; 13762282SN/A SERIALIZE_SCALAR(rxListSize); 13772008SN/A 13782282SN/A for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) 137910905SN/A paramOut(cp, csprintf("rxBusy%d", count++), *i); 13802282SN/A int rxBusySize = count; 13812282SN/A SERIALIZE_SCALAR(rxBusySize); 13822282SN/A 13832008SN/A for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) 138410905SN/A paramOut(cp, csprintf("txList%d", count++), *i); 13852282SN/A int txListSize = count; 13862282SN/A SERIALIZE_SCALAR(txListSize); 13872008SN/A 13882008SN/A /* 13891156SN/A * Serialize rx state machine 13901156SN/A */ 13911156SN/A int rxState = this->rxState; 13921156SN/A SERIALIZE_SCALAR(rxState); 13931939SN/A SERIALIZE_SCALAR(rxEmpty); 13942282SN/A SERIALIZE_SCALAR(rxLow); 139510905SN/A rxFifo.serialize("rxFifo", cp); 13961156SN/A 13971156SN/A /* 13981156SN/A * Serialize tx state machine 13991156SN/A */ 14001156SN/A int txState = this->txState; 14011156SN/A SERIALIZE_SCALAR(txState); 14021939SN/A SERIALIZE_SCALAR(txFull); 140310905SN/A txFifo.serialize("txFifo", cp); 140410469SN/A bool txPacketExists = txPacket != nullptr; 14051156SN/A SERIALIZE_SCALAR(txPacketExists); 14061156SN/A if (txPacketExists) { 140710905SN/A txPacket->serialize("txPacket", cp); 14082008SN/A SERIALIZE_SCALAR(txPacketOffset); 14092008SN/A SERIALIZE_SCALAR(txPacketBytes); 14101156SN/A } 14111156SN/A 14121156SN/A /* 14131156SN/A * If there's a pending transmit, store the time so we can 14141156SN/A * reschedule it later 14151156SN/A */ 14167823SN/A Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 14171156SN/A SERIALIZE_SCALAR(transmitTick); 14181156SN/A} 14191156SN/A 14201156SN/Avoid 142110905SN/ADevice::unserialize(CheckpointIn &cp) 14221156SN/A{ 14239807SN/A // Unserialize the PciDevice base class 142410905SN/A Base::unserialize(cp); 14251156SN/A 14261156SN/A /* 14275603SN/A * Unserialize the device registers that may have been written by the OS. 14281156SN/A */ 14291156SN/A UNSERIALIZE_SCALAR(regs.Config); 14301939SN/A UNSERIALIZE_SCALAR(regs.IntrStatus); 14311939SN/A UNSERIALIZE_SCALAR(regs.IntrMask); 14321156SN/A UNSERIALIZE_SCALAR(regs.RxData); 14331156SN/A UNSERIALIZE_SCALAR(regs.TxData); 14341156SN/A 14352282SN/A UNSERIALIZE_SCALAR(rxActive); 14365603SN/A UNSERIALIZE_SCALAR(rxBusyCount); 14375603SN/A UNSERIALIZE_SCALAR(rxDirtyCount); 14385603SN/A UNSERIALIZE_SCALAR(rxMappedCount); 14392282SN/A 14402008SN/A int rxListSize; 14412008SN/A UNSERIALIZE_SCALAR(rxListSize); 14422008SN/A rxList.clear(); 14432008SN/A for (int i = 0; i < rxListSize; ++i) { 14442008SN/A int value; 144510905SN/A paramIn(cp, csprintf("rxList%d", i), value); 14462008SN/A rxList.push_back(value); 14472008SN/A } 14482008SN/A 14492282SN/A int rxBusySize; 14502282SN/A UNSERIALIZE_SCALAR(rxBusySize); 14512282SN/A rxBusy.clear(); 14522282SN/A for (int i = 0; i < rxBusySize; ++i) { 14532282SN/A int value; 145410905SN/A paramIn(cp, csprintf("rxBusy%d", i), value); 14552282SN/A rxBusy.push_back(value); 14562282SN/A } 14572282SN/A 14582008SN/A int txListSize; 14592008SN/A UNSERIALIZE_SCALAR(txListSize); 14602008SN/A txList.clear(); 14612008SN/A for (int i = 0; i < txListSize; ++i) { 14622008SN/A int value; 146310905SN/A paramIn(cp, csprintf("txList%d", i), value); 14642008SN/A txList.push_back(value); 14652008SN/A } 14662008SN/A 14671156SN/A /* 14681156SN/A * Unserialize rx state machine 14691156SN/A */ 14701156SN/A int rxState; 14711156SN/A UNSERIALIZE_SCALAR(rxState); 14721939SN/A UNSERIALIZE_SCALAR(rxEmpty); 14732282SN/A UNSERIALIZE_SCALAR(rxLow); 14741156SN/A this->rxState = (RxState) rxState; 147510905SN/A rxFifo.unserialize("rxFifo", cp); 14761156SN/A 14772282SN/A int rxFifoPtr; 14782282SN/A UNSERIALIZE_SCALAR(rxFifoPtr); 14795603SN/A if (rxFifoPtr >= 0) { 14805603SN/A this->rxFifoPtr = rxFifo.begin(); 14815603SN/A for (int i = 0; i < rxFifoPtr; ++i) 14825603SN/A ++this->rxFifoPtr; 14835603SN/A } else { 14845603SN/A this->rxFifoPtr = rxFifo.end(); 14855603SN/A } 14862282SN/A 14871156SN/A /* 14881156SN/A * Unserialize tx state machine 14891156SN/A */ 14901156SN/A int txState; 14911156SN/A UNSERIALIZE_SCALAR(txState); 14921939SN/A UNSERIALIZE_SCALAR(txFull); 14931156SN/A this->txState = (TxState) txState; 149410905SN/A txFifo.unserialize("txFifo", cp); 14951156SN/A bool txPacketExists; 14961156SN/A UNSERIALIZE_SCALAR(txPacketExists); 14971156SN/A txPacket = 0; 14981156SN/A if (txPacketExists) { 149910469SN/A txPacket = make_shared<EthPacketData>(16384); 150010905SN/A txPacket->unserialize("txPacket", cp); 15012008SN/A UNSERIALIZE_SCALAR(txPacketOffset); 15022008SN/A UNSERIALIZE_SCALAR(txPacketBytes); 15032008SN/A } 15042008SN/A 15052008SN/A /* 15062008SN/A * unserialize the virtual nic registers/state 15072008SN/A * 15082008SN/A * this must be done after the unserialization of the rxFifo 15092008SN/A * because the packet iterators depend on the fifo being populated 15102008SN/A */ 15112008SN/A int virtualRegsSize; 15122008SN/A UNSERIALIZE_SCALAR(virtualRegsSize); 15132008SN/A virtualRegs.clear(); 15142008SN/A virtualRegs.resize(virtualRegsSize); 15152008SN/A for (int i = 0; i < virtualRegsSize; ++i) { 15162008SN/A VirtualReg *vnic = &virtualRegs[i]; 15172566SN/A std::string reg = csprintf("vnic%d", i); 15182008SN/A 151910905SN/A paramIn(cp, reg + ".RxData", vnic->RxData); 152010905SN/A paramIn(cp, reg + ".RxDone", vnic->RxDone); 152110905SN/A paramIn(cp, reg + ".TxData", vnic->TxData); 152210905SN/A paramIn(cp, reg + ".TxDone", vnic->TxDone); 15232008SN/A 15242282SN/A vnic->rxUnique = rxUnique++; 15252282SN/A vnic->txUnique = txUnique++; 15262282SN/A 15272008SN/A bool rxPacketExists; 152810905SN/A paramIn(cp, reg + ".rxPacketExists", rxPacketExists); 15292008SN/A if (rxPacketExists) { 15302008SN/A int rxPacket; 153110905SN/A paramIn(cp, reg + ".rxPacket", rxPacket); 15325603SN/A vnic->rxIndex = rxFifo.begin(); 15332008SN/A while (rxPacket--) 15345603SN/A ++vnic->rxIndex; 15352008SN/A 153610905SN/A paramIn(cp, reg + ".rxPacketOffset", 15372008SN/A vnic->rxPacketOffset); 153810905SN/A paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 15392008SN/A } else { 15405603SN/A vnic->rxIndex = rxFifo.end(); 15412008SN/A } 154210905SN/A paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData); 15431156SN/A } 15441156SN/A 15451156SN/A /* 15461156SN/A * If there's a pending transmit, reschedule it now 15471156SN/A */ 15481156SN/A Tick transmitTick; 15491156SN/A UNSERIALIZE_SCALAR(transmitTick); 15501156SN/A if (transmitTick) 15517823SN/A schedule(txEvent, curTick() + transmitTick); 15521156SN/A 15538851SN/A pioPort.sendRangeChange(); 15542566SN/A 15551156SN/A} 15561156SN/A 15577811SN/A} // namespace Sinic 15581156SN/A 15594762SN/ASinic::Device * 15604762SN/ASinicParams::create() 15611156SN/A{ 15624762SN/A return new Sinic::Device(this); 15631156SN/A} 1564