sinic.cc revision 11701:5e7599457b97
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), rxDmaEvent(this), txDmaEvent(this), 95 dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), 96 dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) 97{ 98 interface = new Interface(name() + ".int0", this); 99 reset(); 100 101} 102 103Device::~Device() 104{} 105 106void 107Device::regStats() 108{ 109 Base::regStats(); 110 111 _maxVnicDistance = 0; 112 113 maxVnicDistance 114 .name(name() + ".maxVnicDistance") 115 .desc("maximum vnic distance") 116 ; 117 118 totalVnicDistance 119 .name(name() + ".totalVnicDistance") 120 .desc("total vnic distance") 121 ; 122 numVnicDistance 123 .name(name() + ".numVnicDistance") 124 .desc("number of vnic distance measurements") 125 ; 126 127 avgVnicDistance 128 .name(name() + ".avgVnicDistance") 129 .desc("average vnic distance") 130 ; 131 132 avgVnicDistance = totalVnicDistance / numVnicDistance; 133} 134 135void 136Device::resetStats() 137{ 138 Base::resetStats(); 139 140 _maxVnicDistance = 0; 141} 142 143EtherInt* 144Device::getEthPort(const std::string &if_name, int idx) 145{ 146 if (if_name == "interface") { 147 if (interface->getPeer()) 148 panic("interface already connected to\n"); 149 150 return interface; 151 } 152 return NULL; 153} 154 155 156void 157Device::prepareIO(ContextID cpu, int index) 158{ 159 int size = virtualRegs.size(); 160 if (index > size) 161 panic("Trying to access a vnic that doesn't exist %d > %d\n", 162 index, size); 163} 164 165//add stats for head of line blocking 166//add stats for average fifo length 167//add stats for average number of vnics busy 168 169void 170Device::prepareRead(ContextID cpu, int index) 171{ 172 using namespace Regs; 173 prepareIO(cpu, index); 174 175 VirtualReg &vnic = virtualRegs[index]; 176 177 // update rx registers 178 uint64_t rxdone = vnic.RxDone; 179 rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); 180 rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); 181 rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh); 182 rxdone = set_RxDone_NotHigh(rxdone, rxLow); 183 regs.RxData = vnic.RxData; 184 regs.RxDone = rxdone; 185 regs.RxWait = rxdone; 186 187 // update tx regsiters 188 uint64_t txdone = vnic.TxDone; 189 txdone = set_TxDone_Packets(txdone, txFifo.packets()); 190 txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); 191 txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow); 192 regs.TxData = vnic.TxData; 193 regs.TxDone = txdone; 194 regs.TxWait = txdone; 195 196 int head = 0xffff; 197 198 if (!rxFifo.empty()) { 199 int vnic = rxFifo.begin()->priv; 200 if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0) 201 head = vnic; 202 } 203 204 regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head); 205 regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount); 206 regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount); 207 regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount); 208} 209 210void 211Device::prepareWrite(ContextID cpu, int index) 212{ 213 prepareIO(cpu, index); 214} 215 216/** 217 * I/O read of device register 218 */ 219Tick 220Device::read(PacketPtr pkt) 221{ 222 assert(config.command & PCI_CMD_MSE); 223 assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 224 225 ContextID cpu = pkt->req->contextId(); 226 Addr daddr = pkt->getAddr() - BARAddrs[0]; 227 Addr index = daddr >> Regs::VirtualShift; 228 Addr raddr = daddr & Regs::VirtualMask; 229 230 if (!regValid(raddr)) 231 panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d", 232 cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 233 234 const Regs::Info &info = regInfo(raddr); 235 if (!info.read) 236 panic("read %s (write only): " 237 "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 238 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 239 240 panic("read %s (invalid size): " 241 "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 242 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 243 244 prepareRead(cpu, index); 245 246 uint64_t value M5_VAR_USED = 0; 247 if (pkt->getSize() == 4) { 248 uint32_t reg = regData32(raddr); 249 pkt->set(reg); 250 value = reg; 251 } 252 253 if (pkt->getSize() == 8) { 254 uint64_t reg = regData64(raddr); 255 pkt->set(reg); 256 value = reg; 257 } 258 259 DPRINTF(EthernetPIO, 260 "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n", 261 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value); 262 263 // reading the interrupt status register has the side effect of 264 // clearing it 265 if (raddr == Regs::IntrStatus) 266 devIntrClear(); 267 268 return pioDelay; 269} 270 271/** 272 * IPR read of device register 273 274 Fault 275Device::iprRead(Addr daddr, ContextID cpu, uint64_t &result) 276{ 277 if (!regValid(daddr)) 278 panic("invalid address: da=%#x", daddr); 279 280 const Regs::Info &info = regInfo(daddr); 281 if (!info.read) 282 panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); 283 284 DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", 285 info.name, cpu, daddr); 286 287 prepareRead(cpu, 0); 288 289 if (info.size == 4) 290 result = regData32(daddr); 291 292 if (info.size == 8) 293 result = regData64(daddr); 294 295 DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", 296 info.name, cpu, result); 297 298 return NoFault; 299} 300*/ 301/** 302 * I/O write of device register 303 */ 304Tick 305Device::write(PacketPtr pkt) 306{ 307 assert(config.command & PCI_CMD_MSE); 308 assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 309 310 ContextID cpu = pkt->req->contextId(); 311 Addr daddr = pkt->getAddr() - BARAddrs[0]; 312 Addr index = daddr >> Regs::VirtualShift; 313 Addr raddr = daddr & Regs::VirtualMask; 314 315 if (!regValid(raddr)) 316 panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", 317 cpu, daddr, pkt->getAddr(), pkt->getSize()); 318 319 const Regs::Info &info = regInfo(raddr); 320 if (!info.write) 321 panic("write %s (read only): " 322 "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 323 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 324 325 if (pkt->getSize() != info.size) 326 panic("write %s (invalid size): " 327 "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 328 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 329 330 VirtualReg &vnic = virtualRegs[index]; 331 332 DPRINTF(EthernetPIO, 333 "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", 334 info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() : 335 pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize()); 336 337 prepareWrite(cpu, index); 338 339 switch (raddr) { 340 case Regs::Config: 341 changeConfig(pkt->get<uint32_t>()); 342 break; 343 344 case Regs::Command: 345 command(pkt->get<uint32_t>()); 346 break; 347 348 case Regs::IntrStatus: 349 devIntrClear(regs.IntrStatus & pkt->get<uint32_t>()); 350 break; 351 352 case Regs::IntrMask: 353 devIntrChangeMask(pkt->get<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->get<uint64_t>(); 364 rxBusyCount++; 365 366 if (Regs::get_RxData_Vaddr(pkt->get<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->get<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 intrEvent = new IntrEvent(this, true); 539 schedule(intrEvent, intrTick); 540} 541 542void 543Base::cpuInterrupt() 544{ 545 assert(intrTick == curTick()); 546 547 // Whether or not there's a pending interrupt, we don't care about 548 // it anymore 549 intrEvent = 0; 550 intrTick = 0; 551 552 // Don't send an interrupt if there's already one 553 if (cpuPendingIntr) { 554 DPRINTF(EthernetIntr, 555 "would send an interrupt now, but there's already pending\n"); 556 } else { 557 // Send interrupt 558 cpuPendingIntr = true; 559 560 DPRINTF(EthernetIntr, "posting interrupt\n"); 561 intrPost(); 562 } 563} 564 565void 566Base::cpuIntrClear() 567{ 568 if (!cpuPendingIntr) 569 return; 570 571 if (intrEvent) { 572 intrEvent->squash(); 573 intrEvent = 0; 574 } 575 576 intrTick = 0; 577 578 cpuPendingIntr = false; 579 580 DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 581 intrClear(); 582} 583 584bool 585Base::cpuIntrPending() const 586{ return cpuPendingIntr; } 587 588void 589Device::changeConfig(uint32_t newconf) 590{ 591 uint32_t changed = regs.Config ^ newconf; 592 if (!changed) 593 return; 594 595 regs.Config = newconf; 596 597 if ((changed & Regs::Config_IntEn)) { 598 cpuIntrEnable = regs.Config & Regs::Config_IntEn; 599 if (cpuIntrEnable) { 600 if (regs.IntrStatus & regs.IntrMask) 601 cpuIntrPost(curTick()); 602 } else { 603 cpuIntrClear(); 604 } 605 } 606 607 if ((changed & Regs::Config_TxEn)) { 608 txEnable = regs.Config & Regs::Config_TxEn; 609 if (txEnable) 610 txKick(); 611 } 612 613 if ((changed & Regs::Config_RxEn)) { 614 rxEnable = regs.Config & Regs::Config_RxEn; 615 if (rxEnable) 616 rxKick(); 617 } 618} 619 620void 621Device::command(uint32_t command) 622{ 623 if (command & Regs::Command_Intr) 624 devIntrPost(Regs::Intr_Soft); 625 626 if (command & Regs::Command_Reset) 627 reset(); 628} 629 630void 631Device::reset() 632{ 633 using namespace Regs; 634 635 memset(®s, 0, sizeof(regs)); 636 637 regs.Config = 0; 638 if (params()->rx_thread) 639 regs.Config |= Config_RxThread; 640 if (params()->tx_thread) 641 regs.Config |= Config_TxThread; 642 if (params()->rss) 643 regs.Config |= Config_RSS; 644 if (params()->zero_copy) 645 regs.Config |= Config_ZeroCopy; 646 if (params()->delay_copy) 647 regs.Config |= Config_DelayCopy; 648 if (params()->virtual_addr) 649 regs.Config |= Config_Vaddr; 650 651 if (params()->delay_copy && params()->zero_copy) 652 panic("Can't delay copy and zero copy"); 653 654 regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; 655 regs.RxMaxCopy = params()->rx_max_copy; 656 regs.TxMaxCopy = params()->tx_max_copy; 657 regs.ZeroCopySize = params()->zero_copy_size; 658 regs.ZeroCopyMark = params()->zero_copy_threshold; 659 regs.VirtualCount = params()->virtual_count; 660 regs.RxMaxIntr = params()->rx_max_intr; 661 regs.RxFifoSize = params()->rx_fifo_size; 662 regs.TxFifoSize = params()->tx_fifo_size; 663 regs.RxFifoLow = params()->rx_fifo_low_mark; 664 regs.TxFifoLow = params()->tx_fifo_threshold; 665 regs.RxFifoHigh = params()->rx_fifo_threshold; 666 regs.TxFifoHigh = params()->tx_fifo_high_mark; 667 regs.HwAddr = params()->hardware_address; 668 669 if (regs.RxMaxCopy < regs.ZeroCopyMark) 670 panic("Must be able to copy at least as many bytes as the threshold"); 671 672 if (regs.ZeroCopySize >= regs.ZeroCopyMark) 673 panic("The number of bytes to copy must be less than the threshold"); 674 675 rxList.clear(); 676 rxBusy.clear(); 677 rxActive = -1; 678 txList.clear(); 679 rxBusyCount = 0; 680 rxDirtyCount = 0; 681 rxMappedCount = 0; 682 683 rxState = rxIdle; 684 txState = txIdle; 685 686 rxFifo.clear(); 687 rxFifoPtr = rxFifo.end(); 688 txFifo.clear(); 689 rxEmpty = false; 690 rxLow = true; 691 txFull = false; 692 693 int size = virtualRegs.size(); 694 virtualRegs.clear(); 695 virtualRegs.resize(size); 696 for (int i = 0; i < size; ++i) 697 virtualRegs[i].rxIndex = rxFifo.end(); 698} 699 700void 701Device::rxDmaDone() 702{ 703 assert(rxState == rxCopy); 704 rxState = rxCopyDone; 705 DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", 706 rxDmaAddr, rxDmaLen); 707 DDUMP(EthernetData, rxDmaData, rxDmaLen); 708 709 // If the transmit state machine has a pending DMA, let it go first 710 if (txState == txBeginCopy) 711 txKick(); 712 713 rxKick(); 714} 715 716void 717Device::rxKick() 718{ 719 VirtualReg *vnic = NULL; 720 721 DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", 722 RxStateStrings[rxState], rxFifo.size()); 723 724 if (rxKickTick > curTick()) { 725 DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", 726 rxKickTick); 727 return; 728 } 729 730 next: 731 rxFifo.check(); 732 if (rxState == rxIdle) 733 goto exit; 734 735 if (rxActive == -1) { 736 if (rxState != rxFifoBlock) 737 panic("no active vnic while in state %s", RxStateStrings[rxState]); 738 739 DPRINTF(EthernetSM, "processing rxState=%s\n", 740 RxStateStrings[rxState]); 741 } else { 742 vnic = &virtualRegs[rxActive]; 743 DPRINTF(EthernetSM, 744 "processing rxState=%s for vnic %d (rxunique %d)\n", 745 RxStateStrings[rxState], rxActive, vnic->rxUnique); 746 } 747 748 switch (rxState) { 749 case rxFifoBlock: 750 if (DTRACE(EthernetSM)) { 751 PacketFifo::iterator end = rxFifo.end(); 752 int size = virtualRegs.size(); 753 for (int i = 0; i < size; ++i) { 754 VirtualReg *vn = &virtualRegs[i]; 755 bool busy = Regs::get_RxDone_Busy(vn->RxDone); 756 if (vn->rxIndex != end) { 757#ifndef NDEBUG 758 bool dirty = vn->rxPacketOffset > 0; 759 const char *status; 760 761 if (busy && dirty) 762 status = "busy,dirty"; 763 else if (busy) 764 status = "busy"; 765 else if (dirty) 766 status = "dirty"; 767 else 768 status = "mapped"; 769 770 DPRINTF(EthernetSM, 771 "vnic %d %s (rxunique %d), packet %d, slack %d\n", 772 i, status, vn->rxUnique, 773 rxFifo.countPacketsBefore(vn->rxIndex), 774 vn->rxIndex->slack); 775#endif 776 } else if (busy) { 777 DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n", 778 i, vn->rxUnique); 779 } 780 } 781 } 782 783 if (!rxBusy.empty()) { 784 rxActive = rxBusy.front(); 785 rxBusy.pop_front(); 786 vnic = &virtualRegs[rxActive]; 787 788 if (vnic->rxIndex == rxFifo.end()) 789 panic("continuing vnic without packet\n"); 790 791 DPRINTF(EthernetSM, 792 "continue processing for vnic %d (rxunique %d)\n", 793 rxActive, vnic->rxUnique); 794 795 rxState = rxBeginCopy; 796 797 int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex); 798 totalVnicDistance += vnic_distance; 799 numVnicDistance += 1; 800 if (vnic_distance > _maxVnicDistance) { 801 maxVnicDistance = vnic_distance; 802 _maxVnicDistance = vnic_distance; 803 } 804 805 break; 806 } 807 808 if (rxFifoPtr == rxFifo.end()) { 809 DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 810 goto exit; 811 } 812 813 if (rxList.empty()) 814 panic("Not idle, but nothing to do!"); 815 816 assert(!rxFifo.empty()); 817 818 rxActive = rxList.front(); 819 rxList.pop_front(); 820 vnic = &virtualRegs[rxActive]; 821 822 DPRINTF(EthernetSM, 823 "processing new packet for vnic %d (rxunique %d)\n", 824 rxActive, vnic->rxUnique); 825 826 // Grab a new packet from the fifo. 827 vnic->rxIndex = rxFifoPtr++; 828 vnic->rxIndex->priv = rxActive; 829 vnic->rxPacketOffset = 0; 830 vnic->rxPacketBytes = vnic->rxIndex->packet->length; 831 assert(vnic->rxPacketBytes); 832 rxMappedCount++; 833 834 vnic->rxDoneData = 0; 835 /* scope for variables */ { 836 IpPtr ip(vnic->rxIndex->packet); 837 if (ip) { 838 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 839 vnic->rxDoneData |= Regs::RxDone_IpPacket; 840 rxIpChecksums++; 841 if (cksum(ip) != 0) { 842 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 843 vnic->rxDoneData |= Regs::RxDone_IpError; 844 } 845 TcpPtr tcp(ip); 846 UdpPtr udp(ip); 847 if (tcp) { 848 DPRINTF(Ethernet, 849 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 850 tcp->sport(), tcp->dport(), tcp->seq(), 851 tcp->ack()); 852 vnic->rxDoneData |= Regs::RxDone_TcpPacket; 853 rxTcpChecksums++; 854 if (cksum(tcp) != 0) { 855 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 856 vnic->rxDoneData |= Regs::RxDone_TcpError; 857 } 858 } else if (udp) { 859 vnic->rxDoneData |= Regs::RxDone_UdpPacket; 860 rxUdpChecksums++; 861 if (cksum(udp) != 0) { 862 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 863 vnic->rxDoneData |= Regs::RxDone_UdpError; 864 } 865 } 866 } 867 } 868 rxState = rxBeginCopy; 869 break; 870 871 case rxBeginCopy: 872 if (dmaPending() || drainState() != DrainState::Running) 873 goto exit; 874 875 rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData)); 876 rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData), 877 vnic->rxPacketBytes); 878 879 /* 880 * if we're doing zero/delay copy and we're below the fifo 881 * threshold, see if we should try to do the zero/defer copy 882 */ 883 if ((Regs::get_Config_ZeroCopy(regs.Config) || 884 Regs::get_Config_DelayCopy(regs.Config)) && 885 !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) { 886 if (rxDmaLen > regs.ZeroCopyMark) 887 rxDmaLen = regs.ZeroCopySize; 888 } 889 rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset; 890 rxState = rxCopy; 891 if (rxDmaAddr == 1LL) { 892 rxState = rxCopyDone; 893 break; 894 } 895 896 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); 897 break; 898 899 case rxCopy: 900 DPRINTF(EthernetSM, "receive machine still copying\n"); 901 goto exit; 902 903 case rxCopyDone: 904 vnic->RxDone = vnic->rxDoneData; 905 vnic->RxDone |= Regs::RxDone_Complete; 906 rxBusyCount--; 907 908 if (vnic->rxPacketBytes == rxDmaLen) { 909 if (vnic->rxPacketOffset) 910 rxDirtyCount--; 911 912 // Packet is complete. Indicate how many bytes were copied 913 vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); 914 915 DPRINTF(EthernetSM, 916 "rxKick: packet complete on vnic %d (rxunique %d)\n", 917 rxActive, vnic->rxUnique); 918 rxFifo.remove(vnic->rxIndex); 919 vnic->rxIndex = rxFifo.end(); 920 rxMappedCount--; 921 } else { 922 if (!vnic->rxPacketOffset) 923 rxDirtyCount++; 924 925 vnic->rxPacketBytes -= rxDmaLen; 926 vnic->rxPacketOffset += rxDmaLen; 927 vnic->RxDone |= Regs::RxDone_More; 928 vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, 929 vnic->rxPacketBytes); 930 DPRINTF(EthernetSM, 931 "rxKick: packet not complete on vnic %d (rxunique %d): " 932 "%d bytes left\n", 933 rxActive, vnic->rxUnique, vnic->rxPacketBytes); 934 } 935 936 rxActive = -1; 937 rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; 938 939 if (rxFifo.empty()) { 940 devIntrPost(Regs::Intr_RxEmpty); 941 rxEmpty = true; 942 } 943 944 if (rxFifo.size() < regs.RxFifoLow) 945 rxLow = true; 946 947 if (rxFifo.size() > regs.RxFifoHigh) 948 rxLow = false; 949 950 devIntrPost(Regs::Intr_RxDMA); 951 break; 952 953 default: 954 panic("Invalid rxState!"); 955 } 956 957 DPRINTF(EthernetSM, "entering next rxState=%s\n", 958 RxStateStrings[rxState]); 959 960 goto next; 961 962 exit: 963 /** 964 * @todo do we want to schedule a future kick? 965 */ 966 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 967 RxStateStrings[rxState]); 968} 969 970void 971Device::txDmaDone() 972{ 973 assert(txState == txCopy); 974 txState = txCopyDone; 975 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 976 txDmaAddr, txDmaLen); 977 DDUMP(EthernetData, txDmaData, txDmaLen); 978 979 // If the receive state machine has a pending DMA, let it go first 980 if (rxState == rxBeginCopy) 981 rxKick(); 982 983 txKick(); 984} 985 986void 987Device::transmit() 988{ 989 if (txFifo.empty()) { 990 DPRINTF(Ethernet, "nothing to transmit\n"); 991 return; 992 } 993 994 uint32_t interrupts; 995 EthPacketPtr packet = txFifo.front(); 996 if (!interface->sendPacket(packet)) { 997 DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 998 txFifo.avail()); 999 return; 1000 } 1001 1002 txFifo.pop(); 1003#if TRACING_ON 1004 if (DTRACE(Ethernet)) { 1005 IpPtr ip(packet); 1006 if (ip) { 1007 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1008 TcpPtr tcp(ip); 1009 if (tcp) { 1010 DPRINTF(Ethernet, 1011 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1012 tcp->sport(), tcp->dport(), tcp->seq(), 1013 tcp->ack()); 1014 } 1015 } 1016 } 1017#endif 1018 1019 DDUMP(EthernetData, packet->data, packet->length); 1020 txBytes += packet->length; 1021 txPackets++; 1022 1023 DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 1024 txFifo.avail()); 1025 1026 interrupts = Regs::Intr_TxPacket; 1027 if (txFifo.size() < regs.TxFifoLow) 1028 interrupts |= Regs::Intr_TxLow; 1029 devIntrPost(interrupts); 1030} 1031 1032void 1033Device::txKick() 1034{ 1035 VirtualReg *vnic; 1036 DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", 1037 TxStateStrings[txState], txFifo.size()); 1038 1039 if (txKickTick > curTick()) { 1040 DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", 1041 txKickTick); 1042 return; 1043 } 1044 1045 next: 1046 if (txState == txIdle) 1047 goto exit; 1048 1049 assert(!txList.empty()); 1050 vnic = &virtualRegs[txList.front()]; 1051 1052 switch (txState) { 1053 case txFifoBlock: 1054 assert(Regs::get_TxDone_Busy(vnic->TxDone)); 1055 if (!txPacket) { 1056 // Grab a new packet from the fifo. 1057 txPacket = make_shared<EthPacketData>(16384); 1058 txPacketOffset = 0; 1059 } 1060 1061 if (txFifo.avail() - txPacket->length < 1062 Regs::get_TxData_Len(vnic->TxData)) { 1063 DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 1064 goto exit; 1065 } 1066 1067 txState = txBeginCopy; 1068 break; 1069 1070 case txBeginCopy: 1071 if (dmaPending() || drainState() != DrainState::Running) 1072 goto exit; 1073 1074 txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData)); 1075 txDmaLen = Regs::get_TxData_Len(vnic->TxData); 1076 txDmaData = txPacket->data + txPacketOffset; 1077 txState = txCopy; 1078 1079 dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); 1080 break; 1081 1082 case txCopy: 1083 DPRINTF(EthernetSM, "transmit machine still copying\n"); 1084 goto exit; 1085 1086 case txCopyDone: 1087 vnic->TxDone = txDmaLen | Regs::TxDone_Complete; 1088 txPacket->simLength += txDmaLen; 1089 txPacket->length += txDmaLen; 1090 if ((vnic->TxData & Regs::TxData_More)) { 1091 txPacketOffset += txDmaLen; 1092 txState = txIdle; 1093 devIntrPost(Regs::Intr_TxDMA); 1094 break; 1095 } 1096 1097 assert(txPacket->length <= txFifo.avail()); 1098 if ((vnic->TxData & Regs::TxData_Checksum)) { 1099 IpPtr ip(txPacket); 1100 if (ip) { 1101 TcpPtr tcp(ip); 1102 if (tcp) { 1103 tcp->sum(0); 1104 tcp->sum(cksum(tcp)); 1105 txTcpChecksums++; 1106 } 1107 1108 UdpPtr udp(ip); 1109 if (udp) { 1110 udp->sum(0); 1111 udp->sum(cksum(udp)); 1112 txUdpChecksums++; 1113 } 1114 1115 ip->sum(0); 1116 ip->sum(cksum(ip)); 1117 txIpChecksums++; 1118 } 1119 } 1120 1121 txFifo.push(txPacket); 1122 if (txFifo.avail() < regs.TxMaxCopy) { 1123 devIntrPost(Regs::Intr_TxFull); 1124 txFull = true; 1125 } 1126 txPacket = 0; 1127 transmit(); 1128 txList.pop_front(); 1129 txState = txList.empty() ? txIdle : txFifoBlock; 1130 devIntrPost(Regs::Intr_TxDMA); 1131 break; 1132 1133 default: 1134 panic("Invalid txState!"); 1135 } 1136 1137 DPRINTF(EthernetSM, "entering next txState=%s\n", 1138 TxStateStrings[txState]); 1139 1140 goto next; 1141 1142 exit: 1143 /** 1144 * @todo do we want to schedule a future kick? 1145 */ 1146 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1147 TxStateStrings[txState]); 1148} 1149 1150void 1151Device::transferDone() 1152{ 1153 if (txFifo.empty()) { 1154 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1155 return; 1156 } 1157 1158 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 1159 1160 reschedule(txEvent, clockEdge(Cycles(1)), true); 1161} 1162 1163bool 1164Device::rxFilter(const EthPacketPtr &packet) 1165{ 1166 if (!Regs::get_Config_Filter(regs.Config)) 1167 return false; 1168 1169 panic("receive filter not implemented\n"); 1170 bool drop = true; 1171 1172#if 0 1173 string type; 1174 1175 EthHdr *eth = packet->eth(); 1176 if (eth->unicast()) { 1177 // If we're accepting all unicast addresses 1178 if (acceptUnicast) 1179 drop = false; 1180 1181 // If we make a perfect match 1182 if (acceptPerfect && params->eaddr == eth.dst()) 1183 drop = false; 1184 1185 if (acceptArp && eth->type() == ETH_TYPE_ARP) 1186 drop = false; 1187 1188 } else if (eth->broadcast()) { 1189 // if we're accepting broadcasts 1190 if (acceptBroadcast) 1191 drop = false; 1192 1193 } else if (eth->multicast()) { 1194 // if we're accepting all multicasts 1195 if (acceptMulticast) 1196 drop = false; 1197 1198 } 1199 1200 if (drop) { 1201 DPRINTF(Ethernet, "rxFilter drop\n"); 1202 DDUMP(EthernetData, packet->data, packet->length); 1203 } 1204#endif 1205 return drop; 1206} 1207 1208bool 1209Device::recvPacket(EthPacketPtr packet) 1210{ 1211 rxBytes += packet->length; 1212 rxPackets++; 1213 1214 DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 1215 rxFifo.avail()); 1216 1217 if (!rxEnable) { 1218 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1219 return true; 1220 } 1221 1222 if (rxFilter(packet)) { 1223 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1224 return true; 1225 } 1226 1227 if (rxFifo.size() >= regs.RxFifoHigh) 1228 devIntrPost(Regs::Intr_RxHigh); 1229 1230 if (!rxFifo.push(packet)) { 1231 DPRINTF(Ethernet, 1232 "packet will not fit in receive buffer...packet dropped\n"); 1233 return false; 1234 } 1235 1236 // If we were at the last element, back up one ot go to the new 1237 // last element of the list. 1238 if (rxFifoPtr == rxFifo.end()) 1239 --rxFifoPtr; 1240 1241 devIntrPost(Regs::Intr_RxPacket); 1242 rxKick(); 1243 return true; 1244} 1245 1246void 1247Device::drainResume() 1248{ 1249 Drainable::drainResume(); 1250 1251 // During drain we could have left the state machines in a waiting state and 1252 // they wouldn't get out until some other event occured to kick them. 1253 // This way they'll get out immediately 1254 txKick(); 1255 rxKick(); 1256} 1257 1258//===================================================================== 1259// 1260// 1261void 1262Base::serialize(CheckpointOut &cp) const 1263{ 1264 // Serialize the PciDevice base class 1265 PciDevice::serialize(cp); 1266 1267 SERIALIZE_SCALAR(rxEnable); 1268 SERIALIZE_SCALAR(txEnable); 1269 SERIALIZE_SCALAR(cpuIntrEnable); 1270 1271 /* 1272 * Keep track of pending interrupt status. 1273 */ 1274 SERIALIZE_SCALAR(intrTick); 1275 SERIALIZE_SCALAR(cpuPendingIntr); 1276 Tick intrEventTick = 0; 1277 if (intrEvent) 1278 intrEventTick = intrEvent->when(); 1279 SERIALIZE_SCALAR(intrEventTick); 1280} 1281 1282void 1283Base::unserialize(CheckpointIn &cp) 1284{ 1285 // Unserialize the PciDevice base class 1286 PciDevice::unserialize(cp); 1287 1288 UNSERIALIZE_SCALAR(rxEnable); 1289 UNSERIALIZE_SCALAR(txEnable); 1290 UNSERIALIZE_SCALAR(cpuIntrEnable); 1291 1292 /* 1293 * Keep track of pending interrupt status. 1294 */ 1295 UNSERIALIZE_SCALAR(intrTick); 1296 UNSERIALIZE_SCALAR(cpuPendingIntr); 1297 Tick intrEventTick; 1298 UNSERIALIZE_SCALAR(intrEventTick); 1299 if (intrEventTick) { 1300 intrEvent = new IntrEvent(this, true); 1301 schedule(intrEvent, intrEventTick); 1302 } 1303} 1304 1305void 1306Device::serialize(CheckpointOut &cp) const 1307{ 1308 int count; 1309 1310 // Serialize the PciDevice base class 1311 Base::serialize(cp); 1312 1313 if (rxState == rxCopy) 1314 panic("can't serialize with an in flight dma request rxState=%s", 1315 RxStateStrings[rxState]); 1316 1317 if (txState == txCopy) 1318 panic("can't serialize with an in flight dma request txState=%s", 1319 TxStateStrings[txState]); 1320 1321 /* 1322 * Serialize the device registers that could be modified by the OS. 1323 */ 1324 SERIALIZE_SCALAR(regs.Config); 1325 SERIALIZE_SCALAR(regs.IntrStatus); 1326 SERIALIZE_SCALAR(regs.IntrMask); 1327 SERIALIZE_SCALAR(regs.RxData); 1328 SERIALIZE_SCALAR(regs.TxData); 1329 1330 /* 1331 * Serialize the virtual nic state 1332 */ 1333 int virtualRegsSize = virtualRegs.size(); 1334 SERIALIZE_SCALAR(virtualRegsSize); 1335 for (int i = 0; i < virtualRegsSize; ++i) { 1336 const VirtualReg *vnic = &virtualRegs[i]; 1337 1338 std::string reg = csprintf("vnic%d", i); 1339 paramOut(cp, reg + ".RxData", vnic->RxData); 1340 paramOut(cp, reg + ".RxDone", vnic->RxDone); 1341 paramOut(cp, reg + ".TxData", vnic->TxData); 1342 paramOut(cp, reg + ".TxDone", vnic->TxDone); 1343 1344 bool rxPacketExists = vnic->rxIndex != rxFifo.end(); 1345 paramOut(cp, reg + ".rxPacketExists", rxPacketExists); 1346 if (rxPacketExists) { 1347 int rxPacket = 0; 1348 auto i = rxFifo.begin(); 1349 while (i != vnic->rxIndex) { 1350 assert(i != rxFifo.end()); 1351 ++i; 1352 ++rxPacket; 1353 } 1354 1355 paramOut(cp, reg + ".rxPacket", rxPacket); 1356 paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset); 1357 paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1358 } 1359 paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData); 1360 } 1361 1362 int rxFifoPtr = -1; 1363 if (this->rxFifoPtr != rxFifo.end()) 1364 rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); 1365 SERIALIZE_SCALAR(rxFifoPtr); 1366 1367 SERIALIZE_SCALAR(rxActive); 1368 SERIALIZE_SCALAR(rxBusyCount); 1369 SERIALIZE_SCALAR(rxDirtyCount); 1370 SERIALIZE_SCALAR(rxMappedCount); 1371 1372 VirtualList::const_iterator i, end; 1373 for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) 1374 paramOut(cp, csprintf("rxList%d", count++), *i); 1375 int rxListSize = count; 1376 SERIALIZE_SCALAR(rxListSize); 1377 1378 for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) 1379 paramOut(cp, csprintf("rxBusy%d", count++), *i); 1380 int rxBusySize = count; 1381 SERIALIZE_SCALAR(rxBusySize); 1382 1383 for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) 1384 paramOut(cp, csprintf("txList%d", count++), *i); 1385 int txListSize = count; 1386 SERIALIZE_SCALAR(txListSize); 1387 1388 /* 1389 * Serialize rx state machine 1390 */ 1391 int rxState = this->rxState; 1392 SERIALIZE_SCALAR(rxState); 1393 SERIALIZE_SCALAR(rxEmpty); 1394 SERIALIZE_SCALAR(rxLow); 1395 rxFifo.serialize("rxFifo", cp); 1396 1397 /* 1398 * Serialize tx state machine 1399 */ 1400 int txState = this->txState; 1401 SERIALIZE_SCALAR(txState); 1402 SERIALIZE_SCALAR(txFull); 1403 txFifo.serialize("txFifo", cp); 1404 bool txPacketExists = txPacket != nullptr; 1405 SERIALIZE_SCALAR(txPacketExists); 1406 if (txPacketExists) { 1407 txPacket->serialize("txPacket", cp); 1408 SERIALIZE_SCALAR(txPacketOffset); 1409 SERIALIZE_SCALAR(txPacketBytes); 1410 } 1411 1412 /* 1413 * If there's a pending transmit, store the time so we can 1414 * reschedule it later 1415 */ 1416 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 1417 SERIALIZE_SCALAR(transmitTick); 1418} 1419 1420void 1421Device::unserialize(CheckpointIn &cp) 1422{ 1423 // Unserialize the PciDevice base class 1424 Base::unserialize(cp); 1425 1426 /* 1427 * Unserialize the device registers that may have been written by the OS. 1428 */ 1429 UNSERIALIZE_SCALAR(regs.Config); 1430 UNSERIALIZE_SCALAR(regs.IntrStatus); 1431 UNSERIALIZE_SCALAR(regs.IntrMask); 1432 UNSERIALIZE_SCALAR(regs.RxData); 1433 UNSERIALIZE_SCALAR(regs.TxData); 1434 1435 UNSERIALIZE_SCALAR(rxActive); 1436 UNSERIALIZE_SCALAR(rxBusyCount); 1437 UNSERIALIZE_SCALAR(rxDirtyCount); 1438 UNSERIALIZE_SCALAR(rxMappedCount); 1439 1440 int rxListSize; 1441 UNSERIALIZE_SCALAR(rxListSize); 1442 rxList.clear(); 1443 for (int i = 0; i < rxListSize; ++i) { 1444 int value; 1445 paramIn(cp, csprintf("rxList%d", i), value); 1446 rxList.push_back(value); 1447 } 1448 1449 int rxBusySize; 1450 UNSERIALIZE_SCALAR(rxBusySize); 1451 rxBusy.clear(); 1452 for (int i = 0; i < rxBusySize; ++i) { 1453 int value; 1454 paramIn(cp, csprintf("rxBusy%d", i), value); 1455 rxBusy.push_back(value); 1456 } 1457 1458 int txListSize; 1459 UNSERIALIZE_SCALAR(txListSize); 1460 txList.clear(); 1461 for (int i = 0; i < txListSize; ++i) { 1462 int value; 1463 paramIn(cp, csprintf("txList%d", i), value); 1464 txList.push_back(value); 1465 } 1466 1467 /* 1468 * Unserialize rx state machine 1469 */ 1470 int rxState; 1471 UNSERIALIZE_SCALAR(rxState); 1472 UNSERIALIZE_SCALAR(rxEmpty); 1473 UNSERIALIZE_SCALAR(rxLow); 1474 this->rxState = (RxState) rxState; 1475 rxFifo.unserialize("rxFifo", cp); 1476 1477 int rxFifoPtr; 1478 UNSERIALIZE_SCALAR(rxFifoPtr); 1479 if (rxFifoPtr >= 0) { 1480 this->rxFifoPtr = rxFifo.begin(); 1481 for (int i = 0; i < rxFifoPtr; ++i) 1482 ++this->rxFifoPtr; 1483 } else { 1484 this->rxFifoPtr = rxFifo.end(); 1485 } 1486 1487 /* 1488 * Unserialize tx state machine 1489 */ 1490 int txState; 1491 UNSERIALIZE_SCALAR(txState); 1492 UNSERIALIZE_SCALAR(txFull); 1493 this->txState = (TxState) txState; 1494 txFifo.unserialize("txFifo", cp); 1495 bool txPacketExists; 1496 UNSERIALIZE_SCALAR(txPacketExists); 1497 txPacket = 0; 1498 if (txPacketExists) { 1499 txPacket = make_shared<EthPacketData>(); 1500 txPacket->unserialize("txPacket", cp); 1501 UNSERIALIZE_SCALAR(txPacketOffset); 1502 UNSERIALIZE_SCALAR(txPacketBytes); 1503 } 1504 1505 /* 1506 * unserialize the virtual nic registers/state 1507 * 1508 * this must be done after the unserialization of the rxFifo 1509 * because the packet iterators depend on the fifo being populated 1510 */ 1511 int virtualRegsSize; 1512 UNSERIALIZE_SCALAR(virtualRegsSize); 1513 virtualRegs.clear(); 1514 virtualRegs.resize(virtualRegsSize); 1515 for (int i = 0; i < virtualRegsSize; ++i) { 1516 VirtualReg *vnic = &virtualRegs[i]; 1517 std::string reg = csprintf("vnic%d", i); 1518 1519 paramIn(cp, reg + ".RxData", vnic->RxData); 1520 paramIn(cp, reg + ".RxDone", vnic->RxDone); 1521 paramIn(cp, reg + ".TxData", vnic->TxData); 1522 paramIn(cp, reg + ".TxDone", vnic->TxDone); 1523 1524 vnic->rxUnique = rxUnique++; 1525 vnic->txUnique = txUnique++; 1526 1527 bool rxPacketExists; 1528 paramIn(cp, reg + ".rxPacketExists", rxPacketExists); 1529 if (rxPacketExists) { 1530 int rxPacket; 1531 paramIn(cp, reg + ".rxPacket", rxPacket); 1532 vnic->rxIndex = rxFifo.begin(); 1533 while (rxPacket--) 1534 ++vnic->rxIndex; 1535 1536 paramIn(cp, reg + ".rxPacketOffset", 1537 vnic->rxPacketOffset); 1538 paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1539 } else { 1540 vnic->rxIndex = rxFifo.end(); 1541 } 1542 paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData); 1543 } 1544 1545 /* 1546 * If there's a pending transmit, reschedule it now 1547 */ 1548 Tick transmitTick; 1549 UNSERIALIZE_SCALAR(transmitTick); 1550 if (transmitTick) 1551 schedule(txEvent, curTick() + transmitTick); 1552 1553 pioPort.sendRangeChange(); 1554 1555} 1556 1557} // namespace Sinic 1558 1559Sinic::Device * 1560SinicParams::create() 1561{ 1562 return new Sinic::Device(this); 1563} 1564