blob: cdd5c35cd6ce015cb68202bc710a4685f38395d1 [file] [log] [blame]
Kristofer Jonsson641c0912020-08-31 11:34:14 +02001/*
Anton Moberge348f8f2021-03-31 11:08:58 +02002 * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
Kristofer Jonsson641c0912020-08-31 11:34:14 +02003 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
Davide Grohmann53cc13d2021-06-01 14:21:42 +020019#if defined(ETHOSU)
20#include <ethosu_driver.h>
21#endif
22
Kristofer Jonsson641c0912020-08-31 11:34:14 +020023#include <message_process.hpp>
24
Per Åstrandd9afc082020-10-06 13:25:08 +020025#include "cmsis_compiler.h"
26
Kristofer Jonsson641c0912020-08-31 11:34:14 +020027#include <cstddef>
28#include <cstdio>
Kristofer Jonsson25480142020-09-03 12:35:21 +020029#include <cstring>
Per Åstrand91a91732020-09-25 15:04:26 +020030#include <inttypes.h>
Kristofer Jonsson641c0912020-08-31 11:34:14 +020031
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +020032using namespace std;
33using namespace InferenceProcess;
Per Åstrand4edc1782021-01-12 14:33:36 +010034using namespace EthosU;
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +020035
Kristofer Jonsson641c0912020-08-31 11:34:14 +020036namespace MessageProcess {
37
Kristofer Jonsson68b4ad52020-12-10 15:11:27 +010038QueueImpl::QueueImpl(ethosu_core_queue &_queue) : queue(_queue) {
39 cleanHeaderData();
40}
Kristofer Jonsson641c0912020-08-31 11:34:14 +020041
42bool QueueImpl::empty() const {
Kristofer Jonsson2cda7fb2021-02-01 11:22:59 +010043 invalidateHeaderData();
44
Kristofer Jonsson641c0912020-08-31 11:34:14 +020045 return queue.header.read == queue.header.write;
46}
47
48size_t QueueImpl::available() const {
Kristofer Jonsson2cda7fb2021-02-01 11:22:59 +010049 invalidateHeaderData();
50
Kristofer Jonsson641c0912020-08-31 11:34:14 +020051 size_t avail = queue.header.write - queue.header.read;
52
53 if (queue.header.read > queue.header.write) {
54 avail += queue.header.size;
55 }
56
57 return avail;
58}
59
60size_t QueueImpl::capacity() const {
61 return queue.header.size - available();
62}
63
64bool QueueImpl::read(uint8_t *dst, uint32_t length) {
65 const uint8_t *end = dst + length;
Kristofer Jonsson641c0912020-08-31 11:34:14 +020066
Kristofer Jonsson2cda7fb2021-02-01 11:22:59 +010067 // Available will invalidate the cache
Kristofer Jonsson641c0912020-08-31 11:34:14 +020068 if (length > available()) {
69 return false;
70 }
71
Kristofer Jonsson2cda7fb2021-02-01 11:22:59 +010072 uint32_t rpos = queue.header.read;
73
Kristofer Jonsson641c0912020-08-31 11:34:14 +020074 while (dst < end) {
75 *dst++ = queue.data[rpos];
76 rpos = (rpos + 1) % queue.header.size;
77 }
78
79 queue.header.read = rpos;
80
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +010081 cleanHeader();
Kristofer Jonsson641c0912020-08-31 11:34:14 +020082
83 return true;
84}
85
86bool QueueImpl::write(const Vec *vec, size_t length) {
87 size_t total = 0;
88
89 for (size_t i = 0; i < length; i++) {
90 total += vec[i].length;
91 }
92
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +010093 invalidateHeader();
94
Kristofer Jonsson641c0912020-08-31 11:34:14 +020095 if (total > capacity()) {
96 return false;
97 }
98
99 uint32_t wpos = queue.header.write;
100
101 for (size_t i = 0; i < length; i++) {
102 const uint8_t *src = reinterpret_cast<const uint8_t *>(vec[i].base);
103 const uint8_t *end = src + vec[i].length;
104
105 while (src < end) {
106 queue.data[wpos] = *src++;
107 wpos = (wpos + 1) % queue.header.size;
108 }
109 }
110
111 // Update the write position last
112 queue.header.write = wpos;
113
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100114 cleanHeaderData();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200115
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200116 return true;
117}
118
119bool QueueImpl::write(const uint32_t type, const void *src, uint32_t length) {
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100120 ethosu_core_msg msg = {ETHOSU_CORE_MSG_MAGIC, type, length};
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200121 Vec vec[2] = {{&msg, sizeof(msg)}, {src, length}};
122
123 return write(vec, 2);
124}
125
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100126// Skip to magic or end of queue
127void QueueImpl::reset() {
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100128 invalidateHeader();
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100129 queue.header.read = queue.header.write;
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100130 cleanHeader();
Per Åstranddc28b132020-09-28 13:02:18 +0200131}
132
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100133void QueueImpl::cleanHeader() const {
134#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
135 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
136#endif
137}
138
139void QueueImpl::cleanHeaderData() const {
140#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
141 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
Bhavik Patel97906eb2020-12-17 15:32:16 +0100142 uintptr_t queueDataPtr = reinterpret_cast<uintptr_t>(&queue.data[0]);
143 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(queueDataPtr & ~3), queue.header.size + (queueDataPtr & 3));
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100144#endif
145}
146
147void QueueImpl::invalidateHeader() const {
148#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
149 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
150#endif
151}
152
153void QueueImpl::invalidateHeaderData() const {
154#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
155 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
Bhavik Patel97906eb2020-12-17 15:32:16 +0100156 uintptr_t queueDataPtr = reinterpret_cast<uintptr_t>(&queue.data[0]);
157 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(queueDataPtr & ~3),
158 queue.header.size + (queueDataPtr & 3));
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100159#endif
160}
161
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200162MessageProcess::MessageProcess(ethosu_core_queue &in,
163 ethosu_core_queue &out,
Jonny Svärd44398c82020-10-06 14:18:28 +0200164 Mailbox::Mailbox &mbox,
Per Åstrandbbd9c8f2020-09-25 15:07:35 +0200165 ::InferenceProcess::InferenceProcess &_inferenceProcess) :
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200166 queueIn(in),
Jonny Svärd44398c82020-10-06 14:18:28 +0200167 queueOut(out), mailbox(mbox), inferenceProcess(_inferenceProcess) {
168 mailbox.registerCallback(mailboxCallback, reinterpret_cast<void *>(this));
169}
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200170
171void MessageProcess::run() {
172 while (true) {
173 // Handle all messages in queue
174 while (handleMessage())
175 ;
176
177 // Wait for event
178 __WFE();
179 }
180}
181
182void MessageProcess::handleIrq() {
183 __SEV();
184}
185
186bool MessageProcess::handleMessage() {
187 ethosu_core_msg msg;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200188
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100189 if (queueIn.available() == 0) {
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200190 return false;
191 }
192
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100193 // Read msg header
194 // Only process a complete message header, else send error message
195 // and reset queue
196 if (!queueIn.read(msg)) {
197 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_INVALID_SIZE, "Failed to read a complete header");
198 return false;
199 }
200
201 printf("Msg: header magic=%" PRIX32 ", type=%" PRIu32 ", length=%" PRIu32 "\n", msg.magic, msg.type, msg.length);
202
203 if (msg.magic != ETHOSU_CORE_MSG_MAGIC) {
204 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_INVALID_MAGIC, "Invalid magic");
205 return false;
206 }
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200207
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200208 switch (msg.type) {
209 case ETHOSU_CORE_MSG_PING:
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100210 printf("Msg: Ping\n");
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200211 sendPong();
212 break;
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100213 case ETHOSU_CORE_MSG_ERR: {
214 struct ethosu_core_msg_err error = {0};
215 if (!queueIn.read(error)) {
216 printf("ERROR: Msg: Failed to receive error message\n");
217 } else {
218 printf("Msg: Received an error response, type=%" PRIu32 ", msg=\"%s\"\n", error.type, error.msg);
219 }
220 queueIn.reset();
221 return false;
222 }
223 case ETHOSU_CORE_MSG_VERSION_REQ:
224 printf("Msg: Version request\n");
225 sendVersionRsp();
226 break;
Davide Grohmann53cc13d2021-06-01 14:21:42 +0200227 case ETHOSU_CORE_MSG_CAPABILITIES_REQ: {
228 ethosu_core_capabilities_req req;
229 if (!queueIn.read(req)) {
230 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_INVALID_PAYLOAD, "CapabilitiesReq. Failed to read payload");
231 return false;
232 }
233
234 printf("Msg: Capability request.user_arg=0x%" PRIx64 "", req.user_arg);
235
236 sendCapabilityRsp(req.user_arg);
237 break;
238 }
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200239 case ETHOSU_CORE_MSG_INFERENCE_REQ: {
Per Åstranddc28b132020-09-28 13:02:18 +0200240 ethosu_core_inference_req req;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200241
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100242 if (!queueIn.read(req)) {
243 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_INVALID_PAYLOAD, "InferenceReq. Failed to read payload");
Per Åstranddc28b132020-09-28 13:02:18 +0200244 return false;
245 }
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200246
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100247 printf("Msg: InferenceReq. user_arg=0x%" PRIx64 ", network={0x%" PRIx32 ", %" PRIu32 "}",
Per Åstrand91a91732020-09-25 15:04:26 +0200248 req.user_arg,
249 req.network.ptr,
250 req.network.size);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200251
Per Åstrand91a91732020-09-25 15:04:26 +0200252 printf(", ifm_count=%" PRIu32 ", ifm=[", req.ifm_count);
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200253 for (uint32_t i = 0; i < req.ifm_count; ++i) {
254 if (i > 0) {
255 printf(", ");
256 }
257
Per Åstrand91a91732020-09-25 15:04:26 +0200258 printf("{0x%" PRIx32 ", %" PRIu32 "}", req.ifm[i].ptr, req.ifm[i].size);
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200259 }
260 printf("]");
261
Per Åstrand91a91732020-09-25 15:04:26 +0200262 printf(", ofm_count=%" PRIu32 ", ofm=[", req.ofm_count);
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200263 for (uint32_t i = 0; i < req.ofm_count; ++i) {
264 if (i > 0) {
265 printf(", ");
266 }
267
Per Åstrand91a91732020-09-25 15:04:26 +0200268 printf("{0x%" PRIx32 ", %" PRIu32 "}", req.ofm[i].ptr, req.ofm[i].size);
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200269 }
270 printf("]\n");
271
272 DataPtr networkModel(reinterpret_cast<void *>(req.network.ptr), req.network.size);
273
274 vector<DataPtr> ifm;
275 for (uint32_t i = 0; i < req.ifm_count; ++i) {
276 ifm.push_back(DataPtr(reinterpret_cast<void *>(req.ifm[i].ptr), req.ifm[i].size));
277 }
278
279 vector<DataPtr> ofm;
280 for (uint32_t i = 0; i < req.ofm_count; ++i) {
281 ofm.push_back(DataPtr(reinterpret_cast<void *>(req.ofm[i].ptr), req.ofm[i].size));
282 }
283
284 vector<DataPtr> expectedOutput;
285
Jonny Svärde9f57dc2020-12-10 11:12:44 +0100286 vector<uint8_t> pmuEventConfig(ETHOSU_CORE_PMU_MAX);
Bhavik Patelffe845d2020-11-16 12:13:56 +0100287 for (uint32_t i = 0; i < ETHOSU_CORE_PMU_MAX; i++) {
288 pmuEventConfig[i] = req.pmu_event_config[i];
289 }
290
291 InferenceJob job(
292 "job", networkModel, ifm, ofm, expectedOutput, -1, pmuEventConfig, req.pmu_cycle_counter_enable);
Kristofer Jonsson34e24962020-11-23 16:22:10 +0100293 job.invalidate();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200294
295 bool failed = inferenceProcess.runJob(job);
Kristofer Jonsson34e24962020-11-23 16:22:10 +0100296 job.clean();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200297
Bhavik Patelffe845d2020-11-16 12:13:56 +0100298 sendInferenceRsp(req.user_arg,
299 job.output,
300 failed,
301 job.pmuEventConfig,
302 job.pmuCycleCounterEnable,
303 job.pmuEventCount,
304 job.pmuCycleCounterCount);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200305 break;
306 }
Per Åstranddc28b132020-09-28 13:02:18 +0200307 default: {
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100308 char errMsg[128] = {0};
309 snprintf(&errMsg[0],
310 sizeof(errMsg),
311 "Msg: Unknown type: %" PRIu32 " with payload length %" PRIu32 " bytes\n",
312 msg.type,
313 msg.length);
314 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_UNSUPPORTED_TYPE, errMsg);
315 return false;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200316 }
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100317 }
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200318 return true;
319}
320
321void MessageProcess::sendPong() {
322 if (!queueOut.write(ETHOSU_CORE_MSG_PONG)) {
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100323 printf("ERROR: Msg: Failed to write pong response. No mailbox message sent\n");
324 } else {
325 mailbox.sendMessage();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200326 }
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100327}
328
329void MessageProcess::sendVersionRsp() {
Davide Grohmann53cc13d2021-06-01 14:21:42 +0200330 struct ethosu_core_msg_version ver = {
331 ETHOSU_CORE_MSG_VERSION_MAJOR,
332 ETHOSU_CORE_MSG_VERSION_MINOR,
333 ETHOSU_CORE_MSG_VERSION_PATCH,
334 0,
335 };
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100336
337 if (!queueOut.write(ETHOSU_CORE_MSG_VERSION_RSP, ver)) {
338 printf("ERROR: Failed to write version response. No mailbox message sent\n");
339 } else {
340 mailbox.sendMessage();
341 }
342}
343
Davide Grohmann53cc13d2021-06-01 14:21:42 +0200344void MessageProcess::sendCapabilityRsp(uint64_t userArg) {
345 struct ethosu_core_msg_capabilities_rsp capabilities;
346#if defined(ETHOSU)
347 struct ethosu_driver_version driver_version;
348 struct ethosu_hw_info hw_info;
349 ethosu_get_driver_version(&driver_version);
350 struct ethosu_driver *drv = ethosu_reserve_driver();
351 ethosu_get_hw_info(drv, &hw_info);
352 ethosu_release_driver(drv);
353
354 capabilities = {
355 userArg,
356 hw_info.version.version_status,
357 hw_info.version.version_minor,
358 hw_info.version.version_major,
359 hw_info.version.product_major,
360 hw_info.version.arch_patch_rev,
361 hw_info.version.arch_minor_rev,
362 hw_info.version.arch_major_rev,
363 driver_version.patch,
364 driver_version.minor,
365 driver_version.major,
366 hw_info.cfg.macs_per_cc,
367 hw_info.cfg.cmd_stream_version,
368 hw_info.cfg.shram_size,
369 hw_info.cfg.custom_dma,
370 };
371#else
372 capabilities = {
373 userArg,
374 0,
375 0,
376 0,
377 0,
378 0,
379 0,
380 0,
381 0,
382 0,
383 0,
384 0,
385 0,
386 0,
387 0,
388 };
389#endif
390
391 if (!queueOut.write(ETHOSU_CORE_MSG_CAPABILITIES_RSP, capabilities)) {
392 printf("ERROR: Failed to write capability response. No mailbox message sent\n");
393 } else {
394 mailbox.sendMessage();
395 }
396}
397
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100398void MessageProcess::sndErrorRspAndResetQueue(ethosu_core_msg_err_type type, const char *message) {
399 ethosu_core_msg_err error = {0};
400 error.type = type;
401 unsigned int i = 0;
402
403 if (message) {
404 for (; i < (sizeof(error.msg) - 1) && message[i]; i++) {
405 error.msg[i] = message[i];
406 }
407 }
408 printf("ERROR: Msg: \"%s\"\n", message);
409 if (!queueOut.write(ETHOSU_CORE_MSG_ERR, &error)) {
410 printf("ERROR: Msg: Failed to write error response. No mailbox message sent\n");
411 return;
412 }
413 queueIn.reset();
Jonny Svärd44398c82020-10-06 14:18:28 +0200414 mailbox.sendMessage();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200415}
416
Bhavik Patelffe845d2020-11-16 12:13:56 +0100417void MessageProcess::sendInferenceRsp(uint64_t userArg,
418 vector<DataPtr> &ofm,
419 bool failed,
420 vector<uint8_t> &pmuEventConfig,
421 uint32_t pmuCycleCounterEnable,
422 vector<uint32_t> &pmuEventCount,
423 uint64_t pmuCycleCounterCount) {
424 ethosu_core_inference_rsp rsp = {
425 .pmu_event_count =
426 {
427 0,
428 },
429 };
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200430
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200431 rsp.user_arg = userArg;
432 rsp.ofm_count = ofm.size();
433 rsp.status = failed ? ETHOSU_CORE_STATUS_ERROR : ETHOSU_CORE_STATUS_OK;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200434
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200435 for (size_t i = 0; i < ofm.size(); ++i) {
436 rsp.ofm_size[i] = ofm[i].size;
437 }
438
Bhavik Patelffe845d2020-11-16 12:13:56 +0100439 for (size_t i = 0; i < pmuEventConfig.size(); i++) {
440 rsp.pmu_event_config[i] = pmuEventConfig[i];
441 }
442 rsp.pmu_cycle_counter_enable = pmuCycleCounterEnable;
443 for (size_t i = 0; i < pmuEventCount.size(); i++) {
444 rsp.pmu_event_count[i] = pmuEventCount[i];
445 }
446 rsp.pmu_cycle_counter_count = pmuCycleCounterCount;
447
Per Åstrand91a91732020-09-25 15:04:26 +0200448 printf("Sending inference response. userArg=0x%" PRIx64 ", ofm_count=%" PRIu32 ", status=%" PRIu32 "\n",
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200449 rsp.user_arg,
450 rsp.ofm_count,
451 rsp.status);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200452
453 if (!queueOut.write(ETHOSU_CORE_MSG_INFERENCE_RSP, rsp)) {
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100454 printf("ERROR: Msg: Failed to write inference response. No mailbox message sent\n");
455 } else {
456 mailbox.sendMessage();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200457 }
458}
Jonny Svärd44398c82020-10-06 14:18:28 +0200459
460void MessageProcess::mailboxCallback(void *userArg) {
461 MessageProcess *_this = reinterpret_cast<MessageProcess *>(userArg);
462 _this->handleIrq();
463}
464
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200465} // namespace MessageProcess