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