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