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