blob: 2ce1e6260c968c622946b9a70d04d87a71d0fea8 [file] [log] [blame]
/*
* 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);
}
}