Change-Id: I4df2557c71e38cc4e3a485b0e590e85eb45de8b6 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/33553 Maintainer: Jason Lowe-Power <power.jg@gmail.com> Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br> Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu> Tested-by: kokoro <noreply+kokoro@google.com>
209 lines
5.5 KiB
C++
209 lines
5.5 KiB
C++
/*
|
|
* Copyright (c) 2013, 2018-2019 ARM Limited
|
|
* All rights reserved
|
|
*
|
|
* The license below extends only to copyright in the software and shall
|
|
* not be construed as granting a license to any other intellectual
|
|
* property including but not limited to intellectual property relating
|
|
* to a hardware implementation of the functionality of the software
|
|
* licensed hereunder. You may use the software subject to the license
|
|
* terms below provided that you ensure that this notice is replicated
|
|
* unmodified and in its entirety in all distributions of the software,
|
|
* modified or unmodified, in source code or in binary form.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "dev/arm/smmu_v3_proc.hh"
|
|
|
|
#include "dev/arm/smmu_v3.hh"
|
|
#include "sim/system.hh"
|
|
|
|
SMMUProcess::SMMUProcess(const std::string &name, SMMUv3 &_smmu) :
|
|
coroutine(NULL),
|
|
myName(name),
|
|
smmu(_smmu)
|
|
{}
|
|
|
|
SMMUProcess::~SMMUProcess()
|
|
{
|
|
delete coroutine;
|
|
}
|
|
|
|
void
|
|
SMMUProcess::wakeup()
|
|
{
|
|
smmu.runProcess(this, NULL);
|
|
}
|
|
|
|
void
|
|
SMMUProcess::reinit()
|
|
{
|
|
delete coroutine;
|
|
coroutine = new Coroutine(
|
|
std::bind(&SMMUProcess::main, this, std::placeholders::_1));
|
|
}
|
|
|
|
void
|
|
SMMUProcess::doRead(Yield &yield, Addr addr, void *ptr, size_t size)
|
|
{
|
|
doSemaphoreDown(yield, smmu.requestPortSem);
|
|
doDelay(yield, Cycles(1)); // request - assume 1 cycle
|
|
doSemaphoreUp(smmu.requestPortSem);
|
|
|
|
SMMUAction a;
|
|
a.type = ACTION_SEND_REQ;
|
|
|
|
RequestPtr req = std::make_shared<Request>(
|
|
addr, size, 0, smmu.requestorId);
|
|
|
|
req->taskId(ContextSwitchTaskId::DMA);
|
|
|
|
a.pkt = new Packet(req, MemCmd::ReadReq);
|
|
a.pkt->dataStatic(ptr);
|
|
|
|
a.delay = 0;
|
|
|
|
PacketPtr pkt = yield(a).get();
|
|
|
|
assert(pkt);
|
|
// >= because we may get the whole cache line
|
|
assert(pkt->getSize() >= size);
|
|
|
|
delete pkt;
|
|
}
|
|
|
|
void
|
|
SMMUProcess::doWrite(Yield &yield, Addr addr, const void *ptr, size_t size)
|
|
{
|
|
unsigned nbeats = (size + (smmu.requestPortWidth-1))
|
|
/ smmu.requestPortWidth;
|
|
|
|
doSemaphoreDown(yield, smmu.requestPortSem);
|
|
doDelay(yield, Cycles(nbeats));
|
|
doSemaphoreUp(smmu.requestPortSem);
|
|
|
|
|
|
SMMUAction a;
|
|
a.type = ACTION_SEND_REQ;
|
|
|
|
RequestPtr req = std::make_shared<Request>(
|
|
addr, size, 0, smmu.requestorId);
|
|
|
|
req->taskId(ContextSwitchTaskId::DMA);
|
|
|
|
a.pkt = new Packet(req, MemCmd::WriteReq);
|
|
a.pkt->dataStatic(ptr);
|
|
|
|
PacketPtr pkt = yield(a).get();
|
|
|
|
delete pkt;
|
|
}
|
|
|
|
void
|
|
SMMUProcess::doDelay(Yield &yield, Cycles cycles)
|
|
{
|
|
if (smmu.system.isTimingMode())
|
|
scheduleWakeup(smmu.clockEdge(cycles));
|
|
|
|
SMMUAction a;
|
|
a.type = ACTION_DELAY;
|
|
a.delay = cycles * smmu.clockPeriod();
|
|
yield(a);
|
|
}
|
|
|
|
void
|
|
SMMUProcess::doSleep(Yield &yield)
|
|
{
|
|
SMMUAction a;
|
|
a.type = ACTION_SLEEP;
|
|
yield(a);
|
|
}
|
|
|
|
void
|
|
SMMUProcess::doSemaphoreDown(Yield &yield, SMMUSemaphore &sem)
|
|
{
|
|
while (sem.count == 0) {
|
|
sem.queue.push(this);
|
|
doSleep(yield);
|
|
}
|
|
|
|
sem.count--;
|
|
return;
|
|
}
|
|
|
|
void
|
|
SMMUProcess::doSemaphoreUp(SMMUSemaphore &sem)
|
|
{
|
|
sem.count++;
|
|
if (!sem.queue.empty()) {
|
|
SMMUProcess *next_proc = sem.queue.front();
|
|
sem.queue.pop();
|
|
|
|
// Schedule event in the current tick instead of
|
|
// calling the function directly to avoid overflowing
|
|
// the stack in this coroutine.
|
|
next_proc->scheduleWakeup(curTick());
|
|
}
|
|
}
|
|
|
|
void
|
|
SMMUProcess::doWaitForSignal(Yield &yield, SMMUSignal &sig)
|
|
{
|
|
sig.waiting.push_back(this);
|
|
doSleep(yield);
|
|
}
|
|
|
|
void
|
|
SMMUProcess::doBroadcastSignal(SMMUSignal &sig)
|
|
{
|
|
if (!sig.waiting.empty()) {
|
|
for (auto it : sig.waiting) {
|
|
// Schedule event in the current tick instead of
|
|
// calling the function directly to avoid overflowing
|
|
// the stack in this coroutine.
|
|
it->scheduleWakeup(curTick());
|
|
}
|
|
|
|
sig.waiting.clear();
|
|
}
|
|
}
|
|
|
|
void
|
|
SMMUProcess::scheduleWakeup(Tick when)
|
|
{
|
|
auto *ep = new EventWrapper<
|
|
SMMUProcess, &SMMUProcess::wakeup> (this, true);
|
|
|
|
smmu.schedule(ep, when);
|
|
}
|
|
|
|
SMMUAction
|
|
SMMUProcess::run(PacketPtr pkt)
|
|
{
|
|
assert(coroutine != NULL);
|
|
assert(*coroutine);
|
|
return (*coroutine)(pkt).get();
|
|
}
|