copy_engine.cc revision 8232
1/* 2 * Copyright (c) 2008 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: Ali Saidi 29 */ 30 31/* @file 32 * Device model for Intel's I/O AT DMA copy engine. 33 */ 34 35#include <algorithm> 36 37#include "base/cp_annotate.hh" 38#include "base/trace.hh" 39#include "debug/DMACopyEngine.hh" 40#include "dev/copy_engine.hh" 41#include "mem/packet.hh" 42#include "mem/packet_access.hh" 43#include "params/CopyEngine.hh" 44#include "sim/stats.hh" 45#include "sim/system.hh" 46 47using namespace CopyEngineReg; 48using namespace std; 49 50CopyEngine::CopyEngine(const Params *p) 51 : PciDev(p) 52{ 53 // All Reg regs are initialized to 0 by default 54 regs.chanCount = p->ChanCnt; 55 regs.xferCap = findMsbSet(p->XferCap); 56 regs.attnStatus = 0; 57 58 if (regs.chanCount > 64) 59 fatal("CopyEngine interface doesn't support more than 64 DMA engines\n"); 60 61 for (int x = 0; x < regs.chanCount; x++) { 62 CopyEngineChannel *ch = new CopyEngineChannel(this, x); 63 chan.push_back(ch); 64 } 65} 66 67 68CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid) 69 : ce(_ce), channelId(cid), busy(false), underReset(false), 70 refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin), 71 latAfterCompletion(ce->params()->latAfterCompletion), 72 completionDataReg(0), nextState(Idle), drainEvent(NULL), 73 fetchCompleteEvent(this), addrCompleteEvent(this), 74 readCompleteEvent(this), writeCompleteEvent(this), 75 statusCompleteEvent(this) 76 77{ 78 cr.status.dma_transfer_status(3); 79 cr.descChainAddr = 0; 80 cr.completionAddr = 0; 81 82 curDmaDesc = new DmaDesc; 83 memset(curDmaDesc, 0, sizeof(DmaDesc)); 84 copyBuffer = new uint8_t[ce->params()->XferCap]; 85} 86 87CopyEngine::~CopyEngine() 88{ 89 for (int x = 0; x < chan.size(); x++) { 90 delete chan[x]; 91 } 92} 93 94CopyEngine::CopyEngineChannel::~CopyEngineChannel() 95{ 96 delete curDmaDesc; 97 delete [] copyBuffer; 98 delete cePort; 99} 100 101void 102CopyEngine::init() 103{ 104 PciDev::init(); 105 for (int x = 0; x < chan.size(); x++) 106 chan[x]->init(); 107} 108 109void 110CopyEngine::CopyEngineChannel::init() 111{ 112 Port *peer; 113 114 cePort = new DmaPort(ce, ce->sys, ce->params()->min_backoff_delay, 115 ce->params()->max_backoff_delay); 116 peer = ce->dmaPort->getPeer()->getOwner()->getPort(""); 117 peer->setPeer(cePort); 118 cePort->setPeer(peer); 119} 120 121void 122CopyEngine::CopyEngineChannel::recvCommand() 123{ 124 if (cr.command.start_dma()) { 125 assert(!busy); 126 cr.status.dma_transfer_status(0); 127 nextState = DescriptorFetch; 128 fetchAddress = cr.descChainAddr; 129 if (ce->getState() == SimObject::Running) 130 fetchDescriptor(cr.descChainAddr); 131 } else if (cr.command.append_dma()) { 132 if (!busy) { 133 nextState = AddressFetch; 134 if (ce->getState() == SimObject::Running) 135 fetchNextAddr(lastDescriptorAddr); 136 } else 137 refreshNext = true; 138 } else if (cr.command.reset_dma()) { 139 if (busy) 140 underReset = true; 141 else { 142 cr.status.dma_transfer_status(3); 143 nextState = Idle; 144 } 145 } else if (cr.command.resume_dma() || cr.command.abort_dma() || 146 cr.command.suspend_dma()) 147 panic("Resume, Abort, and Suspend are not supported\n"); 148 cr.command(0); 149} 150 151Tick 152CopyEngine::read(PacketPtr pkt) 153{ 154 int bar; 155 Addr daddr; 156 157 if (!getBAR(pkt->getAddr(), bar, daddr)) 158 panic("Invalid PCI memory access to unmapped memory.\n"); 159 160 // Only Memory register BAR is allowed 161 assert(bar == 0); 162 163 int size = pkt->getSize(); 164 if (size != sizeof(uint64_t) && size != sizeof(uint32_t) && 165 size != sizeof(uint16_t) && size != sizeof(uint8_t)) { 166 panic("Unknown size for MMIO access: %d\n", pkt->getSize()); 167 } 168 169 DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size); 170 171 pkt->allocate(); 172 173 /// 174 /// Handle read of register here 175 /// 176 177 if (daddr < 0x80) { 178 switch (daddr) { 179 case GEN_CHANCOUNT: 180 assert(size == sizeof(regs.chanCount)); 181 pkt->set<uint8_t>(regs.chanCount); 182 break; 183 case GEN_XFERCAP: 184 assert(size == sizeof(regs.xferCap)); 185 pkt->set<uint8_t>(regs.xferCap); 186 break; 187 case GEN_INTRCTRL: 188 assert(size == sizeof(uint8_t)); 189 pkt->set<uint8_t>(regs.intrctrl()); 190 regs.intrctrl.master_int_enable(0); 191 break; 192 case GEN_ATTNSTATUS: 193 assert(size == sizeof(regs.attnStatus)); 194 pkt->set<uint32_t>(regs.attnStatus); 195 regs.attnStatus = 0; 196 break; 197 default: 198 panic("Read request to unknown register number: %#x\n", daddr); 199 } 200 pkt->makeAtomicResponse(); 201 return pioDelay; 202 } 203 204 205 // Find which channel we're accessing 206 int chanid = 0; 207 daddr -= 0x80; 208 while (daddr >= 0x80) { 209 chanid++; 210 daddr -= 0x80; 211 } 212 213 if (chanid >= regs.chanCount) 214 panic("Access to channel %d (device only configured for %d channels)", 215 chanid, regs.chanCount); 216 217 /// 218 /// Channel registers are handled here 219 /// 220 chan[chanid]->channelRead(pkt, daddr, size); 221 222 pkt->makeAtomicResponse(); 223 return pioDelay; 224} 225 226void 227CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size) 228{ 229 switch (daddr) { 230 case CHAN_CONTROL: 231 assert(size == sizeof(uint16_t)); 232 pkt->set<uint16_t>(cr.ctrl()); 233 cr.ctrl.in_use(1); 234 break; 235 case CHAN_STATUS: 236 assert(size == sizeof(uint64_t)); 237 pkt->set<uint64_t>(cr.status() | ~busy); 238 break; 239 case CHAN_CHAINADDR: 240 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 241 if (size == sizeof(uint64_t)) 242 pkt->set<uint64_t>(cr.descChainAddr); 243 else 244 pkt->set<uint32_t>(bits(cr.descChainAddr,0,31)); 245 break; 246 case CHAN_CHAINADDR_HIGH: 247 assert(size == sizeof(uint32_t)); 248 pkt->set<uint32_t>(bits(cr.descChainAddr,32,63)); 249 break; 250 case CHAN_COMMAND: 251 assert(size == sizeof(uint8_t)); 252 pkt->set<uint32_t>(cr.command()); 253 break; 254 case CHAN_CMPLNADDR: 255 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 256 if (size == sizeof(uint64_t)) 257 pkt->set<uint64_t>(cr.completionAddr); 258 else 259 pkt->set<uint32_t>(bits(cr.completionAddr,0,31)); 260 break; 261 case CHAN_CMPLNADDR_HIGH: 262 assert(size == sizeof(uint32_t)); 263 pkt->set<uint32_t>(bits(cr.completionAddr,32,63)); 264 break; 265 case CHAN_ERROR: 266 assert(size == sizeof(uint32_t)); 267 pkt->set<uint32_t>(cr.error()); 268 break; 269 default: 270 panic("Read request to unknown channel register number: (%d)%#x\n", 271 channelId, daddr); 272 } 273} 274 275 276Tick 277CopyEngine::write(PacketPtr pkt) 278{ 279 int bar; 280 Addr daddr; 281 282 283 if (!getBAR(pkt->getAddr(), bar, daddr)) 284 panic("Invalid PCI memory access to unmapped memory.\n"); 285 286 // Only Memory register BAR is allowed 287 assert(bar == 0); 288 289 int size = pkt->getSize(); 290 291 /// 292 /// Handle write of register here 293 /// 294 295 if (size == sizeof(uint64_t)) { 296 uint64_t val M5_VAR_USED = pkt->get<uint64_t>(); 297 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); 298 } else if (size == sizeof(uint32_t)) { 299 uint32_t val M5_VAR_USED = pkt->get<uint32_t>(); 300 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); 301 } else if (size == sizeof(uint16_t)) { 302 uint16_t val M5_VAR_USED = pkt->get<uint16_t>(); 303 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); 304 } else if (size == sizeof(uint8_t)) { 305 uint8_t val M5_VAR_USED = pkt->get<uint8_t>(); 306 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); 307 } else { 308 panic("Unknown size for MMIO access: %d\n", size); 309 } 310 311 if (daddr < 0x80) { 312 switch (daddr) { 313 case GEN_CHANCOUNT: 314 case GEN_XFERCAP: 315 case GEN_ATTNSTATUS: 316 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n", 317 daddr); 318 break; 319 case GEN_INTRCTRL: 320 regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1)); 321 break; 322 default: 323 panic("Read request to unknown register number: %#x\n", daddr); 324 } 325 pkt->makeAtomicResponse(); 326 return pioDelay; 327 } 328 329 // Find which channel we're accessing 330 int chanid = 0; 331 daddr -= 0x80; 332 while (daddr >= 0x80) { 333 chanid++; 334 daddr -= 0x80; 335 } 336 337 if (chanid >= regs.chanCount) 338 panic("Access to channel %d (device only configured for %d channels)", 339 chanid, regs.chanCount); 340 341 /// 342 /// Channel registers are handled here 343 /// 344 chan[chanid]->channelWrite(pkt, daddr, size); 345 346 pkt->makeAtomicResponse(); 347 return pioDelay; 348} 349 350void 351CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size) 352{ 353 switch (daddr) { 354 case CHAN_CONTROL: 355 assert(size == sizeof(uint16_t)); 356 int old_int_disable; 357 old_int_disable = cr.ctrl.interrupt_disable(); 358 cr.ctrl(pkt->get<uint16_t>()); 359 if (cr.ctrl.interrupt_disable()) 360 cr.ctrl.interrupt_disable(0); 361 else 362 cr.ctrl.interrupt_disable(old_int_disable); 363 break; 364 case CHAN_STATUS: 365 assert(size == sizeof(uint64_t)); 366 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n", 367 daddr); 368 break; 369 case CHAN_CHAINADDR: 370 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 371 if (size == sizeof(uint64_t)) 372 cr.descChainAddr = pkt->get<uint64_t>(); 373 else 374 cr.descChainAddr = (uint64_t)pkt->get<uint32_t>() | 375 (cr.descChainAddr & ~mask(32)); 376 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr); 377 break; 378 case CHAN_CHAINADDR_HIGH: 379 assert(size == sizeof(uint32_t)); 380 cr.descChainAddr = ((uint64_t)pkt->get<uint32_t>() <<32) | 381 (cr.descChainAddr & mask(32)); 382 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr); 383 break; 384 case CHAN_COMMAND: 385 assert(size == sizeof(uint8_t)); 386 cr.command(pkt->get<uint8_t>()); 387 recvCommand(); 388 break; 389 case CHAN_CMPLNADDR: 390 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 391 if (size == sizeof(uint64_t)) 392 cr.completionAddr = pkt->get<uint64_t>(); 393 else 394 cr.completionAddr = pkt->get<uint32_t>() | 395 (cr.completionAddr & ~mask(32)); 396 break; 397 case CHAN_CMPLNADDR_HIGH: 398 assert(size == sizeof(uint32_t)); 399 cr.completionAddr = ((uint64_t)pkt->get<uint32_t>() <<32) | 400 (cr.completionAddr & mask(32)); 401 break; 402 case CHAN_ERROR: 403 assert(size == sizeof(uint32_t)); 404 cr.error(~pkt->get<uint32_t>() & cr.error()); 405 break; 406 default: 407 panic("Read request to unknown channel register number: (%d)%#x\n", 408 channelId, daddr); 409 } 410} 411 412void 413CopyEngine::regStats() 414{ 415 using namespace Stats; 416 bytesCopied 417 .init(regs.chanCount) 418 .name(name() + ".bytes_copied") 419 .desc("Number of bytes copied by each engine") 420 .flags(total) 421 ; 422 copiesProcessed 423 .init(regs.chanCount) 424 .name(name() + ".copies_processed") 425 .desc("Number of copies processed by each engine") 426 .flags(total) 427 ; 428} 429 430void 431CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address) 432{ 433 anDq(); 434 anBegin("FetchDescriptor"); 435 DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n", 436 address, ce->platform->pciToDma(address)); 437 assert(address); 438 busy = true; 439 440 DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n", 441 ce->platform->pciToDma(address), sizeof(DmaDesc), curDmaDesc); 442 443 cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address), 444 sizeof(DmaDesc), &fetchCompleteEvent, (uint8_t*)curDmaDesc, 445 latBeforeBegin); 446 lastDescriptorAddr = address; 447} 448 449void 450CopyEngine::CopyEngineChannel::fetchDescComplete() 451{ 452 DPRINTF(DMACopyEngine, "Read of descriptor complete\n"); 453 454 if ((curDmaDesc->command & DESC_CTRL_NULL)) { 455 DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n"); 456 assert(!(curDmaDesc->command & DESC_CTRL_CP_STS)); 457 if (curDmaDesc->command & DESC_CTRL_CP_STS) { 458 panic("Shouldn't be able to get here\n"); 459 nextState = CompletionWrite; 460 if (inDrain()) return; 461 writeCompletionStatus(); 462 } else { 463 anBegin("Idle"); 464 anWait(); 465 busy = false; 466 nextState = Idle; 467 inDrain(); 468 } 469 return; 470 } 471 472 if (curDmaDesc->command & ~DESC_CTRL_CP_STS) 473 panic("Descriptor has flag other that completion status set\n"); 474 475 nextState = DMARead; 476 if (inDrain()) return; 477 readCopyBytes(); 478} 479 480void 481CopyEngine::CopyEngineChannel::readCopyBytes() 482{ 483 anBegin("ReadCopyBytes"); 484 DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n", 485 curDmaDesc->len, curDmaDesc->dest, 486 ce->platform->pciToDma(curDmaDesc->src)); 487 cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(curDmaDesc->src), 488 curDmaDesc->len, &readCompleteEvent, copyBuffer, 0); 489} 490 491void 492CopyEngine::CopyEngineChannel::readCopyBytesComplete() 493{ 494 DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n"); 495 496 nextState = DMAWrite; 497 if (inDrain()) return; 498 writeCopyBytes(); 499} 500 501void 502CopyEngine::CopyEngineChannel::writeCopyBytes() 503{ 504 anBegin("WriteCopyBytes"); 505 DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n", 506 curDmaDesc->len, curDmaDesc->dest, 507 ce->platform->pciToDma(curDmaDesc->dest)); 508 509 cePort->dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(curDmaDesc->dest), 510 curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0); 511 512 ce->bytesCopied[channelId] += curDmaDesc->len; 513 ce->copiesProcessed[channelId]++; 514} 515 516void 517CopyEngine::CopyEngineChannel::writeCopyBytesComplete() 518{ 519 DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n", 520 curDmaDesc->user1); 521 522 cr.status.compl_desc_addr(lastDescriptorAddr >> 6); 523 completionDataReg = cr.status() | 1; 524 525 anQ("DMAUsedDescQ", channelId, 1); 526 anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len); 527 if (curDmaDesc->command & DESC_CTRL_CP_STS) { 528 nextState = CompletionWrite; 529 if (inDrain()) return; 530 writeCompletionStatus(); 531 return; 532 } 533 534 continueProcessing(); 535} 536 537void 538CopyEngine::CopyEngineChannel::continueProcessing() 539{ 540 busy = false; 541 542 if (underReset) { 543 anBegin("Reset"); 544 anWait(); 545 underReset = false; 546 refreshNext = false; 547 busy = false; 548 nextState = Idle; 549 return; 550 } 551 552 if (curDmaDesc->next) { 553 nextState = DescriptorFetch; 554 fetchAddress = curDmaDesc->next; 555 if (inDrain()) return; 556 fetchDescriptor(curDmaDesc->next); 557 } else if (refreshNext) { 558 nextState = AddressFetch; 559 refreshNext = false; 560 if (inDrain()) return; 561 fetchNextAddr(lastDescriptorAddr); 562 } else { 563 inDrain(); 564 nextState = Idle; 565 anWait(); 566 anBegin("Idle"); 567 } 568} 569 570void 571CopyEngine::CopyEngineChannel::writeCompletionStatus() 572{ 573 anBegin("WriteCompletionStatus"); 574 DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n", 575 completionDataReg, cr.completionAddr, 576 ce->platform->pciToDma(cr.completionAddr)); 577 578 cePort->dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(cr.completionAddr), 579 sizeof(completionDataReg), &statusCompleteEvent, 580 (uint8_t*)&completionDataReg, latAfterCompletion); 581} 582 583void 584CopyEngine::CopyEngineChannel::writeStatusComplete() 585{ 586 DPRINTF(DMACopyEngine, "Writing completion status complete\n"); 587 continueProcessing(); 588} 589 590void 591CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address) 592{ 593 anBegin("FetchNextAddr"); 594 DPRINTF(DMACopyEngine, "Fetching next address...\n"); 595 busy = true; 596 cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address + 597 offsetof(DmaDesc, next)), sizeof(Addr), &addrCompleteEvent, 598 (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0); 599} 600 601void 602CopyEngine::CopyEngineChannel::fetchAddrComplete() 603{ 604 DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n", 605 curDmaDesc->next); 606 if (!curDmaDesc->next) { 607 DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n"); 608 busy = false; 609 nextState = Idle; 610 anWait(); 611 anBegin("Idle"); 612 inDrain(); 613 return; 614 } 615 nextState = DescriptorFetch; 616 fetchAddress = curDmaDesc->next; 617 if (inDrain()) return; 618 fetchDescriptor(curDmaDesc->next); 619} 620 621bool 622CopyEngine::CopyEngineChannel::inDrain() 623{ 624 if (ce->getState() == SimObject::Draining) { 625 DPRINTF(DMACopyEngine, "processing drain\n"); 626 assert(drainEvent); 627 drainEvent->process(); 628 drainEvent = NULL; 629 } 630 631 return ce->getState() != SimObject::Running; 632} 633 634unsigned int 635CopyEngine::CopyEngineChannel::drain(Event *de) 636{ 637 if (nextState == Idle || ce->getState() != SimObject::Running) 638 return 0; 639 unsigned int count = 1; 640 count += cePort->drain(de); 641 642 DPRINTF(DMACopyEngine, "unable to drain, returning %d\n", count); 643 drainEvent = de; 644 return count; 645} 646 647unsigned int 648CopyEngine::drain(Event *de) 649{ 650 unsigned int count; 651 count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de); 652 for (int x = 0;x < chan.size(); x++) 653 count += chan[x]->drain(de); 654 655 if (count) 656 changeState(Draining); 657 else 658 changeState(Drained); 659 660 DPRINTF(DMACopyEngine, "call to CopyEngine::drain() returning %d\n", count); 661 return count; 662} 663 664void 665CopyEngine::serialize(std::ostream &os) 666{ 667 PciDev::serialize(os); 668 regs.serialize(os); 669 for (int x =0; x < chan.size(); x++) { 670 nameOut(os, csprintf("%s.channel%d", name(), x)); 671 chan[x]->serialize(os); 672 } 673} 674 675void 676CopyEngine::unserialize(Checkpoint *cp, const std::string §ion) 677{ 678 PciDev::unserialize(cp, section); 679 regs.unserialize(cp, section); 680 for (int x = 0; x < chan.size(); x++) 681 chan[x]->unserialize(cp, csprintf("%s.channel%d", section, x)); 682} 683 684void 685CopyEngine::CopyEngineChannel::serialize(std::ostream &os) 686{ 687 SERIALIZE_SCALAR(channelId); 688 SERIALIZE_SCALAR(busy); 689 SERIALIZE_SCALAR(underReset); 690 SERIALIZE_SCALAR(refreshNext); 691 SERIALIZE_SCALAR(lastDescriptorAddr); 692 SERIALIZE_SCALAR(completionDataReg); 693 SERIALIZE_SCALAR(fetchAddress); 694 int nextState = this->nextState; 695 SERIALIZE_SCALAR(nextState); 696 arrayParamOut(os, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc)); 697 SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap); 698 cr.serialize(os); 699 700} 701void 702CopyEngine::CopyEngineChannel::unserialize(Checkpoint *cp, const std::string §ion) 703{ 704 UNSERIALIZE_SCALAR(channelId); 705 UNSERIALIZE_SCALAR(busy); 706 UNSERIALIZE_SCALAR(underReset); 707 UNSERIALIZE_SCALAR(refreshNext); 708 UNSERIALIZE_SCALAR(lastDescriptorAddr); 709 UNSERIALIZE_SCALAR(completionDataReg); 710 UNSERIALIZE_SCALAR(fetchAddress); 711 int nextState; 712 UNSERIALIZE_SCALAR(nextState); 713 this->nextState = (ChannelState)nextState; 714 arrayParamIn(cp, section, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc)); 715 UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap); 716 cr.unserialize(cp, section); 717 718} 719 720void 721CopyEngine::CopyEngineChannel::restartStateMachine() 722{ 723 switch(nextState) { 724 case AddressFetch: 725 fetchNextAddr(lastDescriptorAddr); 726 break; 727 case DescriptorFetch: 728 fetchDescriptor(fetchAddress); 729 break; 730 case DMARead: 731 readCopyBytes(); 732 break; 733 case DMAWrite: 734 writeCopyBytes(); 735 break; 736 case CompletionWrite: 737 writeCompletionStatus(); 738 break; 739 case Idle: 740 break; 741 default: 742 panic("Unknown state for CopyEngineChannel\n"); 743 } 744} 745 746void 747CopyEngine::resume() 748{ 749 SimObject::resume(); 750 for (int x = 0;x < chan.size(); x++) 751 chan[x]->resume(); 752} 753 754 755void 756CopyEngine::CopyEngineChannel::resume() 757{ 758 DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState); 759 restartStateMachine(); 760} 761 762CopyEngine * 763CopyEngineParams::create() 764{ 765 return new CopyEngine(this); 766} 767