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