1/*
2 * Copyright (c) 2014-2015 ARM Limited
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
107 regs[RegAddr(JSn_STATUS)] = 0;
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)];
116 regs[RegAddr(JSn_COMMAND)] = regs[RegAddr(JSn_COMMAND_NEXT)];
120
121 // Reset the next job configuration
122 regs.set64(RegAddr(JSn_HEAD_NEXT_LO), 0);
120 regs.set64(RegAddr(JSn_AFFINITY_NEXT_LO), 0);
121 regs[RegAddr(JSn_CONFIG_NEXT)] = 0;
123 regs[RegAddr(JSn_COMMAND_NEXT)] = 0;
124
125 runJob();
126}
127
128void
129JobSlot::runJob()
130{
130 exitJob(Status(Status::CLASS_NOFAULT, 0, 1), // JSn_STATUS_DONE
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}