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