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