copy_engine.cc revision 13784
19983Sstever@gmail.com/* 29983Sstever@gmail.com * Copyright (c) 2012 ARM Limited 39983Sstever@gmail.com * All rights reserved 49983Sstever@gmail.com * 59983Sstever@gmail.com * The license below extends only to copyright in the software and shall 69983Sstever@gmail.com * not be construed as granting a license to any other intellectual 79983Sstever@gmail.com * property including but not limited to intellectual property relating 89983Sstever@gmail.com * to a hardware implementation of the functionality of the software 99983Sstever@gmail.com * licensed hereunder. You may use the software subject to the license 109983Sstever@gmail.com * terms below provided that you ensure that this notice is replicated 119983Sstever@gmail.com * unmodified and in its entirety in all distributions of the software, 129983Sstever@gmail.com * modified or unmodified, in source code or in binary form. 139983Sstever@gmail.com * 149983Sstever@gmail.com * Copyright (c) 2008 The Regents of The University of Michigan 159983Sstever@gmail.com * All rights reserved. 169983Sstever@gmail.com * 179983Sstever@gmail.com * Redistribution and use in source and binary forms, with or without 189983Sstever@gmail.com * modification, are permitted provided that the following conditions are 199983Sstever@gmail.com * met: redistributions of source code must retain the above copyright 209983Sstever@gmail.com * notice, this list of conditions and the following disclaimer; 219983Sstever@gmail.com * redistributions in binary form must reproduce the above copyright 229983Sstever@gmail.com * notice, this list of conditions and the following disclaimer in the 239983Sstever@gmail.com * documentation and/or other materials provided with the distribution; 249983Sstever@gmail.com * neither the name of the copyright holders nor the names of its 259983Sstever@gmail.com * contributors may be used to endorse or promote products derived from 269983Sstever@gmail.com * this software without specific prior written permission. 279983Sstever@gmail.com * 289983Sstever@gmail.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 299983Sstever@gmail.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 309983Sstever@gmail.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 319983Sstever@gmail.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 329983Sstever@gmail.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 339983Sstever@gmail.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 349983Sstever@gmail.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 359983Sstever@gmail.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 369983Sstever@gmail.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 379983Sstever@gmail.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 389983Sstever@gmail.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 399983Sstever@gmail.com * 409983Sstever@gmail.com * Authors: Ali Saidi 419983Sstever@gmail.com */ 429983Sstever@gmail.com 439983Sstever@gmail.com/* @file 449983Sstever@gmail.com * Device model for Intel's I/O AT DMA copy engine. 459983Sstever@gmail.com */ 469983Sstever@gmail.com 479983Sstever@gmail.com#include "dev/pci/copy_engine.hh" 489983Sstever@gmail.com 499983Sstever@gmail.com#include <algorithm> 509983Sstever@gmail.com 519983Sstever@gmail.com#include "base/cp_annotate.hh" 529983Sstever@gmail.com#include "base/trace.hh" 539983Sstever@gmail.com#include "debug/DMACopyEngine.hh" 549983Sstever@gmail.com#include "debug/Drain.hh" 559983Sstever@gmail.com#include "mem/packet.hh" 569983Sstever@gmail.com#include "mem/packet_access.hh" 579983Sstever@gmail.com#include "params/CopyEngine.hh" 589983Sstever@gmail.com#include "sim/stats.hh" 599983Sstever@gmail.com#include "sim/system.hh" 609983Sstever@gmail.com 619983Sstever@gmail.comusing namespace CopyEngineReg; 629983Sstever@gmail.com 639983Sstever@gmail.comCopyEngine::CopyEngine(const Params *p) 649983Sstever@gmail.com : PciDevice(p) 659983Sstever@gmail.com{ 669983Sstever@gmail.com // All Reg regs are initialized to 0 by default 679983Sstever@gmail.com regs.chanCount = p->ChanCnt; 689983Sstever@gmail.com regs.xferCap = findMsbSet(p->XferCap); 699983Sstever@gmail.com regs.attnStatus = 0; 709983Sstever@gmail.com 719983Sstever@gmail.com if (regs.chanCount > 64) 729983Sstever@gmail.com fatal("CopyEngine interface doesn't support more than 64 DMA engines\n"); 739983Sstever@gmail.com 749983Sstever@gmail.com for (int x = 0; x < regs.chanCount; x++) { 759983Sstever@gmail.com CopyEngineChannel *ch = new CopyEngineChannel(this, x); 769983Sstever@gmail.com chan.push_back(ch); 779983Sstever@gmail.com } 789983Sstever@gmail.com} 799983Sstever@gmail.com 809983Sstever@gmail.com 819983Sstever@gmail.comCopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid) 829983Sstever@gmail.com : cePort(_ce, _ce->sys), 839983Sstever@gmail.com ce(_ce), channelId(cid), busy(false), underReset(false), 849983Sstever@gmail.com refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin), 859983Sstever@gmail.com latAfterCompletion(ce->params()->latAfterCompletion), 869983Sstever@gmail.com completionDataReg(0), nextState(Idle), 879983Sstever@gmail.com fetchCompleteEvent([this]{ fetchDescComplete(); }, name()), 889983Sstever@gmail.com addrCompleteEvent([this]{ fetchAddrComplete(); }, name()), 899983Sstever@gmail.com readCompleteEvent([this]{ readCopyBytesComplete(); }, name()), 909983Sstever@gmail.com writeCompleteEvent([this]{ writeCopyBytesComplete(); }, name()), 919983Sstever@gmail.com statusCompleteEvent([this]{ writeStatusComplete(); }, name()) 929983Sstever@gmail.com 939983Sstever@gmail.com{ 9410153Sandreas@sandberg.pp.se cr.status.dma_transfer_status(3); 9510153Sandreas@sandberg.pp.se cr.descChainAddr = 0; 9610153Sandreas@sandberg.pp.se cr.completionAddr = 0; 9710153Sandreas@sandberg.pp.se 9810153Sandreas@sandberg.pp.se curDmaDesc = new DmaDesc; 9910153Sandreas@sandberg.pp.se memset(curDmaDesc, 0, sizeof(DmaDesc)); 10010153Sandreas@sandberg.pp.se copyBuffer = new uint8_t[ce->params()->XferCap]; 10110153Sandreas@sandberg.pp.se} 10210153Sandreas@sandberg.pp.se 10310361SAndreas.Sandberg@ARM.comCopyEngine::~CopyEngine() 1049983Sstever@gmail.com{ 1059983Sstever@gmail.com for (int x = 0; x < chan.size(); x++) { 1069983Sstever@gmail.com delete chan[x]; 1079983Sstever@gmail.com } 1089983Sstever@gmail.com} 1099983Sstever@gmail.com 1109983Sstever@gmail.comCopyEngine::CopyEngineChannel::~CopyEngineChannel() 1119983Sstever@gmail.com{ 11210361SAndreas.Sandberg@ARM.com delete curDmaDesc; 1139983Sstever@gmail.com delete [] copyBuffer; 1149983Sstever@gmail.com} 1159983Sstever@gmail.com 1169983Sstever@gmail.comPort & 1179983Sstever@gmail.comCopyEngine::getPort(const std::string &if_name, PortID idx) 1189983Sstever@gmail.com{ 1199983Sstever@gmail.com if (if_name != "dma") { 1209983Sstever@gmail.com // pass it along to our super class 1219983Sstever@gmail.com return PciDevice::getPort(if_name, idx); 1229983Sstever@gmail.com } else { 1239983Sstever@gmail.com if (idx >= static_cast<int>(chan.size())) { 1249983Sstever@gmail.com panic("CopyEngine::getPort: unknown index %d\n", idx); 1259983Sstever@gmail.com } 1269983Sstever@gmail.com 1279983Sstever@gmail.com return chan[idx]->getPort(); 1289983Sstever@gmail.com } 1299983Sstever@gmail.com} 1309983Sstever@gmail.com 1319983Sstever@gmail.com 1329983Sstever@gmail.comPort & 1339983Sstever@gmail.comCopyEngine::CopyEngineChannel::getPort() 1349983Sstever@gmail.com{ 1359983Sstever@gmail.com return cePort; 1369983Sstever@gmail.com} 1379983Sstever@gmail.com 1389983Sstever@gmail.comvoid 1399983Sstever@gmail.comCopyEngine::CopyEngineChannel::recvCommand() 1409983Sstever@gmail.com{ 1419983Sstever@gmail.com if (cr.command.start_dma()) { 1429983Sstever@gmail.com assert(!busy); 1439983Sstever@gmail.com cr.status.dma_transfer_status(0); 1449983Sstever@gmail.com nextState = DescriptorFetch; 1459983Sstever@gmail.com fetchAddress = cr.descChainAddr; 1469983Sstever@gmail.com if (ce->drainState() == DrainState::Running) 1479983Sstever@gmail.com fetchDescriptor(cr.descChainAddr); 1489983Sstever@gmail.com } else if (cr.command.append_dma()) { 1499983Sstever@gmail.com if (!busy) { 1509983Sstever@gmail.com nextState = AddressFetch; 1519983Sstever@gmail.com if (ce->drainState() == DrainState::Running) 1529983Sstever@gmail.com fetchNextAddr(lastDescriptorAddr); 1539983Sstever@gmail.com } else 1549983Sstever@gmail.com refreshNext = true; 1559983Sstever@gmail.com } else if (cr.command.reset_dma()) { 1569983Sstever@gmail.com if (busy) 1579983Sstever@gmail.com underReset = true; 1589983Sstever@gmail.com else { 1599983Sstever@gmail.com cr.status.dma_transfer_status(3); 1609983Sstever@gmail.com nextState = Idle; 1619983Sstever@gmail.com } 1629983Sstever@gmail.com } else if (cr.command.resume_dma() || cr.command.abort_dma() || 1639983Sstever@gmail.com cr.command.suspend_dma()) 1649983Sstever@gmail.com panic("Resume, Abort, and Suspend are not supported\n"); 1659983Sstever@gmail.com cr.command(0); 1669983Sstever@gmail.com} 1679983Sstever@gmail.com 1689983Sstever@gmail.comTick 1699983Sstever@gmail.comCopyEngine::read(PacketPtr pkt) 1709983Sstever@gmail.com{ 1719983Sstever@gmail.com int bar; 1729983Sstever@gmail.com Addr daddr; 1739983Sstever@gmail.com 1749983Sstever@gmail.com if (!getBAR(pkt->getAddr(), bar, daddr)) 1759983Sstever@gmail.com panic("Invalid PCI memory access to unmapped memory.\n"); 1769983Sstever@gmail.com 1779983Sstever@gmail.com // Only Memory register BAR is allowed 1789983Sstever@gmail.com assert(bar == 0); 1799983Sstever@gmail.com 1809983Sstever@gmail.com int size = pkt->getSize(); 1819983Sstever@gmail.com if (size != sizeof(uint64_t) && size != sizeof(uint32_t) && 1829983Sstever@gmail.com size != sizeof(uint16_t) && size != sizeof(uint8_t)) { 1839983Sstever@gmail.com panic("Unknown size for MMIO access: %d\n", pkt->getSize()); 1849983Sstever@gmail.com } 1859983Sstever@gmail.com 1869983Sstever@gmail.com DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size); 1879983Sstever@gmail.com 1889983Sstever@gmail.com /// 1899983Sstever@gmail.com /// Handle read of register here 1909983Sstever@gmail.com /// 1919983Sstever@gmail.com 1929983Sstever@gmail.com if (daddr < 0x80) { 1939983Sstever@gmail.com switch (daddr) { 1949983Sstever@gmail.com case GEN_CHANCOUNT: 1959983Sstever@gmail.com assert(size == sizeof(regs.chanCount)); 1969983Sstever@gmail.com pkt->setLE<uint8_t>(regs.chanCount); 1979983Sstever@gmail.com break; 1989983Sstever@gmail.com case GEN_XFERCAP: 1999983Sstever@gmail.com assert(size == sizeof(regs.xferCap)); 2009983Sstever@gmail.com pkt->setLE<uint8_t>(regs.xferCap); 2019983Sstever@gmail.com break; 2029983Sstever@gmail.com case GEN_INTRCTRL: 2039983Sstever@gmail.com assert(size == sizeof(uint8_t)); 2049983Sstever@gmail.com pkt->setLE<uint8_t>(regs.intrctrl()); 2059983Sstever@gmail.com regs.intrctrl.master_int_enable(0); 2069983Sstever@gmail.com break; 2079983Sstever@gmail.com case GEN_ATTNSTATUS: 2089983Sstever@gmail.com assert(size == sizeof(regs.attnStatus)); 2099983Sstever@gmail.com pkt->setLE<uint32_t>(regs.attnStatus); 2109983Sstever@gmail.com regs.attnStatus = 0; 2119983Sstever@gmail.com break; 2129983Sstever@gmail.com default: 2139983Sstever@gmail.com panic("Read request to unknown register number: %#x\n", daddr); 2149983Sstever@gmail.com } 2159983Sstever@gmail.com pkt->makeAtomicResponse(); 2169983Sstever@gmail.com return pioDelay; 2179983Sstever@gmail.com } 2189983Sstever@gmail.com 2199983Sstever@gmail.com 2209983Sstever@gmail.com // Find which channel we're accessing 2219983Sstever@gmail.com int chanid = 0; 22211290Sgabor.dozsa@arm.com daddr -= 0x80; 2239983Sstever@gmail.com while (daddr >= 0x80) { 2249983Sstever@gmail.com chanid++; 2259983Sstever@gmail.com daddr -= 0x80; 2269983Sstever@gmail.com } 2279983Sstever@gmail.com 2289983Sstever@gmail.com if (chanid >= regs.chanCount) 2299983Sstever@gmail.com panic("Access to channel %d (device only configured for %d channels)", 2309983Sstever@gmail.com chanid, regs.chanCount); 2319983Sstever@gmail.com 2329983Sstever@gmail.com /// 2339983Sstever@gmail.com /// Channel registers are handled here 2349983Sstever@gmail.com /// 2359983Sstever@gmail.com chan[chanid]->channelRead(pkt, daddr, size); 2369983Sstever@gmail.com 2379983Sstever@gmail.com pkt->makeAtomicResponse(); 2389983Sstever@gmail.com return pioDelay; 2399983Sstever@gmail.com} 240 241void 242CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size) 243{ 244 switch (daddr) { 245 case CHAN_CONTROL: 246 assert(size == sizeof(uint16_t)); 247 pkt->setLE<uint16_t>(cr.ctrl()); 248 cr.ctrl.in_use(1); 249 break; 250 case CHAN_STATUS: 251 assert(size == sizeof(uint64_t)); 252 pkt->setLE<uint64_t>(cr.status() | (busy ? 0 : 1)); 253 break; 254 case CHAN_CHAINADDR: 255 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 256 if (size == sizeof(uint64_t)) 257 pkt->setLE<uint64_t>(cr.descChainAddr); 258 else 259 pkt->setLE<uint32_t>(bits(cr.descChainAddr,0,31)); 260 break; 261 case CHAN_CHAINADDR_HIGH: 262 assert(size == sizeof(uint32_t)); 263 pkt->setLE<uint32_t>(bits(cr.descChainAddr,32,63)); 264 break; 265 case CHAN_COMMAND: 266 assert(size == sizeof(uint8_t)); 267 pkt->setLE<uint32_t>(cr.command()); 268 break; 269 case CHAN_CMPLNADDR: 270 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 271 if (size == sizeof(uint64_t)) 272 pkt->setLE<uint64_t>(cr.completionAddr); 273 else 274 pkt->setLE<uint32_t>(bits(cr.completionAddr,0,31)); 275 break; 276 case CHAN_CMPLNADDR_HIGH: 277 assert(size == sizeof(uint32_t)); 278 pkt->setLE<uint32_t>(bits(cr.completionAddr,32,63)); 279 break; 280 case CHAN_ERROR: 281 assert(size == sizeof(uint32_t)); 282 pkt->setLE<uint32_t>(cr.error()); 283 break; 284 default: 285 panic("Read request to unknown channel register number: (%d)%#x\n", 286 channelId, daddr); 287 } 288} 289 290 291Tick 292CopyEngine::write(PacketPtr pkt) 293{ 294 int bar; 295 Addr daddr; 296 297 298 if (!getBAR(pkt->getAddr(), bar, daddr)) 299 panic("Invalid PCI memory access to unmapped memory.\n"); 300 301 // Only Memory register BAR is allowed 302 assert(bar == 0); 303 304 int size = pkt->getSize(); 305 306 /// 307 /// Handle write of register here 308 /// 309 310 if (size == sizeof(uint64_t)) { 311 uint64_t val M5_VAR_USED = pkt->getLE<uint64_t>(); 312 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", 313 daddr, val); 314 } else if (size == sizeof(uint32_t)) { 315 uint32_t val M5_VAR_USED = pkt->getLE<uint32_t>(); 316 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", 317 daddr, val); 318 } else if (size == sizeof(uint16_t)) { 319 uint16_t val M5_VAR_USED = pkt->getLE<uint16_t>(); 320 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", 321 daddr, val); 322 } else if (size == sizeof(uint8_t)) { 323 uint8_t val M5_VAR_USED = pkt->getLE<uint8_t>(); 324 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", 325 daddr, val); 326 } else { 327 panic("Unknown size for MMIO access: %d\n", size); 328 } 329 330 if (daddr < 0x80) { 331 switch (daddr) { 332 case GEN_CHANCOUNT: 333 case GEN_XFERCAP: 334 case GEN_ATTNSTATUS: 335 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n", 336 daddr); 337 break; 338 case GEN_INTRCTRL: 339 regs.intrctrl.master_int_enable(bits(pkt->getLE<uint8_t>(), 0, 1)); 340 break; 341 default: 342 panic("Read request to unknown register number: %#x\n", daddr); 343 } 344 pkt->makeAtomicResponse(); 345 return pioDelay; 346 } 347 348 // Find which channel we're accessing 349 int chanid = 0; 350 daddr -= 0x80; 351 while (daddr >= 0x80) { 352 chanid++; 353 daddr -= 0x80; 354 } 355 356 if (chanid >= regs.chanCount) 357 panic("Access to channel %d (device only configured for %d channels)", 358 chanid, regs.chanCount); 359 360 /// 361 /// Channel registers are handled here 362 /// 363 chan[chanid]->channelWrite(pkt, daddr, size); 364 365 pkt->makeAtomicResponse(); 366 return pioDelay; 367} 368 369void 370CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size) 371{ 372 switch (daddr) { 373 case CHAN_CONTROL: 374 assert(size == sizeof(uint16_t)); 375 int old_int_disable; 376 old_int_disable = cr.ctrl.interrupt_disable(); 377 cr.ctrl(pkt->getLE<uint16_t>()); 378 if (cr.ctrl.interrupt_disable()) 379 cr.ctrl.interrupt_disable(0); 380 else 381 cr.ctrl.interrupt_disable(old_int_disable); 382 break; 383 case CHAN_STATUS: 384 assert(size == sizeof(uint64_t)); 385 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n", 386 daddr); 387 break; 388 case CHAN_CHAINADDR: 389 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 390 if (size == sizeof(uint64_t)) 391 cr.descChainAddr = pkt->getLE<uint64_t>(); 392 else 393 cr.descChainAddr = (uint64_t)pkt->getLE<uint32_t>() | 394 (cr.descChainAddr & ~mask(32)); 395 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr); 396 break; 397 case CHAN_CHAINADDR_HIGH: 398 assert(size == sizeof(uint32_t)); 399 cr.descChainAddr = ((uint64_t)pkt->getLE<uint32_t>() << 32) | 400 (cr.descChainAddr & mask(32)); 401 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr); 402 break; 403 case CHAN_COMMAND: 404 assert(size == sizeof(uint8_t)); 405 cr.command(pkt->getLE<uint8_t>()); 406 recvCommand(); 407 break; 408 case CHAN_CMPLNADDR: 409 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); 410 if (size == sizeof(uint64_t)) 411 cr.completionAddr = pkt->getLE<uint64_t>(); 412 else 413 cr.completionAddr = pkt->getLE<uint32_t>() | 414 (cr.completionAddr & ~mask(32)); 415 break; 416 case CHAN_CMPLNADDR_HIGH: 417 assert(size == sizeof(uint32_t)); 418 cr.completionAddr = ((uint64_t)pkt->getLE<uint32_t>() <<32) | 419 (cr.completionAddr & mask(32)); 420 break; 421 case CHAN_ERROR: 422 assert(size == sizeof(uint32_t)); 423 cr.error(~pkt->getLE<uint32_t>() & cr.error()); 424 break; 425 default: 426 panic("Read request to unknown channel register number: (%d)%#x\n", 427 channelId, daddr); 428 } 429} 430 431void 432CopyEngine::regStats() 433{ 434 PciDevice::regStats(); 435 436 using namespace Stats; 437 bytesCopied 438 .init(regs.chanCount) 439 .name(name() + ".bytes_copied") 440 .desc("Number of bytes copied by each engine") 441 .flags(total) 442 ; 443 copiesProcessed 444 .init(regs.chanCount) 445 .name(name() + ".copies_processed") 446 .desc("Number of copies processed by each engine") 447 .flags(total) 448 ; 449} 450 451void 452CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address) 453{ 454 anDq(); 455 anBegin("FetchDescriptor"); 456 DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n", 457 address, ce->pciToDma(address)); 458 assert(address); 459 busy = true; 460 461 DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n", 462 ce->pciToDma(address), sizeof(DmaDesc), curDmaDesc); 463 464 cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(address), 465 sizeof(DmaDesc), &fetchCompleteEvent, 466 (uint8_t*)curDmaDesc, latBeforeBegin); 467 lastDescriptorAddr = address; 468} 469 470void 471CopyEngine::CopyEngineChannel::fetchDescComplete() 472{ 473 DPRINTF(DMACopyEngine, "Read of descriptor complete\n"); 474 475 if ((curDmaDesc->command & DESC_CTRL_NULL)) { 476 DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n"); 477 assert(!(curDmaDesc->command & DESC_CTRL_CP_STS)); 478 if (curDmaDesc->command & DESC_CTRL_CP_STS) { 479 panic("Shouldn't be able to get here\n"); 480 nextState = CompletionWrite; 481 if (inDrain()) return; 482 writeCompletionStatus(); 483 } else { 484 anBegin("Idle"); 485 anWait(); 486 busy = false; 487 nextState = Idle; 488 inDrain(); 489 } 490 return; 491 } 492 493 if (curDmaDesc->command & ~DESC_CTRL_CP_STS) 494 panic("Descriptor has flag other that completion status set\n"); 495 496 nextState = DMARead; 497 if (inDrain()) return; 498 readCopyBytes(); 499} 500 501void 502CopyEngine::CopyEngineChannel::readCopyBytes() 503{ 504 anBegin("ReadCopyBytes"); 505 DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n", 506 curDmaDesc->len, curDmaDesc->dest, 507 ce->pciToDma(curDmaDesc->src)); 508 cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(curDmaDesc->src), 509 curDmaDesc->len, &readCompleteEvent, copyBuffer, 0); 510} 511 512void 513CopyEngine::CopyEngineChannel::readCopyBytesComplete() 514{ 515 DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n"); 516 517 nextState = DMAWrite; 518 if (inDrain()) return; 519 writeCopyBytes(); 520} 521 522void 523CopyEngine::CopyEngineChannel::writeCopyBytes() 524{ 525 anBegin("WriteCopyBytes"); 526 DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n", 527 curDmaDesc->len, curDmaDesc->dest, 528 ce->pciToDma(curDmaDesc->dest)); 529 530 cePort.dmaAction(MemCmd::WriteReq, ce->pciToDma(curDmaDesc->dest), 531 curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0); 532 533 ce->bytesCopied[channelId] += curDmaDesc->len; 534 ce->copiesProcessed[channelId]++; 535} 536 537void 538CopyEngine::CopyEngineChannel::writeCopyBytesComplete() 539{ 540 DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n", 541 curDmaDesc->user1); 542 543 cr.status.compl_desc_addr(lastDescriptorAddr >> 6); 544 completionDataReg = cr.status() | 1; 545 546 anQ("DMAUsedDescQ", channelId, 1); 547 anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len); 548 if (curDmaDesc->command & DESC_CTRL_CP_STS) { 549 nextState = CompletionWrite; 550 if (inDrain()) return; 551 writeCompletionStatus(); 552 return; 553 } 554 555 continueProcessing(); 556} 557 558void 559CopyEngine::CopyEngineChannel::continueProcessing() 560{ 561 busy = false; 562 563 if (underReset) { 564 anBegin("Reset"); 565 anWait(); 566 underReset = false; 567 refreshNext = false; 568 busy = false; 569 nextState = Idle; 570 return; 571 } 572 573 if (curDmaDesc->next) { 574 nextState = DescriptorFetch; 575 fetchAddress = curDmaDesc->next; 576 if (inDrain()) return; 577 fetchDescriptor(curDmaDesc->next); 578 } else if (refreshNext) { 579 nextState = AddressFetch; 580 refreshNext = false; 581 if (inDrain()) return; 582 fetchNextAddr(lastDescriptorAddr); 583 } else { 584 inDrain(); 585 nextState = Idle; 586 anWait(); 587 anBegin("Idle"); 588 } 589} 590 591void 592CopyEngine::CopyEngineChannel::writeCompletionStatus() 593{ 594 anBegin("WriteCompletionStatus"); 595 DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n", 596 completionDataReg, cr.completionAddr, 597 ce->pciToDma(cr.completionAddr)); 598 599 cePort.dmaAction(MemCmd::WriteReq, 600 ce->pciToDma(cr.completionAddr), 601 sizeof(completionDataReg), &statusCompleteEvent, 602 (uint8_t*)&completionDataReg, latAfterCompletion); 603} 604 605void 606CopyEngine::CopyEngineChannel::writeStatusComplete() 607{ 608 DPRINTF(DMACopyEngine, "Writing completion status complete\n"); 609 continueProcessing(); 610} 611 612void 613CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address) 614{ 615 anBegin("FetchNextAddr"); 616 DPRINTF(DMACopyEngine, "Fetching next address...\n"); 617 busy = true; 618 cePort.dmaAction(MemCmd::ReadReq, 619 ce->pciToDma(address + offsetof(DmaDesc, next)), 620 sizeof(Addr), &addrCompleteEvent, 621 (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0); 622} 623 624void 625CopyEngine::CopyEngineChannel::fetchAddrComplete() 626{ 627 DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n", 628 curDmaDesc->next); 629 if (!curDmaDesc->next) { 630 DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n"); 631 busy = false; 632 nextState = Idle; 633 anWait(); 634 anBegin("Idle"); 635 inDrain(); 636 return; 637 } 638 nextState = DescriptorFetch; 639 fetchAddress = curDmaDesc->next; 640 if (inDrain()) return; 641 fetchDescriptor(curDmaDesc->next); 642} 643 644bool 645CopyEngine::CopyEngineChannel::inDrain() 646{ 647 if (drainState() == DrainState::Draining) { 648 DPRINTF(Drain, "CopyEngine done draining, processing drain event\n"); 649 signalDrainDone(); 650 } 651 652 return ce->drainState() != DrainState::Running; 653} 654 655DrainState 656CopyEngine::CopyEngineChannel::drain() 657{ 658 if (nextState == Idle || ce->drainState() != DrainState::Running) { 659 return DrainState::Drained; 660 } else { 661 DPRINTF(Drain, "CopyEngineChannel not drained\n"); 662 return DrainState::Draining; 663 } 664} 665 666void 667CopyEngine::serialize(CheckpointOut &cp) const 668{ 669 PciDevice::serialize(cp); 670 regs.serialize(cp); 671 for (int x =0; x < chan.size(); x++) 672 chan[x]->serializeSection(cp, csprintf("channel%d", x)); 673} 674 675void 676CopyEngine::unserialize(CheckpointIn &cp) 677{ 678 PciDevice::unserialize(cp); 679 regs.unserialize(cp); 680 for (int x = 0; x < chan.size(); x++) 681 chan[x]->unserializeSection(cp, csprintf("channel%d", x)); 682} 683 684void 685CopyEngine::CopyEngineChannel::serialize(CheckpointOut &cp) const 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(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc)); 697 SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap); 698 cr.serialize(cp); 699 700} 701void 702CopyEngine::CopyEngineChannel::unserialize(CheckpointIn &cp) 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, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc)); 715 UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap); 716 cr.unserialize(cp); 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::CopyEngineChannel::drainResume() 748{ 749 DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState); 750 restartStateMachine(); 751} 752 753CopyEngine * 754CopyEngineParams::create() 755{ 756 return new CopyEngine(this); 757} 758