sinic.cc revision 5603
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Nathan Binkert 29 */ 30 31#include <deque> 32#include <limits> 33#include <string> 34 35#include "arch/vtophys.hh" 36#include "base/inet.hh" 37#include "cpu/thread_context.hh" 38#include "cpu/intr_control.hh" 39#include "dev/etherlink.hh" 40#include "dev/sinic.hh" 41#include "mem/packet.hh" 42#include "mem/packet_access.hh" 43#include "sim/debug.hh" 44#include "sim/eventq.hh" 45#include "sim/host.hh" 46#include "sim/stats.hh" 47 48using namespace 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->getCpuNum(); 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->getCpuNum(); 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, intrTick, true); 699} 700 701void 702Base::cpuInterrupt() 703{ 704 assert(intrTick == curTick); 705 706 // Whether or not there's a pending interrupt, we don't care about 707 // it anymore 708 intrEvent = 0; 709 intrTick = 0; 710 711 // Don't send an interrupt if there's already one 712 if (cpuPendingIntr) { 713 DPRINTF(EthernetIntr, 714 "would send an interrupt now, but there's already pending\n"); 715 } else { 716 // Send interrupt 717 cpuPendingIntr = true; 718 719 DPRINTF(EthernetIntr, "posting interrupt\n"); 720 intrPost(); 721 } 722} 723 724void 725Base::cpuIntrClear() 726{ 727 if (!cpuPendingIntr) 728 return; 729 730 if (intrEvent) { 731 intrEvent->squash(); 732 intrEvent = 0; 733 } 734 735 intrTick = 0; 736 737 cpuPendingIntr = false; 738 739 DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 740 intrClear(); 741} 742 743bool 744Base::cpuIntrPending() const 745{ return cpuPendingIntr; } 746 747void 748Device::changeConfig(uint32_t newconf) 749{ 750 uint32_t changed = regs.Config ^ newconf; 751 if (!changed) 752 return; 753 754 regs.Config = newconf; 755 756 if ((changed & Regs::Config_IntEn)) { 757 cpuIntrEnable = regs.Config & Regs::Config_IntEn; 758 if (cpuIntrEnable) { 759 if (regs.IntrStatus & regs.IntrMask) 760 cpuIntrPost(curTick); 761 } else { 762 cpuIntrClear(); 763 } 764 } 765 766 if ((changed & Regs::Config_TxEn)) { 767 txEnable = regs.Config & Regs::Config_TxEn; 768 if (txEnable) 769 txKick(); 770 } 771 772 if ((changed & Regs::Config_RxEn)) { 773 rxEnable = regs.Config & Regs::Config_RxEn; 774 if (rxEnable) 775 rxKick(); 776 } 777} 778 779void 780Device::command(uint32_t command) 781{ 782 if (command & Regs::Command_Intr) 783 devIntrPost(Regs::Intr_Soft); 784 785 if (command & Regs::Command_Reset) 786 reset(); 787} 788 789void 790Device::reset() 791{ 792 using namespace Regs; 793 794 memset(®s, 0, sizeof(regs)); 795 796 regs.Config = 0; 797 if (params()->rx_thread) 798 regs.Config |= Config_RxThread; 799 if (params()->tx_thread) 800 regs.Config |= Config_TxThread; 801 if (params()->rss) 802 regs.Config |= Config_RSS; 803 if (params()->zero_copy) 804 regs.Config |= Config_ZeroCopy; 805 if (params()->delay_copy) 806 regs.Config |= Config_DelayCopy; 807 if (params()->virtual_addr) 808 regs.Config |= Config_Vaddr; 809 810 if (params()->delay_copy && params()->zero_copy) 811 panic("Can't delay copy and zero copy"); 812 813 regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; 814 regs.RxMaxCopy = params()->rx_max_copy; 815 regs.TxMaxCopy = params()->tx_max_copy; 816 regs.ZeroCopySize = params()->zero_copy_size; 817 regs.ZeroCopyMark = params()->zero_copy_threshold; 818 regs.VirtualCount = params()->virtual_count; 819 regs.RxMaxIntr = params()->rx_max_intr; 820 regs.RxFifoSize = params()->rx_fifo_size; 821 regs.TxFifoSize = params()->tx_fifo_size; 822 regs.RxFifoLow = params()->rx_fifo_low_mark; 823 regs.TxFifoLow = params()->tx_fifo_threshold; 824 regs.RxFifoHigh = params()->rx_fifo_threshold; 825 regs.TxFifoHigh = params()->tx_fifo_high_mark; 826 regs.HwAddr = params()->hardware_address; 827 828 if (regs.RxMaxCopy < regs.ZeroCopyMark) 829 panic("Must be able to copy at least as many bytes as the threshold"); 830 831 if (regs.ZeroCopySize >= regs.ZeroCopyMark) 832 panic("The number of bytes to copy must be less than the threshold"); 833 834 rxList.clear(); 835 rxBusy.clear(); 836 rxActive = -1; 837 txList.clear(); 838 rxBusyCount = 0; 839 rxDirtyCount = 0; 840 rxMappedCount = 0; 841 842 rxState = rxIdle; 843 txState = txIdle; 844 845 rxFifo.clear(); 846 rxFifoPtr = rxFifo.end(); 847 txFifo.clear(); 848 rxEmpty = false; 849 rxLow = true; 850 txFull = false; 851 852 int size = virtualRegs.size(); 853 virtualRegs.clear(); 854 virtualRegs.resize(size); 855 for (int i = 0; i < size; ++i) 856 virtualRegs[i].rxIndex = rxFifo.end(); 857} 858 859void 860Device::rxDmaDone() 861{ 862 assert(rxState == rxCopy); 863 rxState = rxCopyDone; 864 DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", 865 rxDmaAddr, rxDmaLen); 866 DDUMP(EthernetData, rxDmaData, rxDmaLen); 867 868 // If the transmit state machine has a pending DMA, let it go first 869 if (txState == txBeginCopy) 870 txKick(); 871 872 rxKick(); 873} 874 875void 876Device::rxKick() 877{ 878 VirtualReg *vnic = NULL; 879 880 DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", 881 RxStateStrings[rxState], rxFifo.size()); 882 883 if (rxKickTick > curTick) { 884 DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", 885 rxKickTick); 886 return; 887 } 888 889 next: 890 rxFifo.check(); 891 if (rxState == rxIdle) 892 goto exit; 893 894 if (rxActive == -1) { 895 if (rxState != rxFifoBlock) 896 panic("no active vnic while in state %s", RxStateStrings[rxState]); 897 898 DPRINTF(EthernetSM, "processing rxState=%s\n", 899 RxStateStrings[rxState]); 900 } else { 901 vnic = &virtualRegs[rxActive]; 902 DPRINTF(EthernetSM, 903 "processing rxState=%s for vnic %d (rxunique %d)\n", 904 RxStateStrings[rxState], rxActive, vnic->rxUnique); 905 } 906 907 switch (rxState) { 908 case rxFifoBlock: 909 if (DTRACE(EthernetSM)) { 910 PacketFifo::iterator end = rxFifo.end(); 911 int size = virtualRegs.size(); 912 for (int i = 0; i < size; ++i) { 913 VirtualReg *vn = &virtualRegs[i]; 914 bool busy = Regs::get_RxDone_Busy(vn->RxDone); 915 if (vn->rxIndex != end) { 916 bool dirty = vn->rxPacketOffset > 0; 917 const char *status; 918 919 if (busy && dirty) 920 status = "busy,dirty"; 921 else if (busy) 922 status = "busy"; 923 else if (dirty) 924 status = "dirty"; 925 else 926 status = "mapped"; 927 928 DPRINTF(EthernetSM, 929 "vnic %d %s (rxunique %d), packet %d, slack %d\n", 930 i, status, vn->rxUnique, 931 rxFifo.countPacketsBefore(vn->rxIndex), 932 vn->rxIndex->slack); 933 } else if (busy) { 934 DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n", 935 i, vn->rxUnique); 936 } 937 } 938 } 939 940 if (!rxBusy.empty()) { 941 rxActive = rxBusy.front(); 942 rxBusy.pop_front(); 943 vnic = &virtualRegs[rxActive]; 944 945 if (vnic->rxIndex == rxFifo.end()) 946 panic("continuing vnic without packet\n"); 947 948 DPRINTF(EthernetSM, 949 "continue processing for vnic %d (rxunique %d)\n", 950 rxActive, vnic->rxUnique); 951 952 rxState = rxBeginCopy; 953 954 int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex); 955 totalVnicDistance += vnic_distance; 956 numVnicDistance += 1; 957 if (vnic_distance > _maxVnicDistance) { 958 maxVnicDistance = vnic_distance; 959 _maxVnicDistance = vnic_distance; 960 } 961 962 break; 963 } 964 965 if (rxFifoPtr == rxFifo.end()) { 966 DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 967 goto exit; 968 } 969 970 if (rxList.empty()) 971 panic("Not idle, but nothing to do!"); 972 973 assert(!rxFifo.empty()); 974 975 rxActive = rxList.front(); 976 rxList.pop_front(); 977 vnic = &virtualRegs[rxActive]; 978 979 DPRINTF(EthernetSM, 980 "processing new packet for vnic %d (rxunique %d)\n", 981 rxActive, vnic->rxUnique); 982 983 // Grab a new packet from the fifo. 984 vnic->rxIndex = rxFifoPtr++; 985 vnic->rxIndex->priv = rxActive; 986 vnic->rxPacketOffset = 0; 987 vnic->rxPacketBytes = vnic->rxIndex->packet->length; 988 assert(vnic->rxPacketBytes); 989 rxMappedCount++; 990 991 vnic->rxDoneData = 0; 992 /* scope for variables */ { 993 IpPtr ip(vnic->rxIndex->packet); 994 if (ip) { 995 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 996 vnic->rxDoneData |= Regs::RxDone_IpPacket; 997 rxIpChecksums++; 998 if (cksum(ip) != 0) { 999 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1000 vnic->rxDoneData |= Regs::RxDone_IpError; 1001 } 1002 TcpPtr tcp(ip); 1003 UdpPtr udp(ip); 1004 if (tcp) { 1005 DPRINTF(Ethernet, 1006 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1007 tcp->sport(), tcp->dport(), tcp->seq(), 1008 tcp->ack()); 1009 vnic->rxDoneData |= Regs::RxDone_TcpPacket; 1010 rxTcpChecksums++; 1011 if (cksum(tcp) != 0) { 1012 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1013 vnic->rxDoneData |= Regs::RxDone_TcpError; 1014 } 1015 } else if (udp) { 1016 vnic->rxDoneData |= Regs::RxDone_UdpPacket; 1017 rxUdpChecksums++; 1018 if (cksum(udp) != 0) { 1019 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1020 vnic->rxDoneData |= Regs::RxDone_UdpError; 1021 } 1022 } 1023 } 1024 } 1025 rxState = rxBeginCopy; 1026 break; 1027 1028 case rxBeginCopy: 1029 if (dmaPending() || getState() != Running) 1030 goto exit; 1031 1032 rxDmaAddr = params()->platform->pciToDma( 1033 Regs::get_RxData_Addr(vnic->RxData)); 1034 rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData), 1035 vnic->rxPacketBytes); 1036 1037 /* 1038 * if we're doing zero/delay copy and we're below the fifo 1039 * threshold, see if we should try to do the zero/defer copy 1040 */ 1041 if ((Regs::get_Config_ZeroCopy(regs.Config) || 1042 Regs::get_Config_DelayCopy(regs.Config)) && 1043 !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) { 1044 if (rxDmaLen > regs.ZeroCopyMark) 1045 rxDmaLen = regs.ZeroCopySize; 1046 } 1047 rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset; 1048 rxState = rxCopy; 1049 if (rxDmaAddr == 1LL) { 1050 rxState = rxCopyDone; 1051 break; 1052 } 1053 1054 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); 1055 break; 1056 1057 case rxCopy: 1058 DPRINTF(EthernetSM, "receive machine still copying\n"); 1059 goto exit; 1060 1061 case rxCopyDone: 1062 vnic->RxDone = vnic->rxDoneData; 1063 vnic->RxDone |= Regs::RxDone_Complete; 1064 rxBusyCount--; 1065 1066 if (vnic->rxPacketBytes == rxDmaLen) { 1067 if (vnic->rxPacketOffset) 1068 rxDirtyCount--; 1069 1070 // Packet is complete. Indicate how many bytes were copied 1071 vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); 1072 1073 DPRINTF(EthernetSM, 1074 "rxKick: packet complete on vnic %d (rxunique %d)\n", 1075 rxActive, vnic->rxUnique); 1076 rxFifo.remove(vnic->rxIndex); 1077 vnic->rxIndex = rxFifo.end(); 1078 rxMappedCount--; 1079 } else { 1080 if (!vnic->rxPacketOffset) 1081 rxDirtyCount++; 1082 1083 vnic->rxPacketBytes -= rxDmaLen; 1084 vnic->rxPacketOffset += rxDmaLen; 1085 vnic->RxDone |= Regs::RxDone_More; 1086 vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, 1087 vnic->rxPacketBytes); 1088 DPRINTF(EthernetSM, 1089 "rxKick: packet not complete on vnic %d (rxunique %d): " 1090 "%d bytes left\n", 1091 rxActive, vnic->rxUnique, vnic->rxPacketBytes); 1092 } 1093 1094 rxActive = -1; 1095 rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; 1096 1097 if (rxFifo.empty()) { 1098 devIntrPost(Regs::Intr_RxEmpty); 1099 rxEmpty = true; 1100 } 1101 1102 if (rxFifo.size() < regs.RxFifoLow) 1103 rxLow = true; 1104 1105 if (rxFifo.size() > regs.RxFifoHigh) 1106 rxLow = false; 1107 1108 devIntrPost(Regs::Intr_RxDMA); 1109 break; 1110 1111 default: 1112 panic("Invalid rxState!"); 1113 } 1114 1115 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1116 RxStateStrings[rxState]); 1117 1118 goto next; 1119 1120 exit: 1121 /** 1122 * @todo do we want to schedule a future kick? 1123 */ 1124 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1125 RxStateStrings[rxState]); 1126} 1127 1128void 1129Device::txDmaDone() 1130{ 1131 assert(txState == txCopy); 1132 txState = txCopyDone; 1133 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1134 txDmaAddr, txDmaLen); 1135 DDUMP(EthernetData, txDmaData, txDmaLen); 1136 1137 // If the receive state machine has a pending DMA, let it go first 1138 if (rxState == rxBeginCopy) 1139 rxKick(); 1140 1141 txKick(); 1142} 1143 1144void 1145Device::transmit() 1146{ 1147 if (txFifo.empty()) { 1148 DPRINTF(Ethernet, "nothing to transmit\n"); 1149 return; 1150 } 1151 1152 uint32_t interrupts; 1153 EthPacketPtr packet = txFifo.front(); 1154 if (!interface->sendPacket(packet)) { 1155 DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 1156 txFifo.avail()); 1157 return; 1158 } 1159 1160 txFifo.pop(); 1161#if TRACING_ON 1162 if (DTRACE(Ethernet)) { 1163 IpPtr ip(packet); 1164 if (ip) { 1165 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1166 TcpPtr tcp(ip); 1167 if (tcp) { 1168 DPRINTF(Ethernet, 1169 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1170 tcp->sport(), tcp->dport(), tcp->seq(), 1171 tcp->ack()); 1172 } 1173 } 1174 } 1175#endif 1176 1177 DDUMP(EthernetData, packet->data, packet->length); 1178 txBytes += packet->length; 1179 txPackets++; 1180 1181 DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 1182 txFifo.avail()); 1183 1184 interrupts = Regs::Intr_TxPacket; 1185 if (txFifo.size() < regs.TxFifoLow) 1186 interrupts |= Regs::Intr_TxLow; 1187 devIntrPost(interrupts); 1188} 1189 1190void 1191Device::txKick() 1192{ 1193 VirtualReg *vnic; 1194 DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", 1195 TxStateStrings[txState], txFifo.size()); 1196 1197 if (txKickTick > curTick) { 1198 DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", 1199 txKickTick); 1200 return; 1201 } 1202 1203 next: 1204 if (txState == txIdle) 1205 goto exit; 1206 1207 assert(!txList.empty()); 1208 vnic = &virtualRegs[txList.front()]; 1209 1210 switch (txState) { 1211 case txFifoBlock: 1212 assert(Regs::get_TxDone_Busy(vnic->TxDone)); 1213 if (!txPacket) { 1214 // Grab a new packet from the fifo. 1215 txPacket = new EthPacketData(16384); 1216 txPacketOffset = 0; 1217 } 1218 1219 if (txFifo.avail() - txPacket->length < 1220 Regs::get_TxData_Len(vnic->TxData)) { 1221 DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 1222 goto exit; 1223 } 1224 1225 txState = txBeginCopy; 1226 break; 1227 1228 case txBeginCopy: 1229 if (dmaPending() || getState() != Running) 1230 goto exit; 1231 1232 txDmaAddr = params()->platform->pciToDma( 1233 Regs::get_TxData_Addr(vnic->TxData)); 1234 txDmaLen = Regs::get_TxData_Len(vnic->TxData); 1235 txDmaData = txPacket->data + txPacketOffset; 1236 txState = txCopy; 1237 1238 dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); 1239 break; 1240 1241 case txCopy: 1242 DPRINTF(EthernetSM, "transmit machine still copying\n"); 1243 goto exit; 1244 1245 case txCopyDone: 1246 vnic->TxDone = txDmaLen | Regs::TxDone_Complete; 1247 txPacket->length += txDmaLen; 1248 if ((vnic->TxData & Regs::TxData_More)) { 1249 txPacketOffset += txDmaLen; 1250 txState = txIdle; 1251 devIntrPost(Regs::Intr_TxDMA); 1252 break; 1253 } 1254 1255 assert(txPacket->length <= txFifo.avail()); 1256 if ((vnic->TxData & Regs::TxData_Checksum)) { 1257 IpPtr ip(txPacket); 1258 if (ip) { 1259 TcpPtr tcp(ip); 1260 if (tcp) { 1261 tcp->sum(0); 1262 tcp->sum(cksum(tcp)); 1263 txTcpChecksums++; 1264 } 1265 1266 UdpPtr udp(ip); 1267 if (udp) { 1268 udp->sum(0); 1269 udp->sum(cksum(udp)); 1270 txUdpChecksums++; 1271 } 1272 1273 ip->sum(0); 1274 ip->sum(cksum(ip)); 1275 txIpChecksums++; 1276 } 1277 } 1278 1279 txFifo.push(txPacket); 1280 if (txFifo.avail() < regs.TxMaxCopy) { 1281 devIntrPost(Regs::Intr_TxFull); 1282 txFull = true; 1283 } 1284 txPacket = 0; 1285 transmit(); 1286 txList.pop_front(); 1287 txState = txList.empty() ? txIdle : txFifoBlock; 1288 devIntrPost(Regs::Intr_TxDMA); 1289 break; 1290 1291 default: 1292 panic("Invalid txState!"); 1293 } 1294 1295 DPRINTF(EthernetSM, "entering next txState=%s\n", 1296 TxStateStrings[txState]); 1297 1298 goto next; 1299 1300 exit: 1301 /** 1302 * @todo do we want to schedule a future kick? 1303 */ 1304 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1305 TxStateStrings[txState]); 1306} 1307 1308void 1309Device::transferDone() 1310{ 1311 if (txFifo.empty()) { 1312 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1313 return; 1314 } 1315 1316 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 1317 1318 txEvent.reschedule(curTick + ticks(1), true); 1319} 1320 1321bool 1322Device::rxFilter(const EthPacketPtr &packet) 1323{ 1324 if (!Regs::get_Config_Filter(regs.Config)) 1325 return false; 1326 1327 panic("receive filter not implemented\n"); 1328 bool drop = true; 1329 1330#if 0 1331 string type; 1332 1333 EthHdr *eth = packet->eth(); 1334 if (eth->unicast()) { 1335 // If we're accepting all unicast addresses 1336 if (acceptUnicast) 1337 drop = false; 1338 1339 // If we make a perfect match 1340 if (acceptPerfect && params->eaddr == eth.dst()) 1341 drop = false; 1342 1343 if (acceptArp && eth->type() == ETH_TYPE_ARP) 1344 drop = false; 1345 1346 } else if (eth->broadcast()) { 1347 // if we're accepting broadcasts 1348 if (acceptBroadcast) 1349 drop = false; 1350 1351 } else if (eth->multicast()) { 1352 // if we're accepting all multicasts 1353 if (acceptMulticast) 1354 drop = false; 1355 1356 } 1357 1358 if (drop) { 1359 DPRINTF(Ethernet, "rxFilter drop\n"); 1360 DDUMP(EthernetData, packet->data, packet->length); 1361 } 1362#endif 1363 return drop; 1364} 1365 1366bool 1367Device::recvPacket(EthPacketPtr packet) 1368{ 1369 rxBytes += packet->length; 1370 rxPackets++; 1371 1372 DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 1373 rxFifo.avail()); 1374 1375 if (!rxEnable) { 1376 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1377 return true; 1378 } 1379 1380 if (rxFilter(packet)) { 1381 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1382 return true; 1383 } 1384 1385 if (rxFifo.size() >= regs.RxFifoHigh) 1386 devIntrPost(Regs::Intr_RxHigh); 1387 1388 if (!rxFifo.push(packet)) { 1389 DPRINTF(Ethernet, 1390 "packet will not fit in receive buffer...packet dropped\n"); 1391 return false; 1392 } 1393 1394 // If we were at the last element, back up one ot go to the new 1395 // last element of the list. 1396 if (rxFifoPtr == rxFifo.end()) 1397 --rxFifoPtr; 1398 1399 devIntrPost(Regs::Intr_RxPacket); 1400 rxKick(); 1401 return true; 1402} 1403 1404void 1405Device::resume() 1406{ 1407 SimObject::resume(); 1408 1409 // During drain we could have left the state machines in a waiting state and 1410 // they wouldn't get out until some other event occured to kick them. 1411 // This way they'll get out immediately 1412 txKick(); 1413 rxKick(); 1414} 1415 1416//===================================================================== 1417// 1418// 1419void 1420Base::serialize(std::ostream &os) 1421{ 1422 // Serialize the PciDev base class 1423 PciDev::serialize(os); 1424 1425 SERIALIZE_SCALAR(rxEnable); 1426 SERIALIZE_SCALAR(txEnable); 1427 SERIALIZE_SCALAR(cpuIntrEnable); 1428 1429 /* 1430 * Keep track of pending interrupt status. 1431 */ 1432 SERIALIZE_SCALAR(intrTick); 1433 SERIALIZE_SCALAR(cpuPendingIntr); 1434 Tick intrEventTick = 0; 1435 if (intrEvent) 1436 intrEventTick = intrEvent->when(); 1437 SERIALIZE_SCALAR(intrEventTick); 1438} 1439 1440void 1441Base::unserialize(Checkpoint *cp, const std::string §ion) 1442{ 1443 // Unserialize the PciDev base class 1444 PciDev::unserialize(cp, section); 1445 1446 UNSERIALIZE_SCALAR(rxEnable); 1447 UNSERIALIZE_SCALAR(txEnable); 1448 UNSERIALIZE_SCALAR(cpuIntrEnable); 1449 1450 /* 1451 * Keep track of pending interrupt status. 1452 */ 1453 UNSERIALIZE_SCALAR(intrTick); 1454 UNSERIALIZE_SCALAR(cpuPendingIntr); 1455 Tick intrEventTick; 1456 UNSERIALIZE_SCALAR(intrEventTick); 1457 if (intrEventTick) { 1458 intrEvent = new IntrEvent(this, intrEventTick, true); 1459 } 1460} 1461 1462void 1463Device::serialize(std::ostream &os) 1464{ 1465 int count; 1466 1467 // Serialize the PciDev base class 1468 Base::serialize(os); 1469 1470 if (rxState == rxCopy) 1471 panic("can't serialize with an in flight dma request rxState=%s", 1472 RxStateStrings[rxState]); 1473 1474 if (txState == txCopy) 1475 panic("can't serialize with an in flight dma request txState=%s", 1476 TxStateStrings[txState]); 1477 1478 /* 1479 * Serialize the device registers that could be modified by the OS. 1480 */ 1481 SERIALIZE_SCALAR(regs.Config); 1482 SERIALIZE_SCALAR(regs.IntrStatus); 1483 SERIALIZE_SCALAR(regs.IntrMask); 1484 SERIALIZE_SCALAR(regs.RxData); 1485 SERIALIZE_SCALAR(regs.TxData); 1486 1487 /* 1488 * Serialize the virtual nic state 1489 */ 1490 int virtualRegsSize = virtualRegs.size(); 1491 SERIALIZE_SCALAR(virtualRegsSize); 1492 for (int i = 0; i < virtualRegsSize; ++i) { 1493 VirtualReg *vnic = &virtualRegs[i]; 1494 1495 std::string reg = csprintf("vnic%d", i); 1496 paramOut(os, reg + ".RxData", vnic->RxData); 1497 paramOut(os, reg + ".RxDone", vnic->RxDone); 1498 paramOut(os, reg + ".TxData", vnic->TxData); 1499 paramOut(os, reg + ".TxDone", vnic->TxDone); 1500 1501 bool rxPacketExists = vnic->rxIndex != rxFifo.end(); 1502 paramOut(os, reg + ".rxPacketExists", rxPacketExists); 1503 if (rxPacketExists) { 1504 int rxPacket = 0; 1505 PacketFifo::iterator i = rxFifo.begin(); 1506 while (i != vnic->rxIndex) { 1507 assert(i != rxFifo.end()); 1508 ++i; 1509 ++rxPacket; 1510 } 1511 1512 paramOut(os, reg + ".rxPacket", rxPacket); 1513 paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset); 1514 paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1515 } 1516 paramOut(os, reg + ".rxDoneData", vnic->rxDoneData); 1517 } 1518 1519 int rxFifoPtr = -1; 1520 if (this->rxFifoPtr != rxFifo.end()) 1521 rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); 1522 SERIALIZE_SCALAR(rxFifoPtr); 1523 1524 SERIALIZE_SCALAR(rxActive); 1525 SERIALIZE_SCALAR(rxBusyCount); 1526 SERIALIZE_SCALAR(rxDirtyCount); 1527 SERIALIZE_SCALAR(rxMappedCount); 1528 1529 VirtualList::iterator i, end; 1530 for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) 1531 paramOut(os, csprintf("rxList%d", count++), *i); 1532 int rxListSize = count; 1533 SERIALIZE_SCALAR(rxListSize); 1534 1535 for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) 1536 paramOut(os, csprintf("rxBusy%d", count++), *i); 1537 int rxBusySize = count; 1538 SERIALIZE_SCALAR(rxBusySize); 1539 1540 for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) 1541 paramOut(os, csprintf("txList%d", count++), *i); 1542 int txListSize = count; 1543 SERIALIZE_SCALAR(txListSize); 1544 1545 /* 1546 * Serialize rx state machine 1547 */ 1548 int rxState = this->rxState; 1549 SERIALIZE_SCALAR(rxState); 1550 SERIALIZE_SCALAR(rxEmpty); 1551 SERIALIZE_SCALAR(rxLow); 1552 rxFifo.serialize("rxFifo", os); 1553 1554 /* 1555 * Serialize tx state machine 1556 */ 1557 int txState = this->txState; 1558 SERIALIZE_SCALAR(txState); 1559 SERIALIZE_SCALAR(txFull); 1560 txFifo.serialize("txFifo", os); 1561 bool txPacketExists = txPacket; 1562 SERIALIZE_SCALAR(txPacketExists); 1563 if (txPacketExists) { 1564 txPacket->serialize("txPacket", os); 1565 SERIALIZE_SCALAR(txPacketOffset); 1566 SERIALIZE_SCALAR(txPacketBytes); 1567 } 1568 1569 /* 1570 * If there's a pending transmit, store the time so we can 1571 * reschedule it later 1572 */ 1573 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 1574 SERIALIZE_SCALAR(transmitTick); 1575} 1576 1577void 1578Device::unserialize(Checkpoint *cp, const std::string §ion) 1579{ 1580 // Unserialize the PciDev base class 1581 Base::unserialize(cp, section); 1582 1583 /* 1584 * Unserialize the device registers that may have been written by the OS. 1585 */ 1586 UNSERIALIZE_SCALAR(regs.Config); 1587 UNSERIALIZE_SCALAR(regs.IntrStatus); 1588 UNSERIALIZE_SCALAR(regs.IntrMask); 1589 UNSERIALIZE_SCALAR(regs.RxData); 1590 UNSERIALIZE_SCALAR(regs.TxData); 1591 1592 UNSERIALIZE_SCALAR(rxActive); 1593 UNSERIALIZE_SCALAR(rxBusyCount); 1594 UNSERIALIZE_SCALAR(rxDirtyCount); 1595 UNSERIALIZE_SCALAR(rxMappedCount); 1596 1597 int rxListSize; 1598 UNSERIALIZE_SCALAR(rxListSize); 1599 rxList.clear(); 1600 for (int i = 0; i < rxListSize; ++i) { 1601 int value; 1602 paramIn(cp, section, csprintf("rxList%d", i), value); 1603 rxList.push_back(value); 1604 } 1605 1606 int rxBusySize; 1607 UNSERIALIZE_SCALAR(rxBusySize); 1608 rxBusy.clear(); 1609 for (int i = 0; i < rxBusySize; ++i) { 1610 int value; 1611 paramIn(cp, section, csprintf("rxBusy%d", i), value); 1612 rxBusy.push_back(value); 1613 } 1614 1615 int txListSize; 1616 UNSERIALIZE_SCALAR(txListSize); 1617 txList.clear(); 1618 for (int i = 0; i < txListSize; ++i) { 1619 int value; 1620 paramIn(cp, section, csprintf("txList%d", i), value); 1621 txList.push_back(value); 1622 } 1623 1624 /* 1625 * Unserialize rx state machine 1626 */ 1627 int rxState; 1628 UNSERIALIZE_SCALAR(rxState); 1629 UNSERIALIZE_SCALAR(rxEmpty); 1630 UNSERIALIZE_SCALAR(rxLow); 1631 this->rxState = (RxState) rxState; 1632 rxFifo.unserialize("rxFifo", cp, section); 1633 1634 int rxFifoPtr; 1635 UNSERIALIZE_SCALAR(rxFifoPtr); 1636 if (rxFifoPtr >= 0) { 1637 this->rxFifoPtr = rxFifo.begin(); 1638 for (int i = 0; i < rxFifoPtr; ++i) 1639 ++this->rxFifoPtr; 1640 } else { 1641 this->rxFifoPtr = rxFifo.end(); 1642 } 1643 1644 /* 1645 * Unserialize tx state machine 1646 */ 1647 int txState; 1648 UNSERIALIZE_SCALAR(txState); 1649 UNSERIALIZE_SCALAR(txFull); 1650 this->txState = (TxState) txState; 1651 txFifo.unserialize("txFifo", cp, section); 1652 bool txPacketExists; 1653 UNSERIALIZE_SCALAR(txPacketExists); 1654 txPacket = 0; 1655 if (txPacketExists) { 1656 txPacket = new EthPacketData(16384); 1657 txPacket->unserialize("txPacket", cp, section); 1658 UNSERIALIZE_SCALAR(txPacketOffset); 1659 UNSERIALIZE_SCALAR(txPacketBytes); 1660 } 1661 1662 /* 1663 * unserialize the virtual nic registers/state 1664 * 1665 * this must be done after the unserialization of the rxFifo 1666 * because the packet iterators depend on the fifo being populated 1667 */ 1668 int virtualRegsSize; 1669 UNSERIALIZE_SCALAR(virtualRegsSize); 1670 virtualRegs.clear(); 1671 virtualRegs.resize(virtualRegsSize); 1672 for (int i = 0; i < virtualRegsSize; ++i) { 1673 VirtualReg *vnic = &virtualRegs[i]; 1674 std::string reg = csprintf("vnic%d", i); 1675 1676 paramIn(cp, section, reg + ".RxData", vnic->RxData); 1677 paramIn(cp, section, reg + ".RxDone", vnic->RxDone); 1678 paramIn(cp, section, reg + ".TxData", vnic->TxData); 1679 paramIn(cp, section, reg + ".TxDone", vnic->TxDone); 1680 1681 vnic->rxUnique = rxUnique++; 1682 vnic->txUnique = txUnique++; 1683 1684 bool rxPacketExists; 1685 paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists); 1686 if (rxPacketExists) { 1687 int rxPacket; 1688 paramIn(cp, section, reg + ".rxPacket", rxPacket); 1689 vnic->rxIndex = rxFifo.begin(); 1690 while (rxPacket--) 1691 ++vnic->rxIndex; 1692 1693 paramIn(cp, section, reg + ".rxPacketOffset", 1694 vnic->rxPacketOffset); 1695 paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1696 } else { 1697 vnic->rxIndex = rxFifo.end(); 1698 } 1699 paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData); 1700 } 1701 1702 /* 1703 * If there's a pending transmit, reschedule it now 1704 */ 1705 Tick transmitTick; 1706 UNSERIALIZE_SCALAR(transmitTick); 1707 if (transmitTick) 1708 txEvent.schedule(curTick + transmitTick); 1709 1710 pioPort->sendStatusChange(Port::RangeChange); 1711 1712} 1713 1714/* namespace Sinic */ } 1715 1716Sinic::Device * 1717SinicParams::create() 1718{ 1719 return new Sinic::Device(this); 1720} 1721