b99fea78a6
Update NoMali from external revision 9adf9d6 to f08e0a5 and bring in the following changes: f08e0a5 Add support for tracking address space state f11099e Fix job slot register handling when running new jobs b28c98e api: Add a reset callback 29ac4c3 tests: Update gitignore to cover all future test cases 1c6b893 Propagate reset calls to all job slots 8f8ec15 Remove redundant reg vector in MMU 85d90d2 tests: Fix incorrect extern declaration
217 lines
5 KiB
C++
217 lines
5 KiB
C++
/*
|
|
* Copyright (c) 2014-2016 ARM Limited
|
|
* All rights reserved
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* Authors: Andreas Sandberg
|
|
*/
|
|
|
|
#include "jobslot.hh"
|
|
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
|
|
#include "jobcontrol.hh"
|
|
#include "gpu.hh"
|
|
#include "regutils.hh"
|
|
|
|
namespace NoMali {
|
|
|
|
static const Status STATUS_IDLE(Status::CLASS_NOFAULT, 0, 0);
|
|
static const Status STATUS_DONE(Status::CLASS_NOFAULT, 0, 1);
|
|
static const Status STATUS_ACTIVE(Status::CLASS_NOFAULT, 1, 0);
|
|
|
|
const std::vector<JobSlot::cmd_t> JobSlot::cmds {
|
|
&JobSlot::cmdNop, // JSn_COMMAND_NOP
|
|
&JobSlot::cmdStart, // JSn_COMMAND_START
|
|
&JobSlot::cmdSoftStop, // JSn_COMMAND_SOFT_STOP
|
|
&JobSlot::cmdHardStop, // JSn_COMMAND_HARD_STOP
|
|
&JobSlot::cmdSoftStop0, // JSn_COMMAND_SOFT_STOP_0
|
|
&JobSlot::cmdHardStop0, // JSn_COMMAND_HARD_STOP_0
|
|
&JobSlot::cmdSoftStop1, // JSn_COMMAND_SOFT_STOP_1
|
|
&JobSlot::cmdHardStop1, // JSn_COMMAND_HARD_STOP_1
|
|
};
|
|
|
|
JobSlot::JobSlot(GPU &_gpu, JobControl &_jc, uint8_t _id)
|
|
: GPUBlock(_gpu, JSn_NO_REGS),
|
|
id(_id),
|
|
jc(_jc)
|
|
{
|
|
}
|
|
|
|
JobSlot::JobSlot(JobSlot &&rhs)
|
|
: GPUBlock(std::move(rhs)),
|
|
id(std::move(rhs.id)),
|
|
jc(rhs.jc)
|
|
{
|
|
}
|
|
|
|
JobSlot::~JobSlot()
|
|
{
|
|
}
|
|
|
|
void
|
|
JobSlot::writeReg(RegAddr addr, uint32_t value)
|
|
{
|
|
switch (addr.value) {
|
|
case JSn_COMMAND:
|
|
jobCommand(value);
|
|
break;
|
|
|
|
case JSn_COMMAND_NEXT:
|
|
regs[addr] = value;
|
|
tryStart();
|
|
break;
|
|
|
|
case JSn_HEAD_NEXT_LO:
|
|
case JSn_HEAD_NEXT_HI:
|
|
case JSn_AFFINITY_NEXT_LO:
|
|
case JSn_AFFINITY_NEXT_HI:
|
|
case JSn_CONFIG_NEXT:
|
|
GPUBlock::writeReg(addr, value);
|
|
break;
|
|
|
|
default:
|
|
// Ignore writes by default
|
|
break;
|
|
};
|
|
}
|
|
|
|
bool
|
|
JobSlot::active() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
JobSlot::activeNext() const
|
|
{
|
|
return regs[RegAddr(JSn_COMMAND_NEXT)] == JSn_COMMAND_START;
|
|
}
|
|
|
|
void
|
|
JobSlot::tryStart()
|
|
{
|
|
// Only actually start something if the next command is start
|
|
if (regs[RegAddr(JSn_COMMAND_NEXT)] != JSn_COMMAND_START )
|
|
return;
|
|
|
|
// Reset the status register
|
|
regs[RegAddr(JSn_STATUS)] = STATUS_ACTIVE.value;
|
|
|
|
// Transfer the next job configuration to the active job
|
|
// configuration
|
|
regs.set64(RegAddr(JSn_HEAD_LO), regs.get64(RegAddr(JSn_HEAD_NEXT_LO)));
|
|
regs.set64(RegAddr(JSn_TAIL_LO), regs.get64(RegAddr(JSn_HEAD_NEXT_LO)));
|
|
regs.set64(RegAddr(JSn_AFFINITY_LO),
|
|
regs.get64(RegAddr(JSn_AFFINITY_NEXT_LO)));
|
|
regs[RegAddr(JSn_CONFIG)] = regs[RegAddr(JSn_CONFIG_NEXT)];
|
|
|
|
// Reset the next job configuration
|
|
regs.set64(RegAddr(JSn_HEAD_NEXT_LO), 0);
|
|
regs[RegAddr(JSn_COMMAND_NEXT)] = 0;
|
|
|
|
runJob();
|
|
}
|
|
|
|
void
|
|
JobSlot::runJob()
|
|
{
|
|
exitJob(STATUS_DONE,
|
|
0); // Time stamp counter value
|
|
}
|
|
|
|
void
|
|
JobSlot::exitJob(Status status, uint64_t fault_address)
|
|
{
|
|
assert(status.statusClass() == Status::CLASS_NOFAULT ||
|
|
status.statusClass() == Status::CLASS_JOB);
|
|
|
|
regs[RegAddr(JSn_STATUS)] = status.value;
|
|
|
|
if (status.statusClass() == Status::CLASS_NOFAULT) {
|
|
jc.jobDone(id);
|
|
} else {
|
|
jc.jobFailed(id);
|
|
}
|
|
}
|
|
|
|
void
|
|
JobSlot::jobCommand(uint32_t cmd)
|
|
{
|
|
if (cmd < cmds.size())
|
|
(this->*cmds[cmd])(cmd);
|
|
}
|
|
|
|
void
|
|
JobSlot::cmdNop(uint32_t cmd)
|
|
{
|
|
assert(cmd == JSn_COMMAND_NOP);
|
|
}
|
|
|
|
void
|
|
JobSlot::cmdStart(uint32_t cmd)
|
|
{
|
|
assert(cmd == JSn_COMMAND_START);
|
|
// The JSn_COMMAND_START should never be issued through the
|
|
// JSn_COMMAND register. It should use the JSn_COMMAND_NEXT
|
|
// register instead.
|
|
abort();
|
|
}
|
|
|
|
void
|
|
JobSlot::cmdSoftStop(uint32_t cmd)
|
|
{
|
|
assert(cmd == JSn_COMMAND_SOFT_STOP ||
|
|
cmd == JSn_COMMAND_SOFT_STOP_0 ||
|
|
cmd == JSn_COMMAND_SOFT_STOP_1);
|
|
}
|
|
|
|
void
|
|
JobSlot::cmdHardStop(uint32_t cmd)
|
|
{
|
|
assert(cmd == JSn_COMMAND_HARD_STOP ||
|
|
cmd == JSn_COMMAND_HARD_STOP_0 ||
|
|
cmd == JSn_COMMAND_HARD_STOP_1);
|
|
}
|
|
|
|
void
|
|
JobSlot::cmdSoftStop0(uint32_t cmd)
|
|
{
|
|
if (!(regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG))
|
|
cmdSoftStop(cmd);
|
|
}
|
|
|
|
void
|
|
JobSlot::cmdHardStop0(uint32_t cmd)
|
|
{
|
|
if (!(regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG))
|
|
cmdHardStop(cmd);
|
|
}
|
|
|
|
void
|
|
JobSlot::cmdSoftStop1(uint32_t cmd)
|
|
{
|
|
if (regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG)
|
|
cmdSoftStop(cmd);
|
|
}
|
|
|
|
void
|
|
JobSlot::cmdHardStop1(uint32_t cmd)
|
|
{
|
|
if (regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG)
|
|
cmdHardStop(cmd);
|
|
}
|
|
|
|
}
|