1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Nathan Binkert 29 */ 30 31#include "dev/net/sinic.hh" 32 33#include <deque> 34#include <limits> 35#include <string> 36 37#ifdef SINIC_VTOPHYS 38#include "arch/vtophys.hh" 39 40#endif 41#include "base/compiler.hh" 42#include "base/debug.hh" 43#include "base/inet.hh" 44#include "base/types.hh" 45#include "config/the_isa.hh" 46#include "debug/EthernetAll.hh" 47#include "dev/net/etherlink.hh" 48#include "mem/packet.hh" 49#include "mem/packet_access.hh" 50#include "sim/eventq.hh" 51#include "sim/stats.hh" 52 53using namespace std; 54using namespace Net; 55using namespace TheISA; 56 57namespace Sinic { 58 59const char *RxStateStrings[] = 60{ 61 "rxIdle", 62 "rxFifoBlock", 63 "rxBeginCopy", 64 "rxCopy", 65 "rxCopyDone" 66}; 67 68const char *TxStateStrings[] = 69{ 70 "txIdle", 71 "txFifoBlock", 72 "txBeginCopy", 73 "txCopy", 74 "txCopyDone" 75}; 76 77 78/////////////////////////////////////////////////////////////////////// 79// 80// Sinic PCI Device 81// 82Base::Base(const Params *p) 83 : EtherDevBase(p), rxEnable(false), txEnable(false), 84 intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), 85 cpuPendingIntr(false), intrEvent(0), interface(NULL) 86{ 87} 88 89Device::Device(const Params *p) 90 : Base(p), rxUnique(0), txUnique(0), 91 virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count), 92 rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), 93 rxKickTick(0), txKickTick(0), 94 txEvent([this]{ txEventTransmit(); }, name()), 95 rxDmaEvent([this]{ rxDmaDone(); }, name()), 96 txDmaEvent([this]{ txDmaDone(); }, name()), 97 dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), 98 dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) 99{ 100 interface = new Interface(name() + ".int0", this); 101 reset(); 102 103} 104 105Device::~Device() 106{} 107 108void 109Device::regStats() 110{ 111 Base::regStats(); 112 113 _maxVnicDistance = 0; 114 115 maxVnicDistance 116 .name(name() + ".maxVnicDistance") 117 .desc("maximum vnic distance") 118 ; 119 120 totalVnicDistance 121 .name(name() + ".totalVnicDistance") 122 .desc("total vnic distance") 123 ; 124 numVnicDistance 125 .name(name() + ".numVnicDistance") 126 .desc("number of vnic distance measurements") 127 ; 128 129 avgVnicDistance 130 .name(name() + ".avgVnicDistance") 131 .desc("average vnic distance") 132 ; 133 134 avgVnicDistance = totalVnicDistance / numVnicDistance; 135} 136 137void 138Device::resetStats() 139{ 140 Base::resetStats(); 141 142 _maxVnicDistance = 0; 143} 144 145Port & 146Device::getPort(const std::string &if_name, PortID idx) 147{ 148 if (if_name == "interface") 149 return *interface; 150 return EtherDevBase::getPort(if_name, idx); 151} 152 153 154void 155Device::prepareIO(ContextID cpu, int index) 156{ 157 int size = virtualRegs.size(); 158 if (index > size) 159 panic("Trying to access a vnic that doesn't exist %d > %d\n", 160 index, size); 161} 162 163//add stats for head of line blocking 164//add stats for average fifo length 165//add stats for average number of vnics busy 166 167void 168Device::prepareRead(ContextID cpu, int index) 169{ 170 using namespace Regs; 171 prepareIO(cpu, index); 172 173 VirtualReg &vnic = virtualRegs[index]; 174 175 // update rx registers 176 uint64_t rxdone = vnic.RxDone; 177 rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); 178 rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); 179 rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh); 180 rxdone = set_RxDone_NotHigh(rxdone, rxLow); 181 regs.RxData = vnic.RxData; 182 regs.RxDone = rxdone; 183 regs.RxWait = rxdone; 184 185 // update tx regsiters 186 uint64_t txdone = vnic.TxDone; 187 txdone = set_TxDone_Packets(txdone, txFifo.packets()); 188 txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); 189 txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow); 190 regs.TxData = vnic.TxData; 191 regs.TxDone = txdone; 192 regs.TxWait = txdone; 193 194 int head = 0xffff; 195 196 if (!rxFifo.empty()) { 197 int vnic = rxFifo.begin()->priv; 198 if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0) 199 head = vnic; 200 } 201 202 regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head); 203 regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount); 204 regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount); 205 regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount); 206} 207 208void 209Device::prepareWrite(ContextID cpu, int index) 210{ 211 prepareIO(cpu, index); 212} 213 214/** 215 * I/O read of device register 216 */ 217Tick 218Device::read(PacketPtr pkt) 219{ 220 assert(config.command & PCI_CMD_MSE); 221 assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 222 223 ContextID cpu = pkt->req->contextId(); 224 Addr daddr = pkt->getAddr() - BARAddrs[0]; 225 Addr index = daddr >> Regs::VirtualShift; 226 Addr raddr = daddr & Regs::VirtualMask; 227 228 if (!regValid(raddr)) 229 panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d", 230 cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 231 232 const Regs::Info &info = regInfo(raddr); 233 if (!info.read) 234 panic("read %s (write only): " 235 "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 236 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 237 238 panic("read %s (invalid size): " 239 "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 240 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 241 242 prepareRead(cpu, index); 243 244 uint64_t value M5_VAR_USED = 0; 245 if (pkt->getSize() == 4) { 246 uint32_t reg = regData32(raddr); 247 pkt->setLE(reg); 248 value = reg; 249 } 250 251 if (pkt->getSize() == 8) { 252 uint64_t reg = regData64(raddr); 253 pkt->setLE(reg); 254 value = reg; 255 } 256 257 DPRINTF(EthernetPIO, 258 "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n", 259 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value); 260 261 // reading the interrupt status register has the side effect of 262 // clearing it 263 if (raddr == Regs::IntrStatus) 264 devIntrClear(); 265 266 return pioDelay; 267} 268 269/** 270 * IPR read of device register 271 272 Fault 273Device::iprRead(Addr daddr, ContextID cpu, uint64_t &result) 274{ 275 if (!regValid(daddr)) 276 panic("invalid address: da=%#x", daddr); 277 278 const Regs::Info &info = regInfo(daddr); 279 if (!info.read) 280 panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); 281 282 DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", 283 info.name, cpu, daddr); 284 285 prepareRead(cpu, 0); 286 287 if (info.size == 4) 288 result = regData32(daddr); 289 290 if (info.size == 8) 291 result = regData64(daddr); 292 293 DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", 294 info.name, cpu, result); 295 296 return NoFault; 297} 298*/ 299/** 300 * I/O write of device register 301 */ 302Tick 303Device::write(PacketPtr pkt) 304{ 305 assert(config.command & PCI_CMD_MSE); 306 assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 307 308 ContextID cpu = pkt->req->contextId(); 309 Addr daddr = pkt->getAddr() - BARAddrs[0]; 310 Addr index = daddr >> Regs::VirtualShift; 311 Addr raddr = daddr & Regs::VirtualMask; 312 313 if (!regValid(raddr)) 314 panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", 315 cpu, daddr, pkt->getAddr(), pkt->getSize()); 316 317 const Regs::Info &info = regInfo(raddr); 318 if (!info.write) 319 panic("write %s (read only): " 320 "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 321 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 322 323 if (pkt->getSize() != info.size) 324 panic("write %s (invalid size): " 325 "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 326 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 327 328 VirtualReg &vnic = virtualRegs[index]; 329 330 DPRINTF(EthernetPIO, 331 "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", 332 info.name, index, cpu, info.size == 4 ? 333 pkt->getLE<uint32_t>() : pkt->getLE<uint64_t>(), 334 daddr, pkt->getAddr(), pkt->getSize()); 335 336 prepareWrite(cpu, index); 337 338 switch (raddr) { 339 case Regs::Config: 340 changeConfig(pkt->getLE<uint32_t>()); 341 break; 342 343 case Regs::Command: 344 command(pkt->getLE<uint32_t>()); 345 break; 346 347 case Regs::IntrStatus: 348 devIntrClear(regs.IntrStatus & 349 pkt->getLE<uint32_t>()); 350 break; 351 352 case Regs::IntrMask: 353 devIntrChangeMask(pkt->getLE<uint32_t>()); 354 break; 355 356 case Regs::RxData: 357 if (Regs::get_RxDone_Busy(vnic.RxDone)) 358 panic("receive machine busy with another request! rxState=%s", 359 RxStateStrings[rxState]); 360 361 vnic.rxUnique = rxUnique++; 362 vnic.RxDone = Regs::RxDone_Busy; 363 vnic.RxData = pkt->getLE<uint64_t>(); 364 rxBusyCount++; 365 366 if (Regs::get_RxData_Vaddr(pkt->getLE<uint64_t>())) { 367 panic("vtophys not implemented in newmem"); 368#ifdef SINIC_VTOPHYS 369 Addr vaddr = Regs::get_RxData_Addr(reg64); 370 Addr paddr = vtophys(req->xc, vaddr); 371 DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " 372 "vaddr=%#x, paddr=%#x\n", 373 index, vnic.rxUnique, vaddr, paddr); 374 375 vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr); 376#endif 377 } else { 378 DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", 379 index, vnic.rxUnique); 380 } 381 382 if (vnic.rxIndex == rxFifo.end()) { 383 DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); 384 rxList.push_back(index); 385 } else { 386 DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n"); 387 rxBusy.push_back(index); 388 } 389 390 if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) { 391 rxState = rxFifoBlock; 392 rxKick(); 393 } 394 break; 395 396 case Regs::TxData: 397 if (Regs::get_TxDone_Busy(vnic.TxDone)) 398 panic("transmit machine busy with another request! txState=%s", 399 TxStateStrings[txState]); 400 401 vnic.txUnique = txUnique++; 402 vnic.TxDone = Regs::TxDone_Busy; 403 404 if (Regs::get_TxData_Vaddr(pkt->getLE<uint64_t>())) { 405 panic("vtophys won't work here in newmem.\n"); 406#ifdef SINIC_VTOPHYS 407 Addr vaddr = Regs::get_TxData_Addr(reg64); 408 Addr paddr = vtophys(req->xc, vaddr); 409 DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): " 410 "vaddr=%#x, paddr=%#x\n", 411 index, vnic.txUnique, vaddr, paddr); 412 413 vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr); 414#endif 415 } else { 416 DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n", 417 index, vnic.txUnique); 418 } 419 420 if (txList.empty() || txList.front() != index) 421 txList.push_back(index); 422 if (txEnable && txState == txIdle && txList.front() == index) { 423 txState = txFifoBlock; 424 txKick(); 425 } 426 break; 427 } 428 429 return pioDelay; 430} 431 432void 433Device::devIntrPost(uint32_t interrupts) 434{ 435 if ((interrupts & Regs::Intr_Res)) 436 panic("Cannot set a reserved interrupt"); 437 438 regs.IntrStatus |= interrupts; 439 440 DPRINTF(EthernetIntr, 441 "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", 442 interrupts, regs.IntrStatus, regs.IntrMask); 443 444 interrupts = regs.IntrStatus & regs.IntrMask; 445 446 // Intr_RxHigh is special, we only signal it if we've emptied the fifo 447 // and then filled it above the high watermark 448 if (rxEmpty) 449 rxEmpty = false; 450 else 451 interrupts &= ~Regs::Intr_RxHigh; 452 453 // Intr_TxLow is special, we only signal it if we've filled up the fifo 454 // and then dropped below the low watermark 455 if (txFull) 456 txFull = false; 457 else 458 interrupts &= ~Regs::Intr_TxLow; 459 460 if (interrupts) { 461 Tick when = curTick(); 462 if ((interrupts & Regs::Intr_NoDelay) == 0) 463 when += intrDelay; 464 cpuIntrPost(when); 465 } 466} 467 468void 469Device::devIntrClear(uint32_t interrupts) 470{ 471 if ((interrupts & Regs::Intr_Res)) 472 panic("Cannot clear a reserved interrupt"); 473 474 regs.IntrStatus &= ~interrupts; 475 476 DPRINTF(EthernetIntr, 477 "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", 478 interrupts, regs.IntrStatus, regs.IntrMask); 479 480 if (!(regs.IntrStatus & regs.IntrMask)) 481 cpuIntrClear(); 482} 483 484void 485Device::devIntrChangeMask(uint32_t newmask) 486{ 487 if (regs.IntrMask == newmask) 488 return; 489 490 regs.IntrMask = newmask; 491 492 DPRINTF(EthernetIntr, 493 "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", 494 regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); 495 496 if (regs.IntrStatus & regs.IntrMask) 497 cpuIntrPost(curTick()); 498 else 499 cpuIntrClear(); 500} 501 502void 503Base::cpuIntrPost(Tick when) 504{ 505 // If the interrupt you want to post is later than an interrupt 506 // already scheduled, just let it post in the coming one and don't 507 // schedule another. 508 // HOWEVER, must be sure that the scheduled intrTick is in the 509 // future (this was formerly the source of a bug) 510 /** 511 * @todo this warning should be removed and the intrTick code should 512 * be fixed. 513 */ 514 assert(when >= curTick()); 515 assert(intrTick >= curTick() || intrTick == 0); 516 if (!cpuIntrEnable) { 517 DPRINTF(EthernetIntr, "interrupts not enabled.\n", 518 intrTick); 519 return; 520 } 521 522 if (when > intrTick && intrTick != 0) { 523 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 524 intrTick); 525 return; 526 } 527 528 intrTick = when; 529 if (intrTick < curTick()) { 530 intrTick = curTick(); 531 } 532 533 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 534 intrTick); 535 536 if (intrEvent) 537 intrEvent->squash(); 538 539 intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); }, 540 name(), true); 541 schedule(intrEvent, intrTick); 542} 543 544void 545Base::cpuInterrupt() 546{ 547 assert(intrTick == curTick()); 548 549 // Whether or not there's a pending interrupt, we don't care about 550 // it anymore 551 intrEvent = 0; 552 intrTick = 0; 553 554 // Don't send an interrupt if there's already one 555 if (cpuPendingIntr) { 556 DPRINTF(EthernetIntr, 557 "would send an interrupt now, but there's already pending\n"); 558 } else { 559 // Send interrupt 560 cpuPendingIntr = true; 561 562 DPRINTF(EthernetIntr, "posting interrupt\n"); 563 intrPost(); 564 } 565} 566 567void 568Base::cpuIntrClear() 569{ 570 if (!cpuPendingIntr) 571 return; 572 573 if (intrEvent) { 574 intrEvent->squash(); 575 intrEvent = 0; 576 } 577 578 intrTick = 0; 579 580 cpuPendingIntr = false; 581 582 DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 583 intrClear(); 584} 585 586bool 587Base::cpuIntrPending() const 588{ return cpuPendingIntr; } 589 590void 591Device::changeConfig(uint32_t newconf) 592{ 593 uint32_t changed = regs.Config ^ newconf; 594 if (!changed) 595 return; 596 597 regs.Config = newconf; 598 599 if ((changed & Regs::Config_IntEn)) { 600 cpuIntrEnable = regs.Config & Regs::Config_IntEn; 601 if (cpuIntrEnable) { 602 if (regs.IntrStatus & regs.IntrMask) 603 cpuIntrPost(curTick()); 604 } else { 605 cpuIntrClear(); 606 } 607 } 608 609 if ((changed & Regs::Config_TxEn)) { 610 txEnable = regs.Config & Regs::Config_TxEn; 611 if (txEnable) 612 txKick(); 613 } 614 615 if ((changed & Regs::Config_RxEn)) { 616 rxEnable = regs.Config & Regs::Config_RxEn; 617 if (rxEnable) 618 rxKick(); 619 } 620} 621 622void 623Device::command(uint32_t command) 624{ 625 if (command & Regs::Command_Intr) 626 devIntrPost(Regs::Intr_Soft); 627 628 if (command & Regs::Command_Reset) 629 reset(); 630} 631 632void 633Device::reset() 634{ 635 using namespace Regs; 636 637 memset(®s, 0, sizeof(regs)); 638 639 regs.Config = 0; 640 if (params()->rx_thread) 641 regs.Config |= Config_RxThread; 642 if (params()->tx_thread) 643 regs.Config |= Config_TxThread; 644 if (params()->rss) 645 regs.Config |= Config_RSS; 646 if (params()->zero_copy) 647 regs.Config |= Config_ZeroCopy; 648 if (params()->delay_copy) 649 regs.Config |= Config_DelayCopy; 650 if (params()->virtual_addr) 651 regs.Config |= Config_Vaddr; 652 653 if (params()->delay_copy && params()->zero_copy) 654 panic("Can't delay copy and zero copy"); 655 656 regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; 657 regs.RxMaxCopy = params()->rx_max_copy; 658 regs.TxMaxCopy = params()->tx_max_copy; 659 regs.ZeroCopySize = params()->zero_copy_size; 660 regs.ZeroCopyMark = params()->zero_copy_threshold; 661 regs.VirtualCount = params()->virtual_count; 662 regs.RxMaxIntr = params()->rx_max_intr; 663 regs.RxFifoSize = params()->rx_fifo_size; 664 regs.TxFifoSize = params()->tx_fifo_size; 665 regs.RxFifoLow = params()->rx_fifo_low_mark; 666 regs.TxFifoLow = params()->tx_fifo_threshold; 667 regs.RxFifoHigh = params()->rx_fifo_threshold; 668 regs.TxFifoHigh = params()->tx_fifo_high_mark; 669 regs.HwAddr = params()->hardware_address; 670 671 if (regs.RxMaxCopy < regs.ZeroCopyMark) 672 panic("Must be able to copy at least as many bytes as the threshold"); 673 674 if (regs.ZeroCopySize >= regs.ZeroCopyMark) 675 panic("The number of bytes to copy must be less than the threshold"); 676 677 rxList.clear(); 678 rxBusy.clear(); 679 rxActive = -1; 680 txList.clear(); 681 rxBusyCount = 0; 682 rxDirtyCount = 0; 683 rxMappedCount = 0; 684 685 rxState = rxIdle; 686 txState = txIdle; 687 688 rxFifo.clear(); 689 rxFifoPtr = rxFifo.end(); 690 txFifo.clear(); 691 rxEmpty = false; 692 rxLow = true; 693 txFull = false; 694 695 int size = virtualRegs.size(); 696 virtualRegs.clear(); 697 virtualRegs.resize(size); 698 for (int i = 0; i < size; ++i) 699 virtualRegs[i].rxIndex = rxFifo.end(); 700} 701 702void 703Device::rxDmaDone() 704{ 705 assert(rxState == rxCopy); 706 rxState = rxCopyDone; 707 DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", 708 rxDmaAddr, rxDmaLen); 709 DDUMP(EthernetData, rxDmaData, rxDmaLen); 710 711 // If the transmit state machine has a pending DMA, let it go first 712 if (txState == txBeginCopy) 713 txKick(); 714 715 rxKick(); 716} 717 718void 719Device::rxKick() 720{ 721 VirtualReg *vnic = NULL; 722 723 DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", 724 RxStateStrings[rxState], rxFifo.size()); 725 726 if (rxKickTick > curTick()) { 727 DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", 728 rxKickTick); 729 return; 730 } 731 732 next: 733 rxFifo.check(); 734 if (rxState == rxIdle) 735 goto exit; 736 737 if (rxActive == -1) { 738 if (rxState != rxFifoBlock) 739 panic("no active vnic while in state %s", RxStateStrings[rxState]); 740 741 DPRINTF(EthernetSM, "processing rxState=%s\n", 742 RxStateStrings[rxState]); 743 } else { 744 vnic = &virtualRegs[rxActive]; 745 DPRINTF(EthernetSM, 746 "processing rxState=%s for vnic %d (rxunique %d)\n", 747 RxStateStrings[rxState], rxActive, vnic->rxUnique); 748 } 749 750 switch (rxState) { 751 case rxFifoBlock: 752 if (DTRACE(EthernetSM)) { 753 PacketFifo::iterator end = rxFifo.end(); 754 int size = virtualRegs.size(); 755 for (int i = 0; i < size; ++i) { 756 VirtualReg *vn = &virtualRegs[i]; 757 bool busy = Regs::get_RxDone_Busy(vn->RxDone); 758 if (vn->rxIndex != end) { 759#ifndef NDEBUG 760 bool dirty = vn->rxPacketOffset > 0; 761 const char *status; 762 763 if (busy && dirty) 764 status = "busy,dirty"; 765 else if (busy) 766 status = "busy"; 767 else if (dirty) 768 status = "dirty"; 769 else 770 status = "mapped"; 771 772 DPRINTF(EthernetSM, 773 "vnic %d %s (rxunique %d), packet %d, slack %d\n", 774 i, status, vn->rxUnique, 775 rxFifo.countPacketsBefore(vn->rxIndex), 776 vn->rxIndex->slack); 777#endif 778 } else if (busy) { 779 DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n", 780 i, vn->rxUnique); 781 } 782 } 783 } 784 785 if (!rxBusy.empty()) { 786 rxActive = rxBusy.front(); 787 rxBusy.pop_front(); 788 vnic = &virtualRegs[rxActive]; 789 790 if (vnic->rxIndex == rxFifo.end()) 791 panic("continuing vnic without packet\n"); 792 793 DPRINTF(EthernetSM, 794 "continue processing for vnic %d (rxunique %d)\n", 795 rxActive, vnic->rxUnique); 796 797 rxState = rxBeginCopy; 798 799 int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex); 800 totalVnicDistance += vnic_distance; 801 numVnicDistance += 1; 802 if (vnic_distance > _maxVnicDistance) { 803 maxVnicDistance = vnic_distance; 804 _maxVnicDistance = vnic_distance; 805 } 806 807 break; 808 } 809 810 if (rxFifoPtr == rxFifo.end()) { 811 DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 812 goto exit; 813 } 814 815 if (rxList.empty()) 816 panic("Not idle, but nothing to do!"); 817 818 assert(!rxFifo.empty()); 819 820 rxActive = rxList.front(); 821 rxList.pop_front(); 822 vnic = &virtualRegs[rxActive]; 823 824 DPRINTF(EthernetSM, 825 "processing new packet for vnic %d (rxunique %d)\n", 826 rxActive, vnic->rxUnique); 827 828 // Grab a new packet from the fifo. 829 vnic->rxIndex = rxFifoPtr++; 830 vnic->rxIndex->priv = rxActive; 831 vnic->rxPacketOffset = 0; 832 vnic->rxPacketBytes = vnic->rxIndex->packet->length; 833 assert(vnic->rxPacketBytes); 834 rxMappedCount++; 835 836 vnic->rxDoneData = 0; 837 /* scope for variables */ { 838 IpPtr ip(vnic->rxIndex->packet); 839 if (ip) { 840 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 841 vnic->rxDoneData |= Regs::RxDone_IpPacket; 842 rxIpChecksums++; 843 if (cksum(ip) != 0) { 844 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 845 vnic->rxDoneData |= Regs::RxDone_IpError; 846 } 847 TcpPtr tcp(ip); 848 UdpPtr udp(ip); 849 if (tcp) { 850 DPRINTF(Ethernet, 851 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 852 tcp->sport(), tcp->dport(), tcp->seq(), 853 tcp->ack()); 854 vnic->rxDoneData |= Regs::RxDone_TcpPacket; 855 rxTcpChecksums++; 856 if (cksum(tcp) != 0) { 857 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 858 vnic->rxDoneData |= Regs::RxDone_TcpError; 859 } 860 } else if (udp) { 861 vnic->rxDoneData |= Regs::RxDone_UdpPacket; 862 rxUdpChecksums++; 863 if (cksum(udp) != 0) { 864 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 865 vnic->rxDoneData |= Regs::RxDone_UdpError; 866 } 867 } 868 } 869 } 870 rxState = rxBeginCopy; 871 break; 872 873 case rxBeginCopy: 874 if (dmaPending() || drainState() != DrainState::Running) 875 goto exit; 876 877 rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData)); 878 rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData), 879 vnic->rxPacketBytes); 880 881 /* 882 * if we're doing zero/delay copy and we're below the fifo 883 * threshold, see if we should try to do the zero/defer copy 884 */ 885 if ((Regs::get_Config_ZeroCopy(regs.Config) || 886 Regs::get_Config_DelayCopy(regs.Config)) && 887 !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) { 888 if (rxDmaLen > regs.ZeroCopyMark) 889 rxDmaLen = regs.ZeroCopySize; 890 } 891 rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset; 892 rxState = rxCopy; 893 if (rxDmaAddr == 1LL) { 894 rxState = rxCopyDone; 895 break; 896 } 897 898 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); 899 break; 900 901 case rxCopy: 902 DPRINTF(EthernetSM, "receive machine still copying\n"); 903 goto exit; 904 905 case rxCopyDone: 906 vnic->RxDone = vnic->rxDoneData; 907 vnic->RxDone |= Regs::RxDone_Complete; 908 rxBusyCount--; 909 910 if (vnic->rxPacketBytes == rxDmaLen) { 911 if (vnic->rxPacketOffset) 912 rxDirtyCount--; 913 914 // Packet is complete. Indicate how many bytes were copied 915 vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); 916 917 DPRINTF(EthernetSM, 918 "rxKick: packet complete on vnic %d (rxunique %d)\n", 919 rxActive, vnic->rxUnique); 920 rxFifo.remove(vnic->rxIndex); 921 vnic->rxIndex = rxFifo.end(); 922 rxMappedCount--; 923 } else { 924 if (!vnic->rxPacketOffset) 925 rxDirtyCount++; 926 927 vnic->rxPacketBytes -= rxDmaLen; 928 vnic->rxPacketOffset += rxDmaLen; 929 vnic->RxDone |= Regs::RxDone_More; 930 vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, 931 vnic->rxPacketBytes); 932 DPRINTF(EthernetSM, 933 "rxKick: packet not complete on vnic %d (rxunique %d): " 934 "%d bytes left\n", 935 rxActive, vnic->rxUnique, vnic->rxPacketBytes); 936 } 937 938 rxActive = -1; 939 rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; 940 941 if (rxFifo.empty()) { 942 devIntrPost(Regs::Intr_RxEmpty); 943 rxEmpty = true; 944 } 945 946 if (rxFifo.size() < regs.RxFifoLow) 947 rxLow = true; 948 949 if (rxFifo.size() > regs.RxFifoHigh) 950 rxLow = false; 951 952 devIntrPost(Regs::Intr_RxDMA); 953 break; 954 955 default: 956 panic("Invalid rxState!"); 957 } 958 959 DPRINTF(EthernetSM, "entering next rxState=%s\n", 960 RxStateStrings[rxState]); 961 962 goto next; 963 964 exit: 965 /** 966 * @todo do we want to schedule a future kick? 967 */ 968 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 969 RxStateStrings[rxState]); 970} 971 972void 973Device::txDmaDone() 974{ 975 assert(txState == txCopy); 976 txState = txCopyDone; 977 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 978 txDmaAddr, txDmaLen); 979 DDUMP(EthernetData, txDmaData, txDmaLen); 980 981 // If the receive state machine has a pending DMA, let it go first 982 if (rxState == rxBeginCopy) 983 rxKick(); 984 985 txKick(); 986} 987 988void 989Device::transmit() 990{ 991 if (txFifo.empty()) { 992 DPRINTF(Ethernet, "nothing to transmit\n"); 993 return; 994 } 995 996 uint32_t interrupts; 997 EthPacketPtr packet = txFifo.front(); 998 if (!interface->sendPacket(packet)) { 999 DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 1000 txFifo.avail()); 1001 return; 1002 } 1003 1004 txFifo.pop(); 1005#if TRACING_ON 1006 if (DTRACE(Ethernet)) { 1007 IpPtr ip(packet); 1008 if (ip) { 1009 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1010 TcpPtr tcp(ip); 1011 if (tcp) { 1012 DPRINTF(Ethernet, 1013 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1014 tcp->sport(), tcp->dport(), tcp->seq(), 1015 tcp->ack()); 1016 } 1017 } 1018 } 1019#endif 1020 1021 DDUMP(EthernetData, packet->data, packet->length); 1022 txBytes += packet->length; 1023 txPackets++; 1024 1025 DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 1026 txFifo.avail()); 1027 1028 interrupts = Regs::Intr_TxPacket; 1029 if (txFifo.size() < regs.TxFifoLow) 1030 interrupts |= Regs::Intr_TxLow; 1031 devIntrPost(interrupts); 1032} 1033 1034void 1035Device::txKick() 1036{ 1037 VirtualReg *vnic; 1038 DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", 1039 TxStateStrings[txState], txFifo.size()); 1040 1041 if (txKickTick > curTick()) { 1042 DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", 1043 txKickTick); 1044 return; 1045 } 1046 1047 next: 1048 if (txState == txIdle) 1049 goto exit; 1050 1051 assert(!txList.empty()); 1052 vnic = &virtualRegs[txList.front()]; 1053 1054 switch (txState) { 1055 case txFifoBlock: 1056 assert(Regs::get_TxDone_Busy(vnic->TxDone)); 1057 if (!txPacket) { 1058 // Grab a new packet from the fifo. 1059 txPacket = make_shared<EthPacketData>(16384); 1060 txPacketOffset = 0; 1061 } 1062 1063 if (txFifo.avail() - txPacket->length < 1064 Regs::get_TxData_Len(vnic->TxData)) { 1065 DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 1066 goto exit; 1067 } 1068 1069 txState = txBeginCopy; 1070 break; 1071 1072 case txBeginCopy: 1073 if (dmaPending() || drainState() != DrainState::Running) 1074 goto exit; 1075 1076 txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData)); 1077 txDmaLen = Regs::get_TxData_Len(vnic->TxData); 1078 txDmaData = txPacket->data + txPacketOffset; 1079 txState = txCopy; 1080 1081 dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); 1082 break; 1083 1084 case txCopy: 1085 DPRINTF(EthernetSM, "transmit machine still copying\n"); 1086 goto exit; 1087 1088 case txCopyDone: 1089 vnic->TxDone = txDmaLen | Regs::TxDone_Complete; 1090 txPacket->simLength += txDmaLen; 1091 txPacket->length += txDmaLen; 1092 if ((vnic->TxData & Regs::TxData_More)) { 1093 txPacketOffset += txDmaLen; 1094 txState = txIdle; 1095 devIntrPost(Regs::Intr_TxDMA); 1096 break; 1097 } 1098 1099 assert(txPacket->length <= txFifo.avail()); 1100 if ((vnic->TxData & Regs::TxData_Checksum)) { 1101 IpPtr ip(txPacket); 1102 if (ip) { 1103 TcpPtr tcp(ip); 1104 if (tcp) { 1105 tcp->sum(0); 1106 tcp->sum(cksum(tcp)); 1107 txTcpChecksums++; 1108 } 1109 1110 UdpPtr udp(ip); 1111 if (udp) { 1112 udp->sum(0); 1113 udp->sum(cksum(udp)); 1114 txUdpChecksums++; 1115 } 1116 1117 ip->sum(0); 1118 ip->sum(cksum(ip)); 1119 txIpChecksums++; 1120 } 1121 } 1122 1123 txFifo.push(txPacket); 1124 if (txFifo.avail() < regs.TxMaxCopy) { 1125 devIntrPost(Regs::Intr_TxFull); 1126 txFull = true; 1127 } 1128 txPacket = 0; 1129 transmit(); 1130 txList.pop_front(); 1131 txState = txList.empty() ? txIdle : txFifoBlock; 1132 devIntrPost(Regs::Intr_TxDMA); 1133 break; 1134 1135 default: 1136 panic("Invalid txState!"); 1137 } 1138 1139 DPRINTF(EthernetSM, "entering next txState=%s\n", 1140 TxStateStrings[txState]); 1141 1142 goto next; 1143 1144 exit: 1145 /** 1146 * @todo do we want to schedule a future kick? 1147 */ 1148 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1149 TxStateStrings[txState]); 1150} 1151 1152void 1153Device::transferDone() 1154{ 1155 if (txFifo.empty()) { 1156 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1157 return; 1158 } 1159 1160 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 1161 1162 reschedule(txEvent, clockEdge(Cycles(1)), true); 1163} 1164 1165bool 1166Device::rxFilter(const EthPacketPtr &packet) 1167{ 1168 if (!Regs::get_Config_Filter(regs.Config)) 1169 return false; 1170 1171 panic("receive filter not implemented\n"); 1172 bool drop = true; 1173 return drop; 1174} 1175 1176bool 1177Device::recvPacket(EthPacketPtr packet) 1178{ 1179 rxBytes += packet->length; 1180 rxPackets++; 1181 1182 DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 1183 rxFifo.avail()); 1184 1185 if (!rxEnable) { 1186 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1187 return true; 1188 } 1189 1190 if (rxFilter(packet)) { 1191 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1192 return true; 1193 } 1194 1195 if (rxFifo.size() >= regs.RxFifoHigh) 1196 devIntrPost(Regs::Intr_RxHigh); 1197 1198 if (!rxFifo.push(packet)) { 1199 DPRINTF(Ethernet, 1200 "packet will not fit in receive buffer...packet dropped\n"); 1201 return false; 1202 } 1203 1204 // If we were at the last element, back up one ot go to the new 1205 // last element of the list. 1206 if (rxFifoPtr == rxFifo.end()) 1207 --rxFifoPtr; 1208 1209 devIntrPost(Regs::Intr_RxPacket); 1210 rxKick(); 1211 return true; 1212} 1213 1214void 1215Device::drainResume() 1216{ 1217 Drainable::drainResume(); 1218 1219 // During drain we could have left the state machines in a waiting state and 1220 // they wouldn't get out until some other event occured to kick them. 1221 // This way they'll get out immediately 1222 txKick(); 1223 rxKick(); 1224} 1225 1226//===================================================================== 1227// 1228// 1229void 1230Base::serialize(CheckpointOut &cp) const 1231{ 1232 // Serialize the PciDevice base class 1233 PciDevice::serialize(cp); 1234 1235 SERIALIZE_SCALAR(rxEnable); 1236 SERIALIZE_SCALAR(txEnable); 1237 SERIALIZE_SCALAR(cpuIntrEnable); 1238 1239 /* 1240 * Keep track of pending interrupt status. 1241 */ 1242 SERIALIZE_SCALAR(intrTick); 1243 SERIALIZE_SCALAR(cpuPendingIntr); 1244 Tick intrEventTick = 0; 1245 if (intrEvent) 1246 intrEventTick = intrEvent->when(); 1247 SERIALIZE_SCALAR(intrEventTick); 1248} 1249 1250void 1251Base::unserialize(CheckpointIn &cp) 1252{ 1253 // Unserialize the PciDevice base class 1254 PciDevice::unserialize(cp); 1255 1256 UNSERIALIZE_SCALAR(rxEnable); 1257 UNSERIALIZE_SCALAR(txEnable); 1258 UNSERIALIZE_SCALAR(cpuIntrEnable); 1259 1260 /* 1261 * Keep track of pending interrupt status. 1262 */ 1263 UNSERIALIZE_SCALAR(intrTick); 1264 UNSERIALIZE_SCALAR(cpuPendingIntr); 1265 Tick intrEventTick; 1266 UNSERIALIZE_SCALAR(intrEventTick); 1267 if (intrEventTick) { 1268 intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); }, 1269 name(), true); 1270 schedule(intrEvent, intrEventTick); 1271 } 1272} 1273 1274void 1275Device::serialize(CheckpointOut &cp) const 1276{ 1277 int count; 1278 1279 // Serialize the PciDevice base class 1280 Base::serialize(cp); 1281 1282 if (rxState == rxCopy) 1283 panic("can't serialize with an in flight dma request rxState=%s", 1284 RxStateStrings[rxState]); 1285 1286 if (txState == txCopy) 1287 panic("can't serialize with an in flight dma request txState=%s", 1288 TxStateStrings[txState]); 1289 1290 /* 1291 * Serialize the device registers that could be modified by the OS. 1292 */ 1293 SERIALIZE_SCALAR(regs.Config); 1294 SERIALIZE_SCALAR(regs.IntrStatus); 1295 SERIALIZE_SCALAR(regs.IntrMask); 1296 SERIALIZE_SCALAR(regs.RxData); 1297 SERIALIZE_SCALAR(regs.TxData); 1298 1299 /* 1300 * Serialize the virtual nic state 1301 */ 1302 int virtualRegsSize = virtualRegs.size(); 1303 SERIALIZE_SCALAR(virtualRegsSize); 1304 for (int i = 0; i < virtualRegsSize; ++i) { 1305 const VirtualReg *vnic = &virtualRegs[i]; 1306 1307 std::string reg = csprintf("vnic%d", i); 1308 paramOut(cp, reg + ".RxData", vnic->RxData); 1309 paramOut(cp, reg + ".RxDone", vnic->RxDone); 1310 paramOut(cp, reg + ".TxData", vnic->TxData); 1311 paramOut(cp, reg + ".TxDone", vnic->TxDone); 1312 1313 bool rxPacketExists = vnic->rxIndex != rxFifo.end(); 1314 paramOut(cp, reg + ".rxPacketExists", rxPacketExists); 1315 if (rxPacketExists) { 1316 int rxPacket = 0; 1317 auto i = rxFifo.begin(); 1318 while (i != vnic->rxIndex) { 1319 assert(i != rxFifo.end()); 1320 ++i; 1321 ++rxPacket; 1322 } 1323 1324 paramOut(cp, reg + ".rxPacket", rxPacket); 1325 paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset); 1326 paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1327 } 1328 paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData); 1329 } 1330 1331 int rxFifoPtr = -1; 1332 if (this->rxFifoPtr != rxFifo.end()) 1333 rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); 1334 SERIALIZE_SCALAR(rxFifoPtr); 1335 1336 SERIALIZE_SCALAR(rxActive); 1337 SERIALIZE_SCALAR(rxBusyCount); 1338 SERIALIZE_SCALAR(rxDirtyCount); 1339 SERIALIZE_SCALAR(rxMappedCount); 1340 1341 VirtualList::const_iterator i, end; 1342 for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) 1343 paramOut(cp, csprintf("rxList%d", count++), *i); 1344 int rxListSize = count; 1345 SERIALIZE_SCALAR(rxListSize); 1346 1347 for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) 1348 paramOut(cp, csprintf("rxBusy%d", count++), *i); 1349 int rxBusySize = count; 1350 SERIALIZE_SCALAR(rxBusySize); 1351 1352 for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) 1353 paramOut(cp, csprintf("txList%d", count++), *i); 1354 int txListSize = count; 1355 SERIALIZE_SCALAR(txListSize); 1356 1357 /* 1358 * Serialize rx state machine 1359 */ 1360 int rxState = this->rxState; 1361 SERIALIZE_SCALAR(rxState); 1362 SERIALIZE_SCALAR(rxEmpty); 1363 SERIALIZE_SCALAR(rxLow); 1364 rxFifo.serialize("rxFifo", cp); 1365 1366 /* 1367 * Serialize tx state machine 1368 */ 1369 int txState = this->txState; 1370 SERIALIZE_SCALAR(txState); 1371 SERIALIZE_SCALAR(txFull); 1372 txFifo.serialize("txFifo", cp); 1373 bool txPacketExists = txPacket != nullptr; 1374 SERIALIZE_SCALAR(txPacketExists); 1375 if (txPacketExists) { 1376 txPacket->serialize("txPacket", cp); 1377 SERIALIZE_SCALAR(txPacketOffset); 1378 SERIALIZE_SCALAR(txPacketBytes); 1379 } 1380 1381 /* 1382 * If there's a pending transmit, store the time so we can 1383 * reschedule it later 1384 */ 1385 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 1386 SERIALIZE_SCALAR(transmitTick); 1387} 1388 1389void 1390Device::unserialize(CheckpointIn &cp) 1391{ 1392 // Unserialize the PciDevice base class 1393 Base::unserialize(cp); 1394 1395 /* 1396 * Unserialize the device registers that may have been written by the OS. 1397 */ 1398 UNSERIALIZE_SCALAR(regs.Config); 1399 UNSERIALIZE_SCALAR(regs.IntrStatus); 1400 UNSERIALIZE_SCALAR(regs.IntrMask); 1401 UNSERIALIZE_SCALAR(regs.RxData); 1402 UNSERIALIZE_SCALAR(regs.TxData); 1403 1404 UNSERIALIZE_SCALAR(rxActive); 1405 UNSERIALIZE_SCALAR(rxBusyCount); 1406 UNSERIALIZE_SCALAR(rxDirtyCount); 1407 UNSERIALIZE_SCALAR(rxMappedCount); 1408 1409 int rxListSize; 1410 UNSERIALIZE_SCALAR(rxListSize); 1411 rxList.clear(); 1412 for (int i = 0; i < rxListSize; ++i) { 1413 int value; 1414 paramIn(cp, csprintf("rxList%d", i), value); 1415 rxList.push_back(value); 1416 } 1417 1418 int rxBusySize; 1419 UNSERIALIZE_SCALAR(rxBusySize); 1420 rxBusy.clear(); 1421 for (int i = 0; i < rxBusySize; ++i) { 1422 int value; 1423 paramIn(cp, csprintf("rxBusy%d", i), value); 1424 rxBusy.push_back(value); 1425 } 1426 1427 int txListSize; 1428 UNSERIALIZE_SCALAR(txListSize); 1429 txList.clear(); 1430 for (int i = 0; i < txListSize; ++i) { 1431 int value; 1432 paramIn(cp, csprintf("txList%d", i), value); 1433 txList.push_back(value); 1434 } 1435 1436 /* 1437 * Unserialize rx state machine 1438 */ 1439 int rxState; 1440 UNSERIALIZE_SCALAR(rxState); 1441 UNSERIALIZE_SCALAR(rxEmpty); 1442 UNSERIALIZE_SCALAR(rxLow); 1443 this->rxState = (RxState) rxState; 1444 rxFifo.unserialize("rxFifo", cp); 1445 1446 int rxFifoPtr; 1447 UNSERIALIZE_SCALAR(rxFifoPtr); 1448 if (rxFifoPtr >= 0) { 1449 this->rxFifoPtr = rxFifo.begin(); 1450 for (int i = 0; i < rxFifoPtr; ++i) 1451 ++this->rxFifoPtr; 1452 } else { 1453 this->rxFifoPtr = rxFifo.end(); 1454 } 1455 1456 /* 1457 * Unserialize tx state machine 1458 */ 1459 int txState; 1460 UNSERIALIZE_SCALAR(txState); 1461 UNSERIALIZE_SCALAR(txFull); 1462 this->txState = (TxState) txState; 1463 txFifo.unserialize("txFifo", cp); 1464 bool txPacketExists; 1465 UNSERIALIZE_SCALAR(txPacketExists); 1466 txPacket = 0; 1467 if (txPacketExists) { 1468 txPacket = make_shared<EthPacketData>(16384); 1469 txPacket->unserialize("txPacket", cp); 1470 UNSERIALIZE_SCALAR(txPacketOffset); 1471 UNSERIALIZE_SCALAR(txPacketBytes); 1472 } 1473 1474 /* 1475 * unserialize the virtual nic registers/state 1476 * 1477 * this must be done after the unserialization of the rxFifo 1478 * because the packet iterators depend on the fifo being populated 1479 */ 1480 int virtualRegsSize; 1481 UNSERIALIZE_SCALAR(virtualRegsSize); 1482 virtualRegs.clear(); 1483 virtualRegs.resize(virtualRegsSize); 1484 for (int i = 0; i < virtualRegsSize; ++i) { 1485 VirtualReg *vnic = &virtualRegs[i]; 1486 std::string reg = csprintf("vnic%d", i); 1487 1488 paramIn(cp, reg + ".RxData", vnic->RxData); 1489 paramIn(cp, reg + ".RxDone", vnic->RxDone); 1490 paramIn(cp, reg + ".TxData", vnic->TxData); 1491 paramIn(cp, reg + ".TxDone", vnic->TxDone); 1492 1493 vnic->rxUnique = rxUnique++; 1494 vnic->txUnique = txUnique++; 1495 1496 bool rxPacketExists; 1497 paramIn(cp, reg + ".rxPacketExists", rxPacketExists); 1498 if (rxPacketExists) { 1499 int rxPacket; 1500 paramIn(cp, reg + ".rxPacket", rxPacket); 1501 vnic->rxIndex = rxFifo.begin(); 1502 while (rxPacket--) 1503 ++vnic->rxIndex; 1504 1505 paramIn(cp, reg + ".rxPacketOffset", 1506 vnic->rxPacketOffset); 1507 paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1508 } else { 1509 vnic->rxIndex = rxFifo.end(); 1510 } 1511 paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData); 1512 } 1513 1514 /* 1515 * If there's a pending transmit, reschedule it now 1516 */ 1517 Tick transmitTick; 1518 UNSERIALIZE_SCALAR(transmitTick); 1519 if (transmitTick) 1520 schedule(txEvent, curTick() + transmitTick); 1521 1522 pioPort.sendRangeChange(); 1523 1524} 1525 1526} // namespace Sinic 1527 1528Sinic::Device * 1529SinicParams::create() 1530{ 1531 return new Sinic::Device(this); 1532} 1533