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