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