jobslot.cc revision 10915:71ace17ccb3d
1/*
2 * Copyright (c) 2014-2015 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
31const std::vector<JobSlot::cmd_t> JobSlot::cmds {
32    &JobSlot::cmdNop,                      // JSn_COMMAND_NOP
33    &JobSlot::cmdStart,                    // JSn_COMMAND_START
34    &JobSlot::cmdSoftStop,                 // JSn_COMMAND_SOFT_STOP
35    &JobSlot::cmdHardStop,                 // JSn_COMMAND_HARD_STOP
36    &JobSlot::cmdSoftStop0,                // JSn_COMMAND_SOFT_STOP_0
37    &JobSlot::cmdHardStop0,                // JSn_COMMAND_HARD_STOP_0
38    &JobSlot::cmdSoftStop1,                // JSn_COMMAND_SOFT_STOP_1
39    &JobSlot::cmdHardStop1,                // JSn_COMMAND_HARD_STOP_1
40};
41
42JobSlot::JobSlot(GPU &_gpu, JobControl &_jc, uint8_t _id)
43    : GPUBlock(_gpu, JSn_NO_REGS),
44      id(_id),
45      jc(_jc)
46{
47}
48
49JobSlot::JobSlot(JobSlot &&rhs)
50    : GPUBlock(std::move(rhs)),
51      id(std::move(rhs.id)),
52      jc(rhs.jc)
53{
54}
55
56JobSlot::~JobSlot()
57{
58}
59
60void
61JobSlot::writeReg(RegAddr addr, uint32_t value)
62{
63    switch (addr.value) {
64      case JSn_COMMAND:
65        jobCommand(value);
66        break;
67
68      case JSn_COMMAND_NEXT:
69        regs[addr] = value;
70        tryStart();
71        break;
72
73      case JSn_HEAD_NEXT_LO:
74      case JSn_HEAD_NEXT_HI:
75      case JSn_AFFINITY_NEXT_LO:
76      case JSn_AFFINITY_NEXT_HI:
77      case JSn_CONFIG_NEXT:
78        GPUBlock::writeReg(addr, value);
79        break;
80
81      default:
82        // Ignore writes by default
83        break;
84    };
85}
86
87bool
88JobSlot::active() const
89{
90    return false;
91}
92
93bool
94JobSlot::activeNext() const
95{
96    return regs[RegAddr(JSn_COMMAND_NEXT)] == JSn_COMMAND_START;
97}
98
99void
100JobSlot::tryStart()
101{
102    // Only actually start something if the next command is start
103    if (regs[RegAddr(JSn_COMMAND_NEXT)] != JSn_COMMAND_START )
104        return;
105
106    // Reset the status register
107    regs[RegAddr(JSn_STATUS)] = 0;
108
109    // Transfer the next job configuration to the active job
110    // configuration
111    regs.set64(RegAddr(JSn_HEAD_LO), regs.get64(RegAddr(JSn_HEAD_NEXT_LO)));
112    regs.set64(RegAddr(JSn_TAIL_LO), regs.get64(RegAddr(JSn_HEAD_NEXT_LO)));
113    regs.set64(RegAddr(JSn_AFFINITY_LO),
114               regs.get64(RegAddr(JSn_AFFINITY_NEXT_LO)));
115    regs[RegAddr(JSn_CONFIG)] = regs[RegAddr(JSn_CONFIG_NEXT)];
116    regs[RegAddr(JSn_COMMAND)] = regs[RegAddr(JSn_COMMAND_NEXT)];
117
118    // Reset the next job configuration
119    regs.set64(RegAddr(JSn_HEAD_NEXT_LO), 0);
120    regs.set64(RegAddr(JSn_AFFINITY_NEXT_LO), 0);
121    regs[RegAddr(JSn_CONFIG_NEXT)] = 0;
122    regs[RegAddr(JSn_COMMAND_NEXT)] = 0;
123
124    runJob();
125}
126
127void
128JobSlot::runJob()
129{
130    exitJob(Status(Status::CLASS_NOFAULT, 0, 1), // JSn_STATUS_DONE
131            0); // Time stamp counter value
132}
133
134void
135JobSlot::exitJob(Status status, uint64_t fault_address)
136{
137    assert(status.statusClass() == Status::CLASS_NOFAULT ||
138           status.statusClass() == Status::CLASS_JOB);
139
140    regs[RegAddr(JSn_STATUS)] = status.value;
141
142    if (status.statusClass() == Status::CLASS_NOFAULT) {
143        jc.jobDone(id);
144    } else {
145        jc.jobFailed(id);
146    }
147}
148
149void
150JobSlot::jobCommand(uint32_t cmd)
151{
152    if (cmd < cmds.size())
153        (this->*cmds[cmd])(cmd);
154}
155
156void
157JobSlot::cmdNop(uint32_t cmd)
158{
159    assert(cmd == JSn_COMMAND_NOP);
160}
161
162void
163JobSlot::cmdStart(uint32_t cmd)
164{
165    assert(cmd == JSn_COMMAND_START);
166    // The JSn_COMMAND_START should never be issued through the
167    // JSn_COMMAND register. It should use the JSn_COMMAND_NEXT
168    // register instead.
169    abort();
170}
171
172void
173JobSlot::cmdSoftStop(uint32_t cmd)
174{
175    assert(cmd == JSn_COMMAND_SOFT_STOP ||
176           cmd == JSn_COMMAND_SOFT_STOP_0 ||
177           cmd == JSn_COMMAND_SOFT_STOP_1);
178}
179
180void
181JobSlot::cmdHardStop(uint32_t cmd)
182{
183    assert(cmd == JSn_COMMAND_HARD_STOP ||
184           cmd == JSn_COMMAND_HARD_STOP_0 ||
185           cmd == JSn_COMMAND_HARD_STOP_1);
186}
187
188void
189JobSlot::cmdSoftStop0(uint32_t cmd)
190{
191    if (!(regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG))
192        cmdSoftStop(cmd);
193}
194
195void
196JobSlot::cmdHardStop0(uint32_t cmd)
197{
198    if (!(regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG))
199        cmdHardStop(cmd);
200}
201
202void
203JobSlot::cmdSoftStop1(uint32_t cmd)
204{
205    if (regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG)
206        cmdSoftStop(cmd);
207}
208
209void
210JobSlot::cmdHardStop1(uint32_t cmd)
211{
212    if (regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG)
213        cmdHardStop(cmd);
214}
215
216}
217