7b17a86a342cb55e0b35c099c3e6b5f681af5e88
2 * Copyright (c) 2012 ARM Limited
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.
14 * Copyright (c) 2008 The Regents of The University of Michigan
15 * All rights reserved.
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.
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.
44 * Device model for Intel's I/O AT DMA copy engine.
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"
59 using namespace CopyEngineReg
;
61 CopyEngine::CopyEngine(const Params
*p
)
64 // All Reg regs are initialized to 0 by default
65 regs
.chanCount
= p
->ChanCnt
;
66 regs
.xferCap
= findMsbSet(p
->XferCap
);
69 if (regs
.chanCount
> 64)
70 fatal("CopyEngine interface doesn't support more than 64 DMA engines\n");
72 for (int x
= 0; x
< regs
.chanCount
; x
++) {
73 CopyEngineChannel
*ch
= new CopyEngineChannel(this, x
);
79 CopyEngine::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)
91 cr
.status
.dma_transfer_status(3);
93 cr
.completionAddr
= 0;
95 curDmaDesc
= new DmaDesc
;
96 memset(curDmaDesc
, 0, sizeof(DmaDesc
));
97 copyBuffer
= new uint8_t[ce
->params()->XferCap
];
100 CopyEngine::~CopyEngine()
102 for (int x
= 0; x
< chan
.size(); x
++) {
107 CopyEngine::CopyEngineChannel::~CopyEngineChannel()
110 delete [] copyBuffer
;
114 CopyEngine::getPort(const std::string
&if_name
, int idx
)
116 if (if_name
== "dma") {
117 if (idx
< chan
.size())
118 return chan
[idx
]->getPort();
120 return PciDev::getPort(if_name
, idx
);
125 CopyEngine::CopyEngineChannel::getPort()
131 CopyEngine::CopyEngineChannel::recvCommand()
133 if (cr
.command
.start_dma()) {
135 cr
.status
.dma_transfer_status(0);
136 nextState
= DescriptorFetch
;
137 fetchAddress
= cr
.descChainAddr
;
138 if (ce
->getState() == SimObject::Running
)
139 fetchDescriptor(cr
.descChainAddr
);
140 } else if (cr
.command
.append_dma()) {
142 nextState
= AddressFetch
;
143 if (ce
->getState() == SimObject::Running
)
144 fetchNextAddr(lastDescriptorAddr
);
147 } else if (cr
.command
.reset_dma()) {
151 cr
.status
.dma_transfer_status(3);
154 } else if (cr
.command
.resume_dma() || cr
.command
.abort_dma() ||
155 cr
.command
.suspend_dma())
156 panic("Resume, Abort, and Suspend are not supported\n");
161 CopyEngine::read(PacketPtr pkt
)
166 if (!getBAR(pkt
->getAddr(), bar
, daddr
))
167 panic("Invalid PCI memory access to unmapped memory.\n");
169 // Only Memory register BAR is allowed
172 int size
= pkt
->getSize();
173 if (size
!= sizeof(uint64_t) && size
!= sizeof(uint32_t) &&
174 size
!= sizeof(uint16_t) && size
!= sizeof(uint8_t)) {
175 panic("Unknown size for MMIO access: %d\n", pkt
->getSize());
178 DPRINTF(DMACopyEngine
, "Read device register %#X size: %d\n", daddr
, size
);
183 /// Handle read of register here
189 assert(size
== sizeof(regs
.chanCount
));
190 pkt
->set
<uint8_t>(regs
.chanCount
);
193 assert(size
== sizeof(regs
.xferCap
));
194 pkt
->set
<uint8_t>(regs
.xferCap
);
197 assert(size
== sizeof(uint8_t));
198 pkt
->set
<uint8_t>(regs
.intrctrl());
199 regs
.intrctrl
.master_int_enable(0);
202 assert(size
== sizeof(regs
.attnStatus
));
203 pkt
->set
<uint32_t>(regs
.attnStatus
);
207 panic("Read request to unknown register number: %#x\n", daddr
);
209 pkt
->makeAtomicResponse();
214 // Find which channel we're accessing
217 while (daddr
>= 0x80) {
222 if (chanid
>= regs
.chanCount
)
223 panic("Access to channel %d (device only configured for %d channels)",
224 chanid
, regs
.chanCount
);
227 /// Channel registers are handled here
229 chan
[chanid
]->channelRead(pkt
, daddr
, size
);
231 pkt
->makeAtomicResponse();
236 CopyEngine::CopyEngineChannel::channelRead(Packet
*pkt
, Addr daddr
, int size
)
240 assert(size
== sizeof(uint16_t));
241 pkt
->set
<uint16_t>(cr
.ctrl());
245 assert(size
== sizeof(uint64_t));
246 pkt
->set
<uint64_t>(cr
.status() | ~busy
);
249 assert(size
== sizeof(uint64_t) || size
== sizeof(uint32_t));
250 if (size
== sizeof(uint64_t))
251 pkt
->set
<uint64_t>(cr
.descChainAddr
);
253 pkt
->set
<uint32_t>(bits(cr
.descChainAddr
,0,31));
255 case CHAN_CHAINADDR_HIGH
:
256 assert(size
== sizeof(uint32_t));
257 pkt
->set
<uint32_t>(bits(cr
.descChainAddr
,32,63));
260 assert(size
== sizeof(uint8_t));
261 pkt
->set
<uint32_t>(cr
.command());
264 assert(size
== sizeof(uint64_t) || size
== sizeof(uint32_t));
265 if (size
== sizeof(uint64_t))
266 pkt
->set
<uint64_t>(cr
.completionAddr
);
268 pkt
->set
<uint32_t>(bits(cr
.completionAddr
,0,31));
270 case CHAN_CMPLNADDR_HIGH
:
271 assert(size
== sizeof(uint32_t));
272 pkt
->set
<uint32_t>(bits(cr
.completionAddr
,32,63));
275 assert(size
== sizeof(uint32_t));
276 pkt
->set
<uint32_t>(cr
.error());
279 panic("Read request to unknown channel register number: (%d)%#x\n",
286 CopyEngine::write(PacketPtr pkt
)
292 if (!getBAR(pkt
->getAddr(), bar
, daddr
))
293 panic("Invalid PCI memory access to unmapped memory.\n");
295 // Only Memory register BAR is allowed
298 int size
= pkt
->getSize();
301 /// Handle write of register here
304 if (size
== sizeof(uint64_t)) {
305 uint64_t val M5_VAR_USED
= pkt
->get
<uint64_t>();
306 DPRINTF(DMACopyEngine
, "Wrote device register %#X value %#X\n", daddr
, val
);
307 } else if (size
== sizeof(uint32_t)) {
308 uint32_t val M5_VAR_USED
= pkt
->get
<uint32_t>();
309 DPRINTF(DMACopyEngine
, "Wrote device register %#X value %#X\n", daddr
, val
);
310 } else if (size
== sizeof(uint16_t)) {
311 uint16_t val M5_VAR_USED
= pkt
->get
<uint16_t>();
312 DPRINTF(DMACopyEngine
, "Wrote device register %#X value %#X\n", daddr
, val
);
313 } else if (size
== sizeof(uint8_t)) {
314 uint8_t val M5_VAR_USED
= pkt
->get
<uint8_t>();
315 DPRINTF(DMACopyEngine
, "Wrote device register %#X value %#X\n", daddr
, val
);
317 panic("Unknown size for MMIO access: %d\n", size
);
325 DPRINTF(DMACopyEngine
, "Warning, ignorning write to register %x\n",
329 regs
.intrctrl
.master_int_enable(bits(pkt
->get
<uint8_t>(),0,1));
332 panic("Read request to unknown register number: %#x\n", daddr
);
334 pkt
->makeAtomicResponse();
338 // Find which channel we're accessing
341 while (daddr
>= 0x80) {
346 if (chanid
>= regs
.chanCount
)
347 panic("Access to channel %d (device only configured for %d channels)",
348 chanid
, regs
.chanCount
);
351 /// Channel registers are handled here
353 chan
[chanid
]->channelWrite(pkt
, daddr
, size
);
355 pkt
->makeAtomicResponse();
360 CopyEngine::CopyEngineChannel::channelWrite(Packet
*pkt
, Addr daddr
, int size
)
364 assert(size
== sizeof(uint16_t));
366 old_int_disable
= cr
.ctrl
.interrupt_disable();
367 cr
.ctrl(pkt
->get
<uint16_t>());
368 if (cr
.ctrl
.interrupt_disable())
369 cr
.ctrl
.interrupt_disable(0);
371 cr
.ctrl
.interrupt_disable(old_int_disable
);
374 assert(size
== sizeof(uint64_t));
375 DPRINTF(DMACopyEngine
, "Warning, ignorning write to register %x\n",
379 assert(size
== sizeof(uint64_t) || size
== sizeof(uint32_t));
380 if (size
== sizeof(uint64_t))
381 cr
.descChainAddr
= pkt
->get
<uint64_t>();
383 cr
.descChainAddr
= (uint64_t)pkt
->get
<uint32_t>() |
384 (cr
.descChainAddr
& ~mask(32));
385 DPRINTF(DMACopyEngine
, "Chain Address %x\n", cr
.descChainAddr
);
387 case CHAN_CHAINADDR_HIGH
:
388 assert(size
== sizeof(uint32_t));
389 cr
.descChainAddr
= ((uint64_t)pkt
->get
<uint32_t>() <<32) |
390 (cr
.descChainAddr
& mask(32));
391 DPRINTF(DMACopyEngine
, "Chain Address %x\n", cr
.descChainAddr
);
394 assert(size
== sizeof(uint8_t));
395 cr
.command(pkt
->get
<uint8_t>());
399 assert(size
== sizeof(uint64_t) || size
== sizeof(uint32_t));
400 if (size
== sizeof(uint64_t))
401 cr
.completionAddr
= pkt
->get
<uint64_t>();
403 cr
.completionAddr
= pkt
->get
<uint32_t>() |
404 (cr
.completionAddr
& ~mask(32));
406 case CHAN_CMPLNADDR_HIGH
:
407 assert(size
== sizeof(uint32_t));
408 cr
.completionAddr
= ((uint64_t)pkt
->get
<uint32_t>() <<32) |
409 (cr
.completionAddr
& mask(32));
412 assert(size
== sizeof(uint32_t));
413 cr
.error(~pkt
->get
<uint32_t>() & cr
.error());
416 panic("Read request to unknown channel register number: (%d)%#x\n",
422 CopyEngine::regStats()
424 using namespace Stats
;
426 .init(regs
.chanCount
)
427 .name(name() + ".bytes_copied")
428 .desc("Number of bytes copied by each engine")
432 .init(regs
.chanCount
)
433 .name(name() + ".copies_processed")
434 .desc("Number of copies processed by each engine")
440 CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address
)
443 anBegin("FetchDescriptor");
444 DPRINTF(DMACopyEngine
, "Reading descriptor from at memory location %#x(%#x)\n",
445 address
, ce
->platform
->pciToDma(address
));
449 DPRINTF(DMACopyEngine
, "dmaAction: %#x, %d bytes, to addr %#x\n",
450 ce
->platform
->pciToDma(address
), sizeof(DmaDesc
), curDmaDesc
);
452 cePort
.dmaAction(MemCmd::ReadReq
, ce
->platform
->pciToDma(address
),
453 sizeof(DmaDesc
), &fetchCompleteEvent
,
454 (uint8_t*)curDmaDesc
, latBeforeBegin
);
455 lastDescriptorAddr
= address
;
459 CopyEngine::CopyEngineChannel::fetchDescComplete()
461 DPRINTF(DMACopyEngine
, "Read of descriptor complete\n");
463 if ((curDmaDesc
->command
& DESC_CTRL_NULL
)) {
464 DPRINTF(DMACopyEngine
, "Got NULL descriptor, skipping\n");
465 assert(!(curDmaDesc
->command
& DESC_CTRL_CP_STS
));
466 if (curDmaDesc
->command
& DESC_CTRL_CP_STS
) {
467 panic("Shouldn't be able to get here\n");
468 nextState
= CompletionWrite
;
469 if (inDrain()) return;
470 writeCompletionStatus();
481 if (curDmaDesc
->command
& ~DESC_CTRL_CP_STS
)
482 panic("Descriptor has flag other that completion status set\n");
485 if (inDrain()) return;
490 CopyEngine::CopyEngineChannel::readCopyBytes()
492 anBegin("ReadCopyBytes");
493 DPRINTF(DMACopyEngine
, "Reading %d bytes from buffer to memory location %#x(%#x)\n",
494 curDmaDesc
->len
, curDmaDesc
->dest
,
495 ce
->platform
->pciToDma(curDmaDesc
->src
));
496 cePort
.dmaAction(MemCmd::ReadReq
, ce
->platform
->pciToDma(curDmaDesc
->src
),
497 curDmaDesc
->len
, &readCompleteEvent
, copyBuffer
, 0);
501 CopyEngine::CopyEngineChannel::readCopyBytesComplete()
503 DPRINTF(DMACopyEngine
, "Read of bytes to copy complete\n");
505 nextState
= DMAWrite
;
506 if (inDrain()) return;
511 CopyEngine::CopyEngineChannel::writeCopyBytes()
513 anBegin("WriteCopyBytes");
514 DPRINTF(DMACopyEngine
, "Writing %d bytes from buffer to memory location %#x(%#x)\n",
515 curDmaDesc
->len
, curDmaDesc
->dest
,
516 ce
->platform
->pciToDma(curDmaDesc
->dest
));
518 cePort
.dmaAction(MemCmd::WriteReq
, ce
->platform
->pciToDma(curDmaDesc
->dest
),
519 curDmaDesc
->len
, &writeCompleteEvent
, copyBuffer
, 0);
521 ce
->bytesCopied
[channelId
] += curDmaDesc
->len
;
522 ce
->copiesProcessed
[channelId
]++;
526 CopyEngine::CopyEngineChannel::writeCopyBytesComplete()
528 DPRINTF(DMACopyEngine
, "Write of bytes to copy complete user1: %#x\n",
531 cr
.status
.compl_desc_addr(lastDescriptorAddr
>> 6);
532 completionDataReg
= cr
.status() | 1;
534 anQ("DMAUsedDescQ", channelId
, 1);
535 anQ("AppRecvQ", curDmaDesc
->user1
, curDmaDesc
->len
);
536 if (curDmaDesc
->command
& DESC_CTRL_CP_STS
) {
537 nextState
= CompletionWrite
;
538 if (inDrain()) return;
539 writeCompletionStatus();
543 continueProcessing();
547 CopyEngine::CopyEngineChannel::continueProcessing()
561 if (curDmaDesc
->next
) {
562 nextState
= DescriptorFetch
;
563 fetchAddress
= curDmaDesc
->next
;
564 if (inDrain()) return;
565 fetchDescriptor(curDmaDesc
->next
);
566 } else if (refreshNext
) {
567 nextState
= AddressFetch
;
569 if (inDrain()) return;
570 fetchNextAddr(lastDescriptorAddr
);
580 CopyEngine::CopyEngineChannel::writeCompletionStatus()
582 anBegin("WriteCompletionStatus");
583 DPRINTF(DMACopyEngine
, "Writing completion status %#x to address %#x(%#x)\n",
584 completionDataReg
, cr
.completionAddr
,
585 ce
->platform
->pciToDma(cr
.completionAddr
));
587 cePort
.dmaAction(MemCmd::WriteReq
,
588 ce
->platform
->pciToDma(cr
.completionAddr
),
589 sizeof(completionDataReg
), &statusCompleteEvent
,
590 (uint8_t*)&completionDataReg
, latAfterCompletion
);
594 CopyEngine::CopyEngineChannel::writeStatusComplete()
596 DPRINTF(DMACopyEngine
, "Writing completion status complete\n");
597 continueProcessing();
601 CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address
)
603 anBegin("FetchNextAddr");
604 DPRINTF(DMACopyEngine
, "Fetching next address...\n");
606 cePort
.dmaAction(MemCmd::ReadReq
,
607 ce
->platform
->pciToDma(address
+ offsetof(DmaDesc
, next
)),
608 sizeof(Addr
), &addrCompleteEvent
,
609 (uint8_t*)curDmaDesc
+ offsetof(DmaDesc
, next
), 0);
613 CopyEngine::CopyEngineChannel::fetchAddrComplete()
615 DPRINTF(DMACopyEngine
, "Fetching next address complete: %#x\n",
617 if (!curDmaDesc
->next
) {
618 DPRINTF(DMACopyEngine
, "Got NULL descriptor, nothing more to do\n");
626 nextState
= DescriptorFetch
;
627 fetchAddress
= curDmaDesc
->next
;
628 if (inDrain()) return;
629 fetchDescriptor(curDmaDesc
->next
);
633 CopyEngine::CopyEngineChannel::inDrain()
635 if (ce
->getState() == SimObject::Draining
) {
636 DPRINTF(DMACopyEngine
, "processing drain\n");
638 drainEvent
->process();
642 return ce
->getState() != SimObject::Running
;
646 CopyEngine::CopyEngineChannel::drain(Event
*de
)
648 if (nextState
== Idle
|| ce
->getState() != SimObject::Running
)
650 unsigned int count
= 1;
651 count
+= cePort
.drain(de
);
653 DPRINTF(DMACopyEngine
, "unable to drain, returning %d\n", count
);
659 CopyEngine::drain(Event
*de
)
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
);
667 changeState(Draining
);
669 changeState(Drained
);
671 DPRINTF(DMACopyEngine
, "call to CopyEngine::drain() returning %d\n", count
);
676 CopyEngine::serialize(std::ostream
&os
)
678 PciDev::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
);
687 CopyEngine::unserialize(Checkpoint
*cp
, const std::string
§ion
)
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
));
696 CopyEngine::CopyEngineChannel::serialize(std::ostream
&os
)
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
);
713 CopyEngine::CopyEngineChannel::unserialize(Checkpoint
*cp
, const std::string
§ion
)
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
);
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
);
732 CopyEngine::CopyEngineChannel::restartStateMachine()
736 fetchNextAddr(lastDescriptorAddr
);
738 case DescriptorFetch
:
739 fetchDescriptor(fetchAddress
);
747 case CompletionWrite
:
748 writeCompletionStatus();
753 panic("Unknown state for CopyEngineChannel\n");
761 for (int x
= 0;x
< chan
.size(); x
++)
767 CopyEngine::CopyEngineChannel::resume()
769 DPRINTF(DMACopyEngine
, "Restarting state machine at state %d\n", nextState
);
770 restartStateMachine();
774 CopyEngineParams::create()
776 return new CopyEngine(this);