dma_device.cc revision 9016
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
42545SN/A */
43545SN/A
443090SN/A#include "base/chunk_generator.hh"
458232SN/A#include "debug/DMA.hh"
469016Sandreas.hansson@arm.com#include "dev/dma_device.hh"
472901SN/A#include "sim/system.hh"
48545SN/A
499015SN/ADmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff)
509015SN/A    : MasterPort(dev->name() + "-dma", dev), device(dev), sys(s),
518832SN/A      masterId(s->getMasterId(dev->name())),
524435SN/A      pendingCount(0), actionInProgress(0), drainEvent(NULL),
537403SN/A      backoffTime(0), minBackoffDelay(min_backoff),
549015SN/A      maxBackoffDelay(max_backoff), inRetry(false),
558711SN/A      backoffEvent(this)
562489SN/A{ }
572489SN/A
582489SN/Abool
598975SN/ADmaPort::recvTimingResp(PacketPtr pkt)
602384SN/A{
614870SN/A    if (pkt->wasNacked()) {
624739SN/A        DPRINTF(DMA, "Received nacked %s addr %#x\n",
634739SN/A                pkt->cmdString(), pkt->getAddr());
644435SN/A
657403SN/A        if (backoffTime < minBackoffDelay)
667403SN/A            backoffTime = minBackoffDelay;
677403SN/A        else if (backoffTime < maxBackoffDelay)
684435SN/A            backoffTime <<= 1;
694435SN/A
708708SN/A        device->reschedule(backoffEvent, curTick() + backoffTime, true);
714435SN/A
724435SN/A        DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime);
734435SN/A
742685SN/A        pkt->reinitNacked();
754435SN/A        queueDma(pkt, true);
762685SN/A    } else if (pkt->senderState) {
772565SN/A        DmaReqState *state;
784435SN/A        backoffTime >>= 2;
794435SN/A
804739SN/A        DPRINTF(DMA, "Received response %s addr %#x size %#x\n",
814739SN/A                pkt->cmdString(), pkt->getAddr(), pkt->req->getSize());
822641SN/A        state = dynamic_cast<DmaReqState*>(pkt->senderState);
832685SN/A        pendingCount--;
842685SN/A
852685SN/A        assert(pendingCount >= 0);
862657SN/A        assert(state);
872685SN/A
888134SN/A        // We shouldn't ever get a block in ownership state
898134SN/A        assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
908134SN/A
912685SN/A        state->numBytes += pkt->req->getSize();
924435SN/A        assert(state->totBytes >= state->numBytes);
932685SN/A        if (state->totBytes == state->numBytes) {
947403SN/A            if (state->completionEvent) {
957403SN/A                if (state->delay)
968708SN/A                    device->schedule(state->completionEvent,
978708SN/A                                     curTick() + state->delay);
987403SN/A                else
997403SN/A                    state->completionEvent->process();
1007403SN/A            }
1012685SN/A            delete state;
1022685SN/A        }
1032630SN/A        delete pkt->req;
1042630SN/A        delete pkt;
1052901SN/A
1062901SN/A        if (pendingCount == 0 && drainEvent) {
1072901SN/A            drainEvent->process();
1082901SN/A            drainEvent = NULL;
1092901SN/A        }
1102569SN/A    }  else {
1112685SN/A        panic("Got packet without sender state... huh?\n");
1122565SN/A    }
1132569SN/A
1142657SN/A    return true;
1152384SN/A}
116679SN/A
1174762SN/ADmaDevice::DmaDevice(const Params *p)
1188851SN/A    : PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay,
1198851SN/A                            params()->max_backoff_delay)
1202565SN/A{ }
1212384SN/A
1228851SN/Avoid
1238851SN/ADmaDevice::init()
1248851SN/A{
1258851SN/A    if (!dmaPort.isConnected())
1268851SN/A        panic("DMA port of %s not connected to anything!", name());
1278851SN/A    PioDevice::init();
1288851SN/A}
1298851SN/A
1302901SN/Aunsigned int
1312901SN/ADmaDevice::drain(Event *de)
1322901SN/A{
1332901SN/A    unsigned int count;
1348851SN/A    count = pioPort.drain(de) + dmaPort.drain(de);
1352901SN/A    if (count)
1362901SN/A        changeState(Draining);
1372901SN/A    else
1382901SN/A        changeState(Drained);
1392901SN/A    return count;
1402901SN/A}
1412901SN/A
1422901SN/Aunsigned int
1432901SN/ADmaPort::drain(Event *de)
1442901SN/A{
1452901SN/A    if (pendingCount == 0)
1462901SN/A        return 0;
1472901SN/A    drainEvent = de;
1482901SN/A    return 1;
1492901SN/A}
1502901SN/A
1512384SN/Avoid
1522489SN/ADmaPort::recvRetry()
1532489SN/A{
1544435SN/A    assert(transmitList.size());
1552659SN/A    bool result = true;
1564435SN/A    do {
1575539SN/A        PacketPtr pkt = transmitList.front();
1584739SN/A        DPRINTF(DMA, "Retry on %s addr %#x\n",
1594739SN/A                pkt->cmdString(), pkt->getAddr());
1608975SN/A        result = sendTimingReq(pkt);
1612659SN/A        if (result) {
1622659SN/A            DPRINTF(DMA, "-- Done\n");
1632659SN/A            transmitList.pop_front();
1644435SN/A            inRetry = false;
1652659SN/A        } else {
1664435SN/A            inRetry = true;
1672659SN/A            DPRINTF(DMA, "-- Failed, queued\n");
1682659SN/A        }
1694435SN/A    } while (!backoffTime &&  result && transmitList.size());
1704435SN/A
1714435SN/A    if (transmitList.size() && backoffTime && !inRetry) {
1727823SN/A        DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime);
1734435SN/A        if (!backoffEvent.scheduled())
1748708SN/A            device->schedule(backoffEvent, backoffTime + curTick());
1752657SN/A    }
1764435SN/A    DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n",
1774435SN/A            transmitList.size(), backoffTime, inRetry,
1784435SN/A            backoffEvent.scheduled());
1792489SN/A}
1802641SN/A
1812489SN/Avoid
1822641SN/ADmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
1837607SN/A                   uint8_t *data, Tick delay, Request::Flags flag)
1842384SN/A{
1852901SN/A    assert(device->getState() == SimObject::Running);
1862901SN/A
1879016Sandreas.hansson@arm.com    DmaReqState *reqState = new DmaReqState(event, size, delay);
1882384SN/A
1894451SN/A
1904451SN/A    DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
1917607SN/A            event ? event->scheduled() : -1 );
1922406SN/A    for (ChunkGenerator gen(addr, size, peerBlockSize());
1932406SN/A         !gen.done(); gen.next()) {
1948832SN/A            Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
1958949SN/A            PacketPtr pkt = new Packet(req, cmd);
1962641SN/A
1972384SN/A            // Increment the data pointer on a write
1982566SN/A            if (data)
1992685SN/A                pkt->dataStatic(data + gen.complete());
2002641SN/A
2012685SN/A            pkt->senderState = reqState;
2022641SN/A
2032565SN/A            assert(pendingCount >= 0);
2042565SN/A            pendingCount++;
2054451SN/A            DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
2064451SN/A                    gen.size());
2074435SN/A            queueDma(pkt);
2082384SN/A    }
2092901SN/A
2102384SN/A}
2112384SN/A
2124435SN/Avoid
2134435SN/ADmaPort::queueDma(PacketPtr pkt, bool front)
2144435SN/A{
2154435SN/A
2164435SN/A    if (front)
2174435SN/A        transmitList.push_front(pkt);
2184435SN/A    else
2194435SN/A        transmitList.push_back(pkt);
2204435SN/A    sendDma();
2214435SN/A}
2224435SN/A
2232384SN/Avoid
2244435SN/ADmaPort::sendDma()
2252384SN/A{
2262901SN/A    // some kind of selction between access methods
2272901SN/A    // more work is going to have to be done to make
2282901SN/A    // switching actually work
2294435SN/A    assert(transmitList.size());
2304435SN/A    PacketPtr pkt = transmitList.front();
2312902SN/A
2324762SN/A    Enums::MemoryMode state = sys->getMemoryMode();
2334762SN/A    if (state == Enums::timing) {
2344435SN/A        if (backoffEvent.scheduled() || inRetry) {
2354435SN/A            DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n");
2364435SN/A            return;
2374435SN/A        }
2384435SN/A
2394739SN/A        DPRINTF(DMA, "Attempting to send %s addr %#x\n",
2404739SN/A                pkt->cmdString(), pkt->getAddr());
2414435SN/A
2424435SN/A        bool result;
2434435SN/A        do {
2448975SN/A            result = sendTimingReq(pkt);
2454435SN/A            if (result) {
2464435SN/A                transmitList.pop_front();
2474435SN/A                DPRINTF(DMA, "-- Done\n");
2484435SN/A            } else {
2494435SN/A                inRetry = true;
2504435SN/A                DPRINTF(DMA, "-- Failed: queued\n");
2514435SN/A            }
2524435SN/A        } while (result && !backoffTime && transmitList.size());
2534435SN/A
2544435SN/A        if (transmitList.size() && backoffTime && !inRetry &&
2554435SN/A                !backoffEvent.scheduled()) {
2564451SN/A            DPRINTF(DMA, "-- Scheduling backoff timer for %d\n",
2577823SN/A                    backoffTime+curTick());
2588708SN/A            device->schedule(backoffEvent, backoffTime + curTick());
2592901SN/A        }
2604762SN/A    } else if (state == Enums::atomic) {
2614435SN/A        transmitList.pop_front();
2624435SN/A
2632902SN/A        Tick lat;
2644451SN/A        DPRINTF(DMA, "--Sending  DMA for addr: %#x size: %d\n",
2654451SN/A                pkt->req->getPaddr(), pkt->req->getSize());
2662902SN/A        lat = sendAtomic(pkt);
2672901SN/A        assert(pkt->senderState);
2682901SN/A        DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
2692901SN/A        assert(state);
2704451SN/A        state->numBytes += pkt->req->getSize();
2712384SN/A
2724451SN/A        DPRINTF(DMA, "--Received response for  DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n",
2734451SN/A                pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes,
2747403SN/A                state->totBytes,
2757403SN/A                state->completionEvent ? state->completionEvent->scheduled() : 0 );
2764451SN/A
2772901SN/A        if (state->totBytes == state->numBytes) {
2787403SN/A            if (state->completionEvent) {
2797403SN/A                assert(!state->completionEvent->scheduled());
2808708SN/A                device->schedule(state->completionEvent,
2818708SN/A                                 curTick() + lat + state->delay);
2827403SN/A            }
2832901SN/A            delete state;
2842901SN/A            delete pkt->req;
2852901SN/A        }
2862901SN/A        pendingCount--;
2872901SN/A        assert(pendingCount >= 0);
2882901SN/A        delete pkt;
2892566SN/A
2902901SN/A        if (pendingCount == 0 && drainEvent) {
2912901SN/A            drainEvent->process();
2922901SN/A            drainEvent = NULL;
2932901SN/A        }
2942901SN/A
2952384SN/A   } else
2962384SN/A       panic("Unknown memory command state.");
2972384SN/A}
298545SN/A
299545SN/ADmaDevice::~DmaDevice()
300545SN/A{
301545SN/A}
3028598SN/A
3038922SN/AMasterPort &
3048922SN/ADmaDevice::getMasterPort(const std::string &if_name, int idx)
3058598SN/A{
3068598SN/A    if (if_name == "dma") {
3078922SN/A        return dmaPort;
3088598SN/A    }
3098922SN/A    return PioDevice::getMasterPort(if_name, idx);
3108598SN/A}
311