53 #include "debug/DMACopyEngine.hh"
54 #include "debug/Drain.hh"
57 #include "params/CopyEngine.hh"
61 using namespace CopyEngineReg;
72 fatal(
"CopyEngine interface doesn't support more than 64 DMA engines\n");
82 : cePort(_ce, _ce->sys),
83 ce(_ce), channelId(cid), busy(false), underReset(false),
84 refreshNext(false), latBeforeBegin(
ce->params()->latBeforeBegin),
85 latAfterCompletion(
ce->params()->latAfterCompletion),
86 completionDataReg(0), nextState(Idle),
87 fetchCompleteEvent(this), addrCompleteEvent(this),
88 readCompleteEvent(this), writeCompleteEvent(this),
89 statusCompleteEvent(this)
103 for (
int x = 0;
x <
chan.size();
x++) {
111 delete [] copyBuffer;
117 if (if_name !=
"dma") {
121 if (idx >= static_cast<int>(
chan.size())) {
122 panic(
"CopyEngine::getMasterPort: unknown index %d\n", idx);
125 return chan[idx]->getMasterPort();
139 if (cr.command.start_dma()) {
141 cr.status.dma_transfer_status(0);
142 nextState = DescriptorFetch;
143 fetchAddress = cr.descChainAddr;
145 fetchDescriptor(cr.descChainAddr);
146 }
else if (cr.command.append_dma()) {
148 nextState = AddressFetch;
150 fetchNextAddr(lastDescriptorAddr);
153 }
else if (cr.command.reset_dma()) {
157 cr.status.dma_transfer_status(3);
160 }
else if (cr.command.resume_dma() || cr.command.abort_dma() ||
161 cr.command.suspend_dma())
162 panic(
"Resume, Abort, and Suspend are not supported\n");
173 panic(
"Invalid PCI memory access to unmapped memory.\n");
179 if (size !=
sizeof(uint64_t) && size !=
sizeof(uint32_t) &&
180 size !=
sizeof(uint16_t) && size !=
sizeof(uint8_t)) {
181 panic(
"Unknown size for MMIO access: %d\n", pkt->
getSize());
184 DPRINTF(DMACopyEngine,
"Read device register %#X size: %d\n", daddr, size);
201 assert(size ==
sizeof(uint8_t));
211 panic(
"Read request to unknown register number: %#x\n", daddr);
221 while (daddr >= 0x80) {
227 panic(
"Access to channel %d (device only configured for %d channels)",
233 chan[chanid]->channelRead(pkt, daddr, size);
244 assert(size ==
sizeof(uint16_t));
245 pkt->
set<uint16_t>(cr.ctrl());
249 assert(size ==
sizeof(uint64_t));
250 pkt->
set<uint64_t>(cr.status() | ~busy);
253 assert(size ==
sizeof(uint64_t) || size ==
sizeof(uint32_t));
254 if (size ==
sizeof(uint64_t))
255 pkt->
set<uint64_t>(cr.descChainAddr);
257 pkt->
set<uint32_t>(
bits(cr.descChainAddr,0,31));
260 assert(size ==
sizeof(uint32_t));
261 pkt->
set<uint32_t>(
bits(cr.descChainAddr,32,63));
264 assert(size ==
sizeof(uint8_t));
265 pkt->
set<uint32_t>(cr.command());
268 assert(size ==
sizeof(uint64_t) || size ==
sizeof(uint32_t));
269 if (size ==
sizeof(uint64_t))
270 pkt->
set<uint64_t>(cr.completionAddr);
272 pkt->
set<uint32_t>(
bits(cr.completionAddr,0,31));
275 assert(size ==
sizeof(uint32_t));
276 pkt->
set<uint32_t>(
bits(cr.completionAddr,32,63));
279 assert(size ==
sizeof(uint32_t));
280 pkt->
set<uint32_t>(cr.error());
283 panic(
"Read request to unknown channel register number: (%d)%#x\n",
297 panic(
"Invalid PCI memory access to unmapped memory.\n");
308 if (size ==
sizeof(uint64_t)) {
310 DPRINTF(DMACopyEngine,
"Wrote device register %#X value %#X\n", daddr,
val);
311 }
else if (size ==
sizeof(uint32_t)) {
313 DPRINTF(DMACopyEngine,
"Wrote device register %#X value %#X\n", daddr,
val);
314 }
else if (size ==
sizeof(uint16_t)) {
316 DPRINTF(DMACopyEngine,
"Wrote device register %#X value %#X\n", daddr,
val);
317 }
else if (size ==
sizeof(uint8_t)) {
319 DPRINTF(DMACopyEngine,
"Wrote device register %#X value %#X\n", daddr,
val);
321 panic(
"Unknown size for MMIO access: %d\n", size);
329 DPRINTF(DMACopyEngine,
"Warning, ignorning write to register %x\n",
336 panic(
"Read request to unknown register number: %#x\n", daddr);
345 while (daddr >= 0x80) {
351 panic(
"Access to channel %d (device only configured for %d channels)",
357 chan[chanid]->channelWrite(pkt, daddr, size);
368 assert(size ==
sizeof(uint16_t));
370 old_int_disable = cr.ctrl.interrupt_disable();
371 cr.ctrl(pkt->
get<uint16_t>());
372 if (cr.ctrl.interrupt_disable())
373 cr.ctrl.interrupt_disable(0);
375 cr.ctrl.interrupt_disable(old_int_disable);
378 assert(size ==
sizeof(uint64_t));
379 DPRINTF(DMACopyEngine,
"Warning, ignorning write to register %x\n",
383 assert(size ==
sizeof(uint64_t) || size ==
sizeof(uint32_t));
384 if (size ==
sizeof(uint64_t))
385 cr.descChainAddr = pkt->
get<uint64_t>();
387 cr.descChainAddr = (uint64_t)pkt->
get<uint32_t>() |
388 (cr.descChainAddr & ~
mask(32));
389 DPRINTF(DMACopyEngine,
"Chain Address %x\n", cr.descChainAddr);
392 assert(size ==
sizeof(uint32_t));
393 cr.descChainAddr = ((uint64_t)pkt->
get<uint32_t>() <<32) |
394 (cr.descChainAddr &
mask(32));
395 DPRINTF(DMACopyEngine,
"Chain Address %x\n", cr.descChainAddr);
398 assert(size ==
sizeof(uint8_t));
399 cr.command(pkt->
get<uint8_t>());
403 assert(size ==
sizeof(uint64_t) || size ==
sizeof(uint32_t));
404 if (size ==
sizeof(uint64_t))
405 cr.completionAddr = pkt->
get<uint64_t>();
407 cr.completionAddr = pkt->
get<uint32_t>() |
408 (cr.completionAddr & ~
mask(32));
411 assert(size ==
sizeof(uint32_t));
412 cr.completionAddr = ((uint64_t)pkt->
get<uint32_t>() <<32) |
413 (cr.completionAddr &
mask(32));
416 assert(size ==
sizeof(uint32_t));
417 cr.error(~pkt->
get<uint32_t>() & cr.error());
420 panic(
"Read request to unknown channel register number: (%d)%#x\n",
430 using namespace Stats;
434 .
desc(
"Number of bytes copied by each engine")
440 .
desc(
"Number of copies processed by each engine")
449 anBegin(
"FetchDescriptor");
450 DPRINTF(DMACopyEngine,
"Reading descriptor from at memory location %#x(%#x)\n",
451 address,
ce->pciToDma(address));
455 DPRINTF(DMACopyEngine,
"dmaAction: %#x, %d bytes, to addr %#x\n",
456 ce->pciToDma(address),
sizeof(
DmaDesc), curDmaDesc);
459 sizeof(
DmaDesc), &fetchCompleteEvent,
460 (uint8_t*)curDmaDesc, latBeforeBegin);
461 lastDescriptorAddr = address;
467 DPRINTF(DMACopyEngine,
"Read of descriptor complete\n");
470 DPRINTF(DMACopyEngine,
"Got NULL descriptor, skipping\n");
473 panic(
"Shouldn't be able to get here\n");
474 nextState = CompletionWrite;
475 if (inDrain())
return;
476 writeCompletionStatus();
488 panic(
"Descriptor has flag other that completion status set\n");
491 if (inDrain())
return;
498 anBegin(
"ReadCopyBytes");
499 DPRINTF(DMACopyEngine,
"Reading %d bytes from buffer to memory location %#x(%#x)\n",
500 curDmaDesc->len, curDmaDesc->dest,
501 ce->pciToDma(curDmaDesc->src));
503 curDmaDesc->len, &readCompleteEvent, copyBuffer, 0);
509 DPRINTF(DMACopyEngine,
"Read of bytes to copy complete\n");
511 nextState = DMAWrite;
512 if (inDrain())
return;
519 anBegin(
"WriteCopyBytes");
520 DPRINTF(DMACopyEngine,
"Writing %d bytes from buffer to memory location %#x(%#x)\n",
521 curDmaDesc->len, curDmaDesc->dest,
522 ce->pciToDma(curDmaDesc->dest));
525 curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0);
527 ce->bytesCopied[channelId] += curDmaDesc->len;
528 ce->copiesProcessed[channelId]++;
534 DPRINTF(DMACopyEngine,
"Write of bytes to copy complete user1: %#x\n",
537 cr.status.compl_desc_addr(lastDescriptorAddr >> 6);
538 completionDataReg = cr.status() | 1;
540 anQ(
"DMAUsedDescQ", channelId, 1);
541 anQ(
"AppRecvQ", curDmaDesc->user1, curDmaDesc->len);
543 nextState = CompletionWrite;
544 if (inDrain())
return;
545 writeCompletionStatus();
549 continueProcessing();
567 if (curDmaDesc->next) {
568 nextState = DescriptorFetch;
569 fetchAddress = curDmaDesc->next;
570 if (inDrain())
return;
571 fetchDescriptor(curDmaDesc->next);
572 }
else if (refreshNext) {
573 nextState = AddressFetch;
575 if (inDrain())
return;
576 fetchNextAddr(lastDescriptorAddr);
588 anBegin(
"WriteCompletionStatus");
589 DPRINTF(DMACopyEngine,
"Writing completion status %#x to address %#x(%#x)\n",
590 completionDataReg, cr.completionAddr,
591 ce->pciToDma(cr.completionAddr));
594 ce->pciToDma(cr.completionAddr),
595 sizeof(completionDataReg), &statusCompleteEvent,
596 (uint8_t*)&completionDataReg, latAfterCompletion);
602 DPRINTF(DMACopyEngine,
"Writing completion status complete\n");
603 continueProcessing();
609 anBegin(
"FetchNextAddr");
610 DPRINTF(DMACopyEngine,
"Fetching next address...\n");
613 ce->pciToDma(address + offsetof(
DmaDesc, next)),
614 sizeof(
Addr), &addrCompleteEvent,
615 (uint8_t*)curDmaDesc + offsetof(
DmaDesc, next), 0);
621 DPRINTF(DMACopyEngine,
"Fetching next address complete: %#x\n",
623 if (!curDmaDesc->next) {
624 DPRINTF(DMACopyEngine,
"Got NULL descriptor, nothing more to do\n");
632 nextState = DescriptorFetch;
633 fetchAddress = curDmaDesc->next;
634 if (inDrain())
return;
635 fetchDescriptor(curDmaDesc->next);
642 DPRINTF(Drain,
"CopyEngine done draining, processing drain event\n");
655 DPRINTF(Drain,
"CopyEngineChannel not drained\n");
665 for (
int x =0;
x <
chan.size();
x++)
674 for (
int x = 0;
x <
chan.size();
x++)
688 int nextState = this->nextState;
719 fetchNextAddr(lastDescriptorAddr);
721 case DescriptorFetch:
722 fetchDescriptor(fetchAddress);
730 case CompletionWrite:
731 writeCompletionStatus();
736 panic(
"Unknown state for CopyEngineChannel\n");
743 DPRINTF(DMACopyEngine,
"Restarting state machine at state %d\n", nextState);
744 restartStateMachine();
748 CopyEngineParams::create()
void set(T v, ByteOrder endian)
Set the value in the data pointer to v using the specified endianness.
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
const Params * params() const
const uint32_t CHAN_CHAINADDR_HIGH
const uint32_t CHAN_CHAINADDR
void fetchDescriptor(Addr address)
DrainState
Object drain/handover states.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
const uint32_t DESC_CTRL_CP_STS
PCI device, base implementation is only config space.
const uint32_t CHAN_CMPLNADDR_HIGH
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
const uint32_t CHAN_STATUS
void channelWrite(PacketPtr pkt, Addr daddr, int size)
void serialize(CheckpointOut &cp) const override
Serialize an object.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void writeCompletionStatus()
void restartStateMachine()
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Derived & init(size_type size)
Set this vector to have the given size.
T get(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness.
BaseMasterPort & getMasterPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a master port with a given name and index.
const uint32_t GEN_XFERCAP
void writeCopyBytesComplete()
#define UNSERIALIZE_SCALAR(scalar)
void continueProcessing()
Stats::Vector copiesProcessed
std::string csprintf(const char *format, const Args &...args)
void serialize(CheckpointOut &cp) const override
Serialize an object.
void makeAtomicResponse()
uint64_t Tick
Tick count type.
const uint32_t CHAN_CONTROL
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
#define SERIALIZE_ARRAY(member, size)
void channelRead(PacketPtr pkt, Addr daddr, int size)
int getBAR(Addr addr)
Which base address register (if any) maps the given address?
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
void arrayParamOut(CheckpointOut &cp, const std::string &name, const CircleBuf< T > ¶m)
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
BaseMasterPort & getMasterPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a master port with a given name and index.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
std::vector< CopyEngineChannel * > chan
Draining buffers pending serialization/handover.
CopyEngineReg::ChanRegs cr
const uint32_t DESC_CTRL_NULL
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
CopyEngineReg::DmaDesc * curDmaDesc
void regStats() override
Register statistics for this object.
void writeStatusComplete()
const FlagsType total
Print the total.
const uint32_t CHAN_COMMAND
CopyEngineChannel(CopyEngine *_ce, int cid)
#define SERIALIZE_SCALAR(scalar)
const uint32_t GEN_ATTNSTATUS
void drainResume() override
Resume execution after a successful drain.
#define UNSERIALIZE_ARRAY(member, size)
static const int NumArgumentRegs M5_VAR_USED
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
virtual const std::string name() const
Declaration of the Packet class.
std::ostream CheckpointOut
const uint32_t GEN_CHANCOUNT
A BaseMasterPort is a protocol-agnostic master port, responsible only for the structural connection t...
BaseMasterPort & getMasterPort()
void readCopyBytesComplete()
void signalDrainDone() const
Signal that an object is drained.
Stats::Vector bytesCopied
const uint32_t CHAN_ERROR
int findMsbSet(uint64_t val)
Returns the bit position of the MSB that is set in the input.
const uint32_t GEN_INTRCTRL
DrainState drainState() const
Return the current drain state of an object.
void arrayParamIn(CheckpointIn &cp, const std::string &name, CircleBuf< T > ¶m)
virtual ~CopyEngineChannel()
Derived & desc(const std::string &_desc)
Set the description and marks this stat to print at the end of simulation.
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
T bits(T val, int first, int last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it...
CopyEngine(const Params *params)
const uint32_t CHAN_CMPLNADDR
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void regStats() override
Register statistics for this object.
DrainState drain() override
Notify an object that it needs to drain its state.
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
void fetchNextAddr(Addr address)