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