dma_device.cc revision 10821
1545SN/A/*
28948SN/A * Copyright (c) 2012 ARM Limited
38948SN/A * All rights reserved.
48948SN/A *
58948SN/A * The license below extends only to copyright in the software and shall
68948SN/A * not be construed as granting a license to any other intellectual
78948SN/A * property including but not limited to intellectual property relating
88948SN/A * to a hardware implementation of the functionality of the software
98948SN/A * licensed hereunder.  You may use the software subject to the license
108948SN/A * terms below provided that you ensure that this notice is replicated
118948SN/A * unmodified and in its entirety in all distributions of the software,
128948SN/A * modified or unmodified, in source code or in binary form.
138948SN/A *
142512SN/A * Copyright (c) 2006 The Regents of The University of Michigan
15545SN/A * All rights reserved.
16545SN/A *
17545SN/A * Redistribution and use in source and binary forms, with or without
18545SN/A * modification, are permitted provided that the following conditions are
19545SN/A * met: redistributions of source code must retain the above copyright
20545SN/A * notice, this list of conditions and the following disclaimer;
21545SN/A * redistributions in binary form must reproduce the above copyright
22545SN/A * notice, this list of conditions and the following disclaimer in the
23545SN/A * documentation and/or other materials provided with the distribution;
24545SN/A * neither the name of the copyright holders nor the names of its
25545SN/A * contributors may be used to endorse or promote products derived from
26545SN/A * this software without specific prior written permission.
27545SN/A *
28545SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29545SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30545SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31545SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32545SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33545SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34545SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35545SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36545SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37545SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38545SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665SN/A *
402665SN/A * Authors: Ali Saidi
412665SN/A *          Nathan Binkert
429166Sandreas.hansson@arm.com *          Andreas Hansson
43545SN/A */
44545SN/A
453090SN/A#include "base/chunk_generator.hh"
468232SN/A#include "debug/DMA.hh"
479152Satgutier@umich.edu#include "debug/Drain.hh"
489016Sandreas.hansson@arm.com#include "dev/dma_device.hh"
492901SN/A#include "sim/system.hh"
50545SN/A
519165Sandreas.hansson@arm.comDmaPort::DmaPort(MemObject *dev, System *s)
529307Sandreas.hansson@arm.com    : MasterPort(dev->name() + ".dma", dev), device(dev), sendEvent(this),
539307Sandreas.hansson@arm.com      sys(s), masterId(s->getMasterId(dev->name())),
549342SAndreas.Sandberg@arm.com      pendingCount(0), drainManager(NULL),
559165Sandreas.hansson@arm.com      inRetry(false)
562489SN/A{ }
572489SN/A
589166Sandreas.hansson@arm.comvoid
599166Sandreas.hansson@arm.comDmaPort::handleResp(PacketPtr pkt, Tick delay)
609166Sandreas.hansson@arm.com{
619166Sandreas.hansson@arm.com    // should always see a response with a sender state
629166Sandreas.hansson@arm.com    assert(pkt->isResponse());
639166Sandreas.hansson@arm.com
649166Sandreas.hansson@arm.com    // get the DMA sender state
659166Sandreas.hansson@arm.com    DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
669166Sandreas.hansson@arm.com    assert(state);
679166Sandreas.hansson@arm.com
689166Sandreas.hansson@arm.com    DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d,"  \
699166Sandreas.hansson@arm.com            " tot: %d sched %d\n",
709166Sandreas.hansson@arm.com            pkt->cmdString(), pkt->getAddr(), pkt->req->getSize(),
719166Sandreas.hansson@arm.com            state->numBytes, state->totBytes,
729166Sandreas.hansson@arm.com            state->completionEvent ?
739166Sandreas.hansson@arm.com            state->completionEvent->scheduled() : 0);
749166Sandreas.hansson@arm.com
759166Sandreas.hansson@arm.com    assert(pendingCount != 0);
769166Sandreas.hansson@arm.com    pendingCount--;
779166Sandreas.hansson@arm.com
789166Sandreas.hansson@arm.com    // update the number of bytes received based on the request rather
799166Sandreas.hansson@arm.com    // than the packet as the latter could be rounded up to line sizes
809166Sandreas.hansson@arm.com    state->numBytes += pkt->req->getSize();
819166Sandreas.hansson@arm.com    assert(state->totBytes >= state->numBytes);
829166Sandreas.hansson@arm.com
839166Sandreas.hansson@arm.com    // if we have reached the total number of bytes for this DMA
849166Sandreas.hansson@arm.com    // request, then signal the completion and delete the sate
859166Sandreas.hansson@arm.com    if (state->totBytes == state->numBytes) {
869166Sandreas.hansson@arm.com        if (state->completionEvent) {
879166Sandreas.hansson@arm.com            delay += state->delay;
889452SAndreas.Sandberg@ARM.com            device->schedule(state->completionEvent, curTick() + delay);
899166Sandreas.hansson@arm.com        }
909166Sandreas.hansson@arm.com        delete state;
919166Sandreas.hansson@arm.com    }
929166Sandreas.hansson@arm.com
939166Sandreas.hansson@arm.com    // delete the request that we created and also the packet
949166Sandreas.hansson@arm.com    delete pkt->req;
959166Sandreas.hansson@arm.com    delete pkt;
969166Sandreas.hansson@arm.com
979166Sandreas.hansson@arm.com    // we might be drained at this point, if so signal the drain event
989342SAndreas.Sandberg@arm.com    if (pendingCount == 0 && drainManager) {
999342SAndreas.Sandberg@arm.com        drainManager->signalDrainDone();
1009342SAndreas.Sandberg@arm.com        drainManager = NULL;
1019166Sandreas.hansson@arm.com    }
1029166Sandreas.hansson@arm.com}
1039166Sandreas.hansson@arm.com
1042489SN/Abool
1058975SN/ADmaPort::recvTimingResp(PacketPtr pkt)
1062384SN/A{
10710821Sandreas.hansson@arm.com    // We shouldn't ever get a cacheable block in ownership state
10810821Sandreas.hansson@arm.com    assert(pkt->req->isUncacheable() ||
10910821Sandreas.hansson@arm.com           !(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
1104435SN/A
1119166Sandreas.hansson@arm.com    handleResp(pkt);
1122569SN/A
1132657SN/A    return true;
1142384SN/A}
115679SN/A
1164762SN/ADmaDevice::DmaDevice(const Params *p)
1179165Sandreas.hansson@arm.com    : PioDevice(p), dmaPort(this, sys)
1182565SN/A{ }
1192384SN/A
1208851SN/Avoid
1218851SN/ADmaDevice::init()
1228851SN/A{
1238851SN/A    if (!dmaPort.isConnected())
1248851SN/A        panic("DMA port of %s not connected to anything!", name());
1258851SN/A    PioDevice::init();
1268851SN/A}
1278851SN/A
1282901SN/Aunsigned int
1299342SAndreas.Sandberg@arm.comDmaDevice::drain(DrainManager *dm)
1302901SN/A{
1319342SAndreas.Sandberg@arm.com    unsigned int count = pioPort.drain(dm) + dmaPort.drain(dm);
1322901SN/A    if (count)
1339342SAndreas.Sandberg@arm.com        setDrainState(Drainable::Draining);
1342901SN/A    else
1359342SAndreas.Sandberg@arm.com        setDrainState(Drainable::Drained);
1362901SN/A    return count;
1372901SN/A}
1382901SN/A
1392901SN/Aunsigned int
1409342SAndreas.Sandberg@arm.comDmaPort::drain(DrainManager *dm)
1412901SN/A{
1429166Sandreas.hansson@arm.com    if (pendingCount == 0)
1432901SN/A        return 0;
1449342SAndreas.Sandberg@arm.com    drainManager = dm;
1459152Satgutier@umich.edu    DPRINTF(Drain, "DmaPort not drained\n");
1462901SN/A    return 1;
1472901SN/A}
1482901SN/A
1492384SN/Avoid
15010713Sandreas.hansson@arm.comDmaPort::recvReqRetry()
1512489SN/A{
1524435SN/A    assert(transmitList.size());
1539307Sandreas.hansson@arm.com    trySendTimingReq();
1542489SN/A}
1552641SN/A
15610621SCurtis.Dunham@arm.comRequestPtr
1572641SN/ADmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
1587607SN/A                   uint8_t *data, Tick delay, Request::Flags flag)
1592384SN/A{
1609166Sandreas.hansson@arm.com    // one DMA request sender state for every action, that is then
1619166Sandreas.hansson@arm.com    // split into many requests and packets based on the block size,
1629166Sandreas.hansson@arm.com    // i.e. cache line size
1639016Sandreas.hansson@arm.com    DmaReqState *reqState = new DmaReqState(event, size, delay);
1642384SN/A
16510621SCurtis.Dunham@arm.com    // (functionality added for Table Walker statistics)
16610621SCurtis.Dunham@arm.com    // We're only interested in this when there will only be one request.
16710621SCurtis.Dunham@arm.com    // For simplicity, we return the last request, which would also be
16810621SCurtis.Dunham@arm.com    // the only request in that case.
16910621SCurtis.Dunham@arm.com    RequestPtr req = NULL;
17010621SCurtis.Dunham@arm.com
1714451SN/A    DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
1729166Sandreas.hansson@arm.com            event ? event->scheduled() : -1);
1739814Sandreas.hansson@arm.com    for (ChunkGenerator gen(addr, size, sys->cacheLineSize());
1742406SN/A         !gen.done(); gen.next()) {
17510621SCurtis.Dunham@arm.com        req = new Request(gen.addr(), gen.size(), flag, masterId);
17610024Sdam.sunwoo@arm.com        req->taskId(ContextSwitchTaskId::DMA);
1779166Sandreas.hansson@arm.com        PacketPtr pkt = new Packet(req, cmd);
1782641SN/A
1799166Sandreas.hansson@arm.com        // Increment the data pointer on a write
1809166Sandreas.hansson@arm.com        if (data)
1819166Sandreas.hansson@arm.com            pkt->dataStatic(data + gen.complete());
1822641SN/A
1839166Sandreas.hansson@arm.com        pkt->senderState = reqState;
1842641SN/A
1859166Sandreas.hansson@arm.com        DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
1869166Sandreas.hansson@arm.com                gen.size());
1879166Sandreas.hansson@arm.com        queueDma(pkt);
1882384SN/A    }
1899307Sandreas.hansson@arm.com
1909307Sandreas.hansson@arm.com    // in zero time also initiate the sending of the packets we have
1919307Sandreas.hansson@arm.com    // just created, for atomic this involves actually completing all
1929307Sandreas.hansson@arm.com    // the requests
1939307Sandreas.hansson@arm.com    sendDma();
19410621SCurtis.Dunham@arm.com
19510621SCurtis.Dunham@arm.com    return req;
1962384SN/A}
1972384SN/A
1984435SN/Avoid
1999166Sandreas.hansson@arm.comDmaPort::queueDma(PacketPtr pkt)
2004435SN/A{
2019166Sandreas.hansson@arm.com    transmitList.push_back(pkt);
2024435SN/A
2039166Sandreas.hansson@arm.com    // remember that we have another packet pending, this will only be
2049166Sandreas.hansson@arm.com    // decremented once a response comes back
2059166Sandreas.hansson@arm.com    pendingCount++;
2069307Sandreas.hansson@arm.com}
2079166Sandreas.hansson@arm.com
2089307Sandreas.hansson@arm.comvoid
2099307Sandreas.hansson@arm.comDmaPort::trySendTimingReq()
2109307Sandreas.hansson@arm.com{
2119307Sandreas.hansson@arm.com    // send the first packet on the transmit list and schedule the
2129307Sandreas.hansson@arm.com    // following send if it is successful
2139307Sandreas.hansson@arm.com    PacketPtr pkt = transmitList.front();
2149307Sandreas.hansson@arm.com
2159307Sandreas.hansson@arm.com    DPRINTF(DMA, "Trying to send %s addr %#x\n", pkt->cmdString(),
2169307Sandreas.hansson@arm.com            pkt->getAddr());
2179307Sandreas.hansson@arm.com
2189307Sandreas.hansson@arm.com    inRetry = !sendTimingReq(pkt);
2199307Sandreas.hansson@arm.com    if (!inRetry) {
2209307Sandreas.hansson@arm.com        transmitList.pop_front();
2219307Sandreas.hansson@arm.com        DPRINTF(DMA, "-- Done\n");
2229307Sandreas.hansson@arm.com        // if there is more to do, then do so
2239307Sandreas.hansson@arm.com        if (!transmitList.empty())
2249307Sandreas.hansson@arm.com            // this should ultimately wait for as many cycles as the
2259307Sandreas.hansson@arm.com            // device needs to send the packet, but currently the port
2269307Sandreas.hansson@arm.com            // does not have any known width so simply wait a single
2279307Sandreas.hansson@arm.com            // cycle
2289307Sandreas.hansson@arm.com            device->schedule(sendEvent, device->clockEdge(Cycles(1)));
2299307Sandreas.hansson@arm.com    } else {
2309307Sandreas.hansson@arm.com        DPRINTF(DMA, "-- Failed, waiting for retry\n");
2319307Sandreas.hansson@arm.com    }
2329307Sandreas.hansson@arm.com
2339307Sandreas.hansson@arm.com    DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n",
2349307Sandreas.hansson@arm.com            transmitList.size(), inRetry);
2354435SN/A}
2364435SN/A
2372384SN/Avoid
2384435SN/ADmaPort::sendDma()
2392384SN/A{
2409166Sandreas.hansson@arm.com    // some kind of selcetion between access methods
2412901SN/A    // more work is going to have to be done to make
2422901SN/A    // switching actually work
2434435SN/A    assert(transmitList.size());
2442902SN/A
2459524SAndreas.Sandberg@ARM.com    if (sys->isTimingMode()) {
2469307Sandreas.hansson@arm.com        // if we are either waiting for a retry or are still waiting
2479307Sandreas.hansson@arm.com        // after sending the last packet, then do not proceed
2489307Sandreas.hansson@arm.com        if (inRetry || sendEvent.scheduled()) {
2499307Sandreas.hansson@arm.com            DPRINTF(DMA, "Can't send immediately, waiting to send\n");
2504435SN/A            return;
2514435SN/A        }
2524435SN/A
2539307Sandreas.hansson@arm.com        trySendTimingReq();
2549524SAndreas.Sandberg@ARM.com    } else if (sys->isAtomicMode()) {
2559307Sandreas.hansson@arm.com        // send everything there is to send in zero time
2569307Sandreas.hansson@arm.com        while (!transmitList.empty()) {
2579307Sandreas.hansson@arm.com            PacketPtr pkt = transmitList.front();
2589307Sandreas.hansson@arm.com            transmitList.pop_front();
2594435SN/A
2609307Sandreas.hansson@arm.com            DPRINTF(DMA, "Sending  DMA for addr: %#x size: %d\n",
2619307Sandreas.hansson@arm.com                    pkt->req->getPaddr(), pkt->req->getSize());
2629307Sandreas.hansson@arm.com            Tick lat = sendAtomic(pkt);
2634435SN/A
2649307Sandreas.hansson@arm.com            handleResp(pkt, lat);
2659307Sandreas.hansson@arm.com        }
2669166Sandreas.hansson@arm.com    } else
2679166Sandreas.hansson@arm.com        panic("Unknown memory mode.");
268545SN/A}
2698598SN/A
2709294Sandreas.hansson@arm.comBaseMasterPort &
2719294Sandreas.hansson@arm.comDmaDevice::getMasterPort(const std::string &if_name, PortID idx)
2728598SN/A{
2738598SN/A    if (if_name == "dma") {
2748922SN/A        return dmaPort;
2758598SN/A    }
2768922SN/A    return PioDevice::getMasterPort(if_name, idx);
2778598SN/A}
278