1/*
2 * Copyright (c) 2014-2016 ARM Limited
3 * All rights reserved
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * Authors: Andreas Sandberg
18 */
19
20#include "jobslot.hh"
21
22#include <cassert>
23#include <cstdlib>
24
25#include "jobcontrol.hh"
26#include "gpu.hh"
27#include "regutils.hh"
28
29namespace NoMali {
30
31static const Status STATUS_IDLE(Status::CLASS_NOFAULT, 0, 0);
32static const Status STATUS_DONE(Status::CLASS_NOFAULT, 0, 1);
33static const Status STATUS_ACTIVE(Status::CLASS_NOFAULT, 1, 0);
34
35const std::vector<JobSlot::cmd_t> JobSlot::cmds {
36    &JobSlot::cmdNop,                      // JSn_COMMAND_NOP
37    &JobSlot::cmdStart,                    // JSn_COMMAND_START
38    &JobSlot::cmdSoftStop,                 // JSn_COMMAND_SOFT_STOP
39    &JobSlot::cmdHardStop,                 // JSn_COMMAND_HARD_STOP
40    &JobSlot::cmdSoftStop0,                // JSn_COMMAND_SOFT_STOP_0
41    &JobSlot::cmdHardStop0,                // JSn_COMMAND_HARD_STOP_0
42    &JobSlot::cmdSoftStop1,                // JSn_COMMAND_SOFT_STOP_1
43    &JobSlot::cmdHardStop1,                // JSn_COMMAND_HARD_STOP_1
44};
45
46JobSlot::JobSlot(GPU &_gpu, JobControl &_jc, uint8_t _id)
47    : GPUBlock(_gpu, JSn_NO_REGS),
48      id(_id),
49      jc(_jc)
50{
51}
52
53JobSlot::JobSlot(JobSlot &&rhs)
54    : GPUBlock(std::move(rhs)),
55      id(std::move(rhs.id)),
56      jc(rhs.jc)
57{
58}
59
60JobSlot::~JobSlot()
61{
62}
63
64void
65JobSlot::writeReg(RegAddr addr, uint32_t value)
66{
67    switch (addr.value) {
68      case JSn_COMMAND:
69        jobCommand(value);
70        break;
71
72      case JSn_COMMAND_NEXT:
73        regs[addr] = value;
74        tryStart();
75        break;
76
77      case JSn_HEAD_NEXT_LO:
78      case JSn_HEAD_NEXT_HI:
79      case JSn_AFFINITY_NEXT_LO:
80      case JSn_AFFINITY_NEXT_HI:
81      case JSn_CONFIG_NEXT:
82        GPUBlock::writeReg(addr, value);
83        break;
84
85      default:
86        // Ignore writes by default
87        break;
88    };
89}
90
91bool
92JobSlot::active() const
93{
94    return false;
95}
96
97bool
98JobSlot::activeNext() const
99{
100    return regs[RegAddr(JSn_COMMAND_NEXT)] == JSn_COMMAND_START;
101}
102
103void
104JobSlot::tryStart()
105{
106    // Only actually start something if the next command is start
107    if (regs[RegAddr(JSn_COMMAND_NEXT)] != JSn_COMMAND_START )
108        return;
109
110    // Reset the status register
111    regs[RegAddr(JSn_STATUS)] = STATUS_ACTIVE.value;
112
113    // Transfer the next job configuration to the active job
114    // configuration
115    regs.set64(RegAddr(JSn_HEAD_LO), regs.get64(RegAddr(JSn_HEAD_NEXT_LO)));
116    regs.set64(RegAddr(JSn_TAIL_LO), regs.get64(RegAddr(JSn_HEAD_NEXT_LO)));
117    regs.set64(RegAddr(JSn_AFFINITY_LO),
118               regs.get64(RegAddr(JSn_AFFINITY_NEXT_LO)));
119    regs[RegAddr(JSn_CONFIG)] = regs[RegAddr(JSn_CONFIG_NEXT)];
120
121    // Reset the next job configuration
122    regs.set64(RegAddr(JSn_HEAD_NEXT_LO), 0);
123    regs[RegAddr(JSn_COMMAND_NEXT)] = 0;
124
125    runJob();
126}
127
128void
129JobSlot::runJob()
130{
131    exitJob(STATUS_DONE,
132            0); // Time stamp counter value
133}
134
135void
136JobSlot::exitJob(Status status, uint64_t fault_address)
137{
138    assert(status.statusClass() == Status::CLASS_NOFAULT ||
139           status.statusClass() == Status::CLASS_JOB);
140
141    regs[RegAddr(JSn_STATUS)] = status.value;
142
143    if (status.statusClass() == Status::CLASS_NOFAULT) {
144        jc.jobDone(id);
145    } else {
146        jc.jobFailed(id);
147    }
148}
149
150void
151JobSlot::jobCommand(uint32_t cmd)
152{
153    if (cmd < cmds.size())
154        (this->*cmds[cmd])(cmd);
155}
156
157void
158JobSlot::cmdNop(uint32_t cmd)
159{
160    assert(cmd == JSn_COMMAND_NOP);
161}
162
163void
164JobSlot::cmdStart(uint32_t cmd)
165{
166    assert(cmd == JSn_COMMAND_START);
167    // The JSn_COMMAND_START should never be issued through the
168    // JSn_COMMAND register. It should use the JSn_COMMAND_NEXT
169    // register instead.
170    abort();
171}
172
173void
174JobSlot::cmdSoftStop(uint32_t cmd)
175{
176    assert(cmd == JSn_COMMAND_SOFT_STOP ||
177           cmd == JSn_COMMAND_SOFT_STOP_0 ||
178           cmd == JSn_COMMAND_SOFT_STOP_1);
179}
180
181void
182JobSlot::cmdHardStop(uint32_t cmd)
183{
184    assert(cmd == JSn_COMMAND_HARD_STOP ||
185           cmd == JSn_COMMAND_HARD_STOP_0 ||
186           cmd == JSn_COMMAND_HARD_STOP_1);
187}
188
189void
190JobSlot::cmdSoftStop0(uint32_t cmd)
191{
192    if (!(regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG))
193        cmdSoftStop(cmd);
194}
195
196void
197JobSlot::cmdHardStop0(uint32_t cmd)
198{
199    if (!(regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG))
200        cmdHardStop(cmd);
201}
202
203void
204JobSlot::cmdSoftStop1(uint32_t cmd)
205{
206    if (regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG)
207        cmdSoftStop(cmd);
208}
209
210void
211JobSlot::cmdHardStop1(uint32_t cmd)
212{
213    if (regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG)
214        cmdHardStop(cmd);
215}
216
217}
218