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