copy_engine.cc revision 11202
16166Ssteve.reinhardt@amd.com/* 26166Ssteve.reinhardt@amd.com * Copyright (c) 2012 ARM Limited 36166Ssteve.reinhardt@amd.com * All rights reserved 46166Ssteve.reinhardt@amd.com * 56166Ssteve.reinhardt@amd.com * The license below extends only to copyright in the software and shall 66166Ssteve.reinhardt@amd.com * not be construed as granting a license to any other intellectual 76166Ssteve.reinhardt@amd.com * property including but not limited to intellectual property relating 86166Ssteve.reinhardt@amd.com * to a hardware implementation of the functionality of the software 96166Ssteve.reinhardt@amd.com * licensed hereunder. You may use the software subject to the license 106166Ssteve.reinhardt@amd.com * terms below provided that you ensure that this notice is replicated 116166Ssteve.reinhardt@amd.com * unmodified and in its entirety in all distributions of the software, 126166Ssteve.reinhardt@amd.com * modified or unmodified, in source code or in binary form. 136166Ssteve.reinhardt@amd.com * 146166Ssteve.reinhardt@amd.com * Copyright (c) 2008 The Regents of The University of Michigan 156166Ssteve.reinhardt@amd.com * All rights reserved. 166166Ssteve.reinhardt@amd.com * 176166Ssteve.reinhardt@amd.com * Redistribution and use in source and binary forms, with or without 186166Ssteve.reinhardt@amd.com * modification, are permitted provided that the following conditions are 196166Ssteve.reinhardt@amd.com * met: redistributions of source code must retain the above copyright 206166Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer; 216166Ssteve.reinhardt@amd.com * redistributions in binary form must reproduce the above copyright 226166Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer in the 236166Ssteve.reinhardt@amd.com * documentation and/or other materials provided with the distribution; 246166Ssteve.reinhardt@amd.com * neither the name of the copyright holders nor the names of its 256166Ssteve.reinhardt@amd.com * contributors may be used to endorse or promote products derived from 266166Ssteve.reinhardt@amd.com * this software without specific prior written permission. 276166Ssteve.reinhardt@amd.com * 286166Ssteve.reinhardt@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 296166Ssteve.reinhardt@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 306166Ssteve.reinhardt@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 316928SBrad.Beckmann@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 326928SBrad.Beckmann@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 336928SBrad.Beckmann@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 346166Ssteve.reinhardt@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3511670Sandreas.hansson@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 366928SBrad.Beckmann@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3711670Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3811682Sandreas.hansson@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 396928SBrad.Beckmann@amd.com * 406928SBrad.Beckmann@amd.com * Authors: Ali Saidi 418920Snilay@cs.wisc.edu */ 426928SBrad.Beckmann@amd.com 437570SBrad.Beckmann@amd.com/* @file 447570SBrad.Beckmann@amd.com * Device model for Intel's I/O AT DMA copy engine. 456928SBrad.Beckmann@amd.com */ 466928SBrad.Beckmann@amd.com 476928SBrad.Beckmann@amd.com#include <algorithm> 487570SBrad.Beckmann@amd.com 497570SBrad.Beckmann@amd.com#include "base/cp_annotate.hh" 507570SBrad.Beckmann@amd.com#include "base/trace.hh" 517570SBrad.Beckmann@amd.com#include "debug/DMACopyEngine.hh" 527570SBrad.Beckmann@amd.com#include "debug/Drain.hh" 537570SBrad.Beckmann@amd.com#include "dev/copy_engine.hh" 547570SBrad.Beckmann@amd.com#include "mem/packet.hh" 557570SBrad.Beckmann@amd.com#include "mem/packet_access.hh" 567570SBrad.Beckmann@amd.com#include "params/CopyEngine.hh" 577570SBrad.Beckmann@amd.com#include "sim/stats.hh" 587570SBrad.Beckmann@amd.com#include "sim/system.hh" 597570SBrad.Beckmann@amd.com 607570SBrad.Beckmann@amd.comusing namespace CopyEngineReg; 616928SBrad.Beckmann@amd.com 626928SBrad.Beckmann@amd.comCopyEngine::CopyEngine(const Params *p) 6310524Snilay@cs.wisc.edu : PciDevice(p) 6410524Snilay@cs.wisc.edu{ 656289Snate@binkert.org // All Reg regs are initialized to 0 by default 669827Sakash.bagdia@arm.com regs.chanCount = p->ChanCnt; 679827Sakash.bagdia@arm.com regs.xferCap = findMsbSet(p->XferCap); 689827Sakash.bagdia@arm.com regs.attnStatus = 0; 699827Sakash.bagdia@arm.com 709793Sakash.bagdia@arm.com if (regs.chanCount > 64) 719793Sakash.bagdia@arm.com fatal("CopyEngine interface doesn't support more than 64 DMA engines\n"); 729793Sakash.bagdia@arm.com 739827Sakash.bagdia@arm.com for (int x = 0; x < regs.chanCount; x++) { 749827Sakash.bagdia@arm.com CopyEngineChannel *ch = new CopyEngineChannel(this, x); 756928SBrad.Beckmann@amd.com chan.push_back(ch); 769826Sandreas.hansson@arm.com } 7710519Snilay@cs.wisc.edu} 786928SBrad.Beckmann@amd.com 799793Sakash.bagdia@arm.com 809827Sakash.bagdia@arm.comCopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid) 819827Sakash.bagdia@arm.com : cePort(_ce, _ce->sys), 829793Sakash.bagdia@arm.com ce(_ce), channelId(cid), busy(false), underReset(false), 8310120Snilay@cs.wisc.edu refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin), 846928SBrad.Beckmann@amd.com latAfterCompletion(ce->params()->latAfterCompletion), 858876Sandreas.hansson@arm.com completionDataReg(0), nextState(Idle), 868876Sandreas.hansson@arm.com fetchCompleteEvent(this), addrCompleteEvent(this), 878876Sandreas.hansson@arm.com readCompleteEvent(this), writeCompleteEvent(this), 886928SBrad.Beckmann@amd.com statusCompleteEvent(this) 896928SBrad.Beckmann@amd.com 906928SBrad.Beckmann@amd.com{ 916928SBrad.Beckmann@amd.com cr.status.dma_transfer_status(3); 9210120Snilay@cs.wisc.edu cr.descChainAddr = 0; 936928SBrad.Beckmann@amd.com cr.completionAddr = 0; 946928SBrad.Beckmann@amd.com 956928SBrad.Beckmann@amd.com curDmaDesc = new DmaDesc; 966928SBrad.Beckmann@amd.com memset(curDmaDesc, 0, sizeof(DmaDesc)); 976166Ssteve.reinhardt@amd.com copyBuffer = new uint8_t[ce->params()->XferCap]; 988801Sgblack@eecs.umich.edu} 996928SBrad.Beckmann@amd.com 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 113BaseMasterPort & 114CopyEngine::getMasterPort(const std::string &if_name, PortID idx) 115{ 116 if (if_name != "dma") { 117 // pass it along to our super class 118 return PciDevice::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 129BaseMasterPort & 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->drainState() == DrainState::Running) 144 fetchDescriptor(cr.descChainAddr); 145 } else if (cr.command.append_dma()) { 146 if (!busy) { 147 nextState = AddressFetch; 148 if (ce->drainState() == DrainState::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 /// 186 /// Handle read of register here 187 /// 188 189 if (daddr < 0x80) { 190 switch (daddr) { 191 case GEN_CHANCOUNT: 192 assert(size == sizeof(regs.chanCount)); 193 pkt->set<uint8_t>(regs.chanCount); 194 break; 195 case GEN_XFERCAP: 196 assert(size == sizeof(regs.xferCap)); 197 pkt->set<uint8_t>(regs.xferCap); 198 break; 199 case GEN_INTRCTRL: 200 assert(size == sizeof(uint8_t)); 201 pkt->set<uint8_t>(regs.intrctrl()); 202 regs.intrctrl.master_int_enable(0); 203 break; 204 case GEN_ATTNSTATUS: 205 assert(size == sizeof(regs.attnStatus)); 206 pkt->set<uint32_t>(regs.attnStatus); 207 regs.attnStatus = 0; 208 break; 209 default: 210 panic("Read request to unknown register number: %#x\n", daddr); 211 } 212 pkt->makeAtomicResponse(); 213 return pioDelay; 214 } 215 216 217 // Find which channel we're accessing 218 int chanid = 0; 219 daddr -= 0x80; 220 while (daddr >= 0x80) { 221 chanid++; 222 daddr -= 0x80; 223 } 224 225 if (chanid >= regs.chanCount) 226 panic("Access to channel %d (device only configured for %d channels)", 227 chanid, regs.chanCount); 228 229 /// 230 /// Channel registers are handled here 231 /// 232 chan[chanid]->channelRead(pkt, daddr, size); 233 234 pkt->makeAtomicResponse(); 235 return pioDelay; 236} 237 238void 239CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size) 240{ 241 switch (daddr) { 242 case CHAN_CONTROL: 243 assert(size == sizeof(uint16_t)); 244 pkt->set<uint16_t>(cr.ctrl()); 245 cr.ctrl.in_use(1); 246 break; 247 case CHAN_STATUS: 248 assert(size == sizeof(uint64_t)); 249 pkt->set<uint64_t>(cr.status() | ~busy); 250 break; 251 case CHAN_CHAINADDR: 252 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 253 if (size == sizeof(uint64_t)) 254 pkt->set<uint64_t>(cr.descChainAddr); 255 else 256 pkt->set<uint32_t>(bits(cr.descChainAddr,0,31)); 257 break; 258 case CHAN_CHAINADDR_HIGH: 259 assert(size == sizeof(uint32_t)); 260 pkt->set<uint32_t>(bits(cr.descChainAddr,32,63)); 261 break; 262 case CHAN_COMMAND: 263 assert(size == sizeof(uint8_t)); 264 pkt->set<uint32_t>(cr.command()); 265 break; 266 case CHAN_CMPLNADDR: 267 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 268 if (size == sizeof(uint64_t)) 269 pkt->set<uint64_t>(cr.completionAddr); 270 else 271 pkt->set<uint32_t>(bits(cr.completionAddr,0,31)); 272 break; 273 case CHAN_CMPLNADDR_HIGH: 274 assert(size == sizeof(uint32_t)); 275 pkt->set<uint32_t>(bits(cr.completionAddr,32,63)); 276 break; 277 case CHAN_ERROR: 278 assert(size == sizeof(uint32_t)); 279 pkt->set<uint32_t>(cr.error()); 280 break; 281 default: 282 panic("Read request to unknown channel register number: (%d)%#x\n", 283 channelId, daddr); 284 } 285} 286 287 288Tick 289CopyEngine::write(PacketPtr pkt) 290{ 291 int bar; 292 Addr daddr; 293 294 295 if (!getBAR(pkt->getAddr(), bar, daddr)) 296 panic("Invalid PCI memory access to unmapped memory.\n"); 297 298 // Only Memory register BAR is allowed 299 assert(bar == 0); 300 301 int size = pkt->getSize(); 302 303 /// 304 /// Handle write of register here 305 /// 306 307 if (size == sizeof(uint64_t)) { 308 uint64_t val M5_VAR_USED = pkt->get<uint64_t>(); 309 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); 310 } else if (size == sizeof(uint32_t)) { 311 uint32_t val M5_VAR_USED = pkt->get<uint32_t>(); 312 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); 313 } else if (size == sizeof(uint16_t)) { 314 uint16_t val M5_VAR_USED = pkt->get<uint16_t>(); 315 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); 316 } else if (size == sizeof(uint8_t)) { 317 uint8_t val M5_VAR_USED = pkt->get<uint8_t>(); 318 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); 319 } else { 320 panic("Unknown size for MMIO access: %d\n", size); 321 } 322 323 if (daddr < 0x80) { 324 switch (daddr) { 325 case GEN_CHANCOUNT: 326 case GEN_XFERCAP: 327 case GEN_ATTNSTATUS: 328 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n", 329 daddr); 330 break; 331 case GEN_INTRCTRL: 332 regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1)); 333 break; 334 default: 335 panic("Read request to unknown register number: %#x\n", daddr); 336 } 337 pkt->makeAtomicResponse(); 338 return pioDelay; 339 } 340 341 // Find which channel we're accessing 342 int chanid = 0; 343 daddr -= 0x80; 344 while (daddr >= 0x80) { 345 chanid++; 346 daddr -= 0x80; 347 } 348 349 if (chanid >= regs.chanCount) 350 panic("Access to channel %d (device only configured for %d channels)", 351 chanid, regs.chanCount); 352 353 /// 354 /// Channel registers are handled here 355 /// 356 chan[chanid]->channelWrite(pkt, daddr, size); 357 358 pkt->makeAtomicResponse(); 359 return pioDelay; 360} 361 362void 363CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size) 364{ 365 switch (daddr) { 366 case CHAN_CONTROL: 367 assert(size == sizeof(uint16_t)); 368 int old_int_disable; 369 old_int_disable = cr.ctrl.interrupt_disable(); 370 cr.ctrl(pkt->get<uint16_t>()); 371 if (cr.ctrl.interrupt_disable()) 372 cr.ctrl.interrupt_disable(0); 373 else 374 cr.ctrl.interrupt_disable(old_int_disable); 375 break; 376 case CHAN_STATUS: 377 assert(size == sizeof(uint64_t)); 378 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n", 379 daddr); 380 break; 381 case CHAN_CHAINADDR: 382 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 383 if (size == sizeof(uint64_t)) 384 cr.descChainAddr = pkt->get<uint64_t>(); 385 else 386 cr.descChainAddr = (uint64_t)pkt->get<uint32_t>() | 387 (cr.descChainAddr & ~mask(32)); 388 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr); 389 break; 390 case CHAN_CHAINADDR_HIGH: 391 assert(size == sizeof(uint32_t)); 392 cr.descChainAddr = ((uint64_t)pkt->get<uint32_t>() <<32) | 393 (cr.descChainAddr & mask(32)); 394 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr); 395 break; 396 case CHAN_COMMAND: 397 assert(size == sizeof(uint8_t)); 398 cr.command(pkt->get<uint8_t>()); 399 recvCommand(); 400 break; 401 case CHAN_CMPLNADDR: 402 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 403 if (size == sizeof(uint64_t)) 404 cr.completionAddr = pkt->get<uint64_t>(); 405 else 406 cr.completionAddr = pkt->get<uint32_t>() | 407 (cr.completionAddr & ~mask(32)); 408 break; 409 case CHAN_CMPLNADDR_HIGH: 410 assert(size == sizeof(uint32_t)); 411 cr.completionAddr = ((uint64_t)pkt->get<uint32_t>() <<32) | 412 (cr.completionAddr & mask(32)); 413 break; 414 case CHAN_ERROR: 415 assert(size == sizeof(uint32_t)); 416 cr.error(~pkt->get<uint32_t>() & cr.error()); 417 break; 418 default: 419 panic("Read request to unknown channel register number: (%d)%#x\n", 420 channelId, daddr); 421 } 422} 423 424void 425CopyEngine::regStats() 426{ 427 using namespace Stats; 428 bytesCopied 429 .init(regs.chanCount) 430 .name(name() + ".bytes_copied") 431 .desc("Number of bytes copied by each engine") 432 .flags(total) 433 ; 434 copiesProcessed 435 .init(regs.chanCount) 436 .name(name() + ".copies_processed") 437 .desc("Number of copies processed by each engine") 438 .flags(total) 439 ; 440} 441 442void 443CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address) 444{ 445 anDq(); 446 anBegin("FetchDescriptor"); 447 DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n", 448 address, ce->pciToDma(address)); 449 assert(address); 450 busy = true; 451 452 DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n", 453 ce->pciToDma(address), sizeof(DmaDesc), curDmaDesc); 454 455 cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(address), 456 sizeof(DmaDesc), &fetchCompleteEvent, 457 (uint8_t*)curDmaDesc, latBeforeBegin); 458 lastDescriptorAddr = address; 459} 460 461void 462CopyEngine::CopyEngineChannel::fetchDescComplete() 463{ 464 DPRINTF(DMACopyEngine, "Read of descriptor complete\n"); 465 466 if ((curDmaDesc->command & DESC_CTRL_NULL)) { 467 DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n"); 468 assert(!(curDmaDesc->command & DESC_CTRL_CP_STS)); 469 if (curDmaDesc->command & DESC_CTRL_CP_STS) { 470 panic("Shouldn't be able to get here\n"); 471 nextState = CompletionWrite; 472 if (inDrain()) return; 473 writeCompletionStatus(); 474 } else { 475 anBegin("Idle"); 476 anWait(); 477 busy = false; 478 nextState = Idle; 479 inDrain(); 480 } 481 return; 482 } 483 484 if (curDmaDesc->command & ~DESC_CTRL_CP_STS) 485 panic("Descriptor has flag other that completion status set\n"); 486 487 nextState = DMARead; 488 if (inDrain()) return; 489 readCopyBytes(); 490} 491 492void 493CopyEngine::CopyEngineChannel::readCopyBytes() 494{ 495 anBegin("ReadCopyBytes"); 496 DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n", 497 curDmaDesc->len, curDmaDesc->dest, 498 ce->pciToDma(curDmaDesc->src)); 499 cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(curDmaDesc->src), 500 curDmaDesc->len, &readCompleteEvent, copyBuffer, 0); 501} 502 503void 504CopyEngine::CopyEngineChannel::readCopyBytesComplete() 505{ 506 DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n"); 507 508 nextState = DMAWrite; 509 if (inDrain()) return; 510 writeCopyBytes(); 511} 512 513void 514CopyEngine::CopyEngineChannel::writeCopyBytes() 515{ 516 anBegin("WriteCopyBytes"); 517 DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n", 518 curDmaDesc->len, curDmaDesc->dest, 519 ce->pciToDma(curDmaDesc->dest)); 520 521 cePort.dmaAction(MemCmd::WriteReq, ce->pciToDma(curDmaDesc->dest), 522 curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0); 523 524 ce->bytesCopied[channelId] += curDmaDesc->len; 525 ce->copiesProcessed[channelId]++; 526} 527 528void 529CopyEngine::CopyEngineChannel::writeCopyBytesComplete() 530{ 531 DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n", 532 curDmaDesc->user1); 533 534 cr.status.compl_desc_addr(lastDescriptorAddr >> 6); 535 completionDataReg = cr.status() | 1; 536 537 anQ("DMAUsedDescQ", channelId, 1); 538 anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len); 539 if (curDmaDesc->command & DESC_CTRL_CP_STS) { 540 nextState = CompletionWrite; 541 if (inDrain()) return; 542 writeCompletionStatus(); 543 return; 544 } 545 546 continueProcessing(); 547} 548 549void 550CopyEngine::CopyEngineChannel::continueProcessing() 551{ 552 busy = false; 553 554 if (underReset) { 555 anBegin("Reset"); 556 anWait(); 557 underReset = false; 558 refreshNext = false; 559 busy = false; 560 nextState = Idle; 561 return; 562 } 563 564 if (curDmaDesc->next) { 565 nextState = DescriptorFetch; 566 fetchAddress = curDmaDesc->next; 567 if (inDrain()) return; 568 fetchDescriptor(curDmaDesc->next); 569 } else if (refreshNext) { 570 nextState = AddressFetch; 571 refreshNext = false; 572 if (inDrain()) return; 573 fetchNextAddr(lastDescriptorAddr); 574 } else { 575 inDrain(); 576 nextState = Idle; 577 anWait(); 578 anBegin("Idle"); 579 } 580} 581 582void 583CopyEngine::CopyEngineChannel::writeCompletionStatus() 584{ 585 anBegin("WriteCompletionStatus"); 586 DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n", 587 completionDataReg, cr.completionAddr, 588 ce->pciToDma(cr.completionAddr)); 589 590 cePort.dmaAction(MemCmd::WriteReq, 591 ce->pciToDma(cr.completionAddr), 592 sizeof(completionDataReg), &statusCompleteEvent, 593 (uint8_t*)&completionDataReg, latAfterCompletion); 594} 595 596void 597CopyEngine::CopyEngineChannel::writeStatusComplete() 598{ 599 DPRINTF(DMACopyEngine, "Writing completion status complete\n"); 600 continueProcessing(); 601} 602 603void 604CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address) 605{ 606 anBegin("FetchNextAddr"); 607 DPRINTF(DMACopyEngine, "Fetching next address...\n"); 608 busy = true; 609 cePort.dmaAction(MemCmd::ReadReq, 610 ce->pciToDma(address + offsetof(DmaDesc, next)), 611 sizeof(Addr), &addrCompleteEvent, 612 (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0); 613} 614 615void 616CopyEngine::CopyEngineChannel::fetchAddrComplete() 617{ 618 DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n", 619 curDmaDesc->next); 620 if (!curDmaDesc->next) { 621 DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n"); 622 busy = false; 623 nextState = Idle; 624 anWait(); 625 anBegin("Idle"); 626 inDrain(); 627 return; 628 } 629 nextState = DescriptorFetch; 630 fetchAddress = curDmaDesc->next; 631 if (inDrain()) return; 632 fetchDescriptor(curDmaDesc->next); 633} 634 635bool 636CopyEngine::CopyEngineChannel::inDrain() 637{ 638 if (drainState() == DrainState::Draining) { 639 DPRINTF(Drain, "CopyEngine done draining, processing drain event\n"); 640 signalDrainDone(); 641 } 642 643 return ce->drainState() != DrainState::Running; 644} 645 646DrainState 647CopyEngine::CopyEngineChannel::drain() 648{ 649 if (nextState == Idle || ce->drainState() != DrainState::Running) { 650 return DrainState::Drained; 651 } else { 652 DPRINTF(Drain, "CopyEngineChannel not drained\n"); 653 return DrainState::Draining; 654 } 655} 656 657void 658CopyEngine::serialize(CheckpointOut &cp) const 659{ 660 PciDevice::serialize(cp); 661 regs.serialize(cp); 662 for (int x =0; x < chan.size(); x++) 663 chan[x]->serializeSection(cp, csprintf("channel%d", x)); 664} 665 666void 667CopyEngine::unserialize(CheckpointIn &cp) 668{ 669 PciDevice::unserialize(cp); 670 regs.unserialize(cp); 671 for (int x = 0; x < chan.size(); x++) 672 chan[x]->unserializeSection(cp, csprintf("channel%d", x)); 673} 674 675void 676CopyEngine::CopyEngineChannel::serialize(CheckpointOut &cp) const 677{ 678 SERIALIZE_SCALAR(channelId); 679 SERIALIZE_SCALAR(busy); 680 SERIALIZE_SCALAR(underReset); 681 SERIALIZE_SCALAR(refreshNext); 682 SERIALIZE_SCALAR(lastDescriptorAddr); 683 SERIALIZE_SCALAR(completionDataReg); 684 SERIALIZE_SCALAR(fetchAddress); 685 int nextState = this->nextState; 686 SERIALIZE_SCALAR(nextState); 687 arrayParamOut(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc)); 688 SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap); 689 cr.serialize(cp); 690 691} 692void 693CopyEngine::CopyEngineChannel::unserialize(CheckpointIn &cp) 694{ 695 UNSERIALIZE_SCALAR(channelId); 696 UNSERIALIZE_SCALAR(busy); 697 UNSERIALIZE_SCALAR(underReset); 698 UNSERIALIZE_SCALAR(refreshNext); 699 UNSERIALIZE_SCALAR(lastDescriptorAddr); 700 UNSERIALIZE_SCALAR(completionDataReg); 701 UNSERIALIZE_SCALAR(fetchAddress); 702 int nextState; 703 UNSERIALIZE_SCALAR(nextState); 704 this->nextState = (ChannelState)nextState; 705 arrayParamIn(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc)); 706 UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap); 707 cr.unserialize(cp); 708 709} 710 711void 712CopyEngine::CopyEngineChannel::restartStateMachine() 713{ 714 switch(nextState) { 715 case AddressFetch: 716 fetchNextAddr(lastDescriptorAddr); 717 break; 718 case DescriptorFetch: 719 fetchDescriptor(fetchAddress); 720 break; 721 case DMARead: 722 readCopyBytes(); 723 break; 724 case DMAWrite: 725 writeCopyBytes(); 726 break; 727 case CompletionWrite: 728 writeCompletionStatus(); 729 break; 730 case Idle: 731 break; 732 default: 733 panic("Unknown state for CopyEngineChannel\n"); 734 } 735} 736 737void 738CopyEngine::CopyEngineChannel::drainResume() 739{ 740 DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState); 741 restartStateMachine(); 742} 743 744CopyEngine * 745CopyEngineParams::create() 746{ 747 return new CopyEngine(this); 748} 749