[COMMON] nanohub: add contexthub driver
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / drivers / staging / nanohub / comms.c
1 /*
2 * Copyright (C) 2016 Google, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15 #include <linux/kernel.h>
16 #include <linux/slab.h>
17 #include <linux/uaccess.h>
18 #include <linux/delay.h>
19 #include <linux/slab.h>
20 #include <linux/semaphore.h>
21 #include <linux/gpio.h>
22
23 #include "main.h"
24 #include "comms.h"
25
26 #if defined(CONFIG_NANOHUB_MAILBOX)
27 #include "chub.h"
28 #endif
29
30 #define READ_ACK_TIMEOUT_MS 10
31 #define READ_MSG_TIMEOUT_MS 70
32
33 #define RESEND_SHORT_DELAY_US 500 /* 500us - 1ms */
34 #define RESEND_LONG_DELAY_US 100000 /* 100ms - 200ms */
35
36 static const uint32_t crc_table[] = {
37 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
38 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
39 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
40 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
41 };
42
43 static uint32_t crc32_word(uint32_t crc, uint32_t data, int cnt)
44 {
45 int i;
46 crc = crc ^ data;
47
48 for (i = 0; i < cnt; i++)
49 crc = (crc << 4) ^ crc_table[crc >> 28];
50
51 return crc;
52 }
53
54 uint32_t crc32(const uint8_t *buffer, int length, uint32_t crc)
55 {
56 uint32_t *data = (uint32_t *)buffer;
57 uint32_t word;
58 int i;
59
60 /* word by word crc32 */
61 for (i = 0; i < (length >> 2); i++)
62 crc = crc32_word(crc, data[i], 8);
63
64 /* zero pad last word if required */
65 if (length & 0x3) {
66 for (i *= 4, word = 0; i < length; i++)
67 word |= buffer[i] << ((i & 0x3) * 8);
68 crc = crc32_word(crc, word, 8);
69 }
70
71 return crc;
72 }
73
74 static inline size_t pad(size_t length)
75 {
76 return (length + 3) & ~3;
77 }
78
79 static inline size_t tot_len(size_t length)
80 {
81 /* [TYPE:1] [LENGTH:3] [DATA] [PAD:0-3] [CRC:4] */
82 return sizeof(uint32_t) + pad(length) + sizeof(uint32_t);
83 }
84
85 static struct nanohub_packet_pad *packet_alloc(int flags)
86 {
87 int len =
88 sizeof(struct nanohub_packet_pad) + MAX_UINT8 +
89 sizeof(struct nanohub_packet_crc);
90 uint8_t *packet = kmalloc(len, flags);
91 memset(packet, 0xFF, len);
92 return (struct nanohub_packet_pad *)packet;
93 }
94
95 #ifdef PACKET_LOW_DEBUG
96 enum comms_action {
97 ca_tx,
98 ca_rx_ack,
99 ca_rx,
100 };
101
102 #define GET_ACT_STRING(act) \
103 ((act) == ca_tx ? 'W' : ((act) == ca_rx_ack ? 'A' : 'R'))
104
105 /* This function is from hostIntfGetFooter function on nanohub kernel. */
106 static inline struct nanohub_packet_crc *get_footer(struct nanohub_packet *packet)
107 {
108 return (void *)(packet + sizeof(*packet) + packet->len);
109 }
110
111 static inline void packet_disassemble(void *buf, int ret, enum comms_action act)
112 {
113 struct nanohub_packet *packet = (struct nanohub_packet *)buf;
114 struct nanohub_packet_crc *footer = get_footer(packet);
115
116 DEBUG_PRINT(KERN_DEBUG,
117 "%c-PACKET(ret:%d):buf:%p,sync:0x%x,seq:0x%x,reason:0x%x,len:%d,crc:0x%x\n",
118 GET_ACT_STRING(act), ret, (unsigned long)buf,
119 (unsigned int)packet->sync, (unsigned int)packet->seq,
120 (unsigned int)packet->reason, (unsigned int)packet->len,
121 (unsigned int)footer->crc);
122 }
123 #else
124 #define packet_disassemble(a, b, c) do {} while (0)
125 #endif
126
127 static int packet_create(struct nanohub_packet *packet, uint32_t seq,
128 uint32_t reason, uint8_t len, const uint8_t *data,
129 bool user)
130 {
131 struct nanohub_packet_crc crc;
132 int ret = sizeof(struct nanohub_packet) + len +
133 sizeof(struct nanohub_packet_crc);
134
135 if (packet) {
136 packet->sync = COMMS_SYNC;
137 packet->seq = seq;
138 packet->reason = reason;
139 packet->len = len;
140 if (len > 0) {
141 if (user) {
142 if (copy_from_user(packet->data, data, len) !=
143 0)
144 ret = ERROR_NACK;
145 } else {
146 memcpy(packet->data, data, len);
147 }
148 }
149 crc.crc =
150 crc32((uint8_t *) packet,
151 sizeof(struct nanohub_packet) + len, ~0);
152 memcpy(&packet->data[len], &crc.crc,
153 sizeof(struct nanohub_packet_crc));
154 } else {
155 ret = ERROR_NACK;
156 }
157 packet_disassemble(packet, ret, ca_tx);
158
159 return ret;
160 }
161
162 static int packet_verify(struct nanohub_packet *packet)
163 {
164 struct nanohub_packet_crc crc;
165 int cmp;
166
167 crc.crc =
168 crc32((uint8_t *) packet,
169 sizeof(struct nanohub_packet) + packet->len, ~0);
170
171 cmp =
172 memcmp(&crc.crc, &packet->data[packet->len],
173 sizeof(struct nanohub_packet_crc));
174
175 if (cmp != 0) {
176 uint8_t *ptr = (uint8_t *)packet;
177 pr_debug("nanohub: gen crc: %08x, got crc: %08x\n", crc.crc,
178 *(uint32_t *)&packet->data[packet->len]);
179 pr_debug(
180 "nanohub: %02x [%02x %02x %02x %02x] [%02x %02x %02x %02x] [%02x] [%02x %02x %02x %02x\n",
181 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6],
182 ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12],
183 ptr[13]);
184 }
185
186 return cmp;
187 }
188
189 static void packet_free(struct nanohub_packet_pad *packet)
190 {
191 kfree(packet);
192 }
193
194 static int read_ack(struct nanohub_data *data, struct nanohub_packet *response,
195 int timeout)
196 {
197 int ret, i;
198 const int max_size = sizeof(struct nanohub_packet) + MAX_UINT8 +
199 sizeof(struct nanohub_packet_crc);
200 unsigned long end = jiffies + msecs_to_jiffies(READ_ACK_TIMEOUT_MS);
201
202 for (i = 0; time_before_eq(jiffies, end); i++) {
203 ret =
204 data->comms.read(data, (uint8_t *) response, max_size,
205 timeout);
206 packet_disassemble(response, ret, ca_rx_ack);
207
208 if (ret == 0) {
209 pr_debug("nanohub: read_ack: %d: empty packet\n", i);
210 ret = ERROR_NACK;
211 continue;
212 } else if (ret < sizeof(struct nanohub_packet)) {
213 pr_debug("nanohub: read_ack: %d: too small\n", i);
214 ret = ERROR_NACK;
215 continue;
216 } else if (ret <
217 sizeof(struct nanohub_packet) + response->len +
218 sizeof(struct nanohub_packet_crc)) {
219 pr_debug("nanohub: read_ack: %d: too small length\n",
220 i);
221 ret = ERROR_NACK;
222 continue;
223 } else if (ret !=
224 sizeof(struct nanohub_packet) + response->len +
225 sizeof(struct nanohub_packet_crc)) {
226 pr_debug("nanohub: read_ack: %d: wrong length\n", i);
227 ret = ERROR_NACK;
228 break;
229 } else if (packet_verify(response) != 0) {
230 pr_debug("nanohub: read_ack: %d: invalid crc\n", i);
231 ret = ERROR_NACK;
232 break;
233 } else {
234 break;
235 }
236 }
237
238 return ret;
239 }
240
241 static int read_msg(struct nanohub_data *data, struct nanohub_packet *response,
242 int timeout)
243 {
244 int ret, i;
245 const int max_size = sizeof(struct nanohub_packet) + MAX_UINT8 +
246 sizeof(struct nanohub_packet_crc);
247 unsigned long end = jiffies + msecs_to_jiffies(READ_MSG_TIMEOUT_MS);
248
249 for (i = 0; time_before_eq(jiffies, end); i++) {
250 ret =
251 data->comms.read(data, (uint8_t *) response, max_size,
252 timeout);
253 packet_disassemble(response, ret, ca_rx);
254
255 if (ret == 0) {
256 pr_debug("nanohub: read_msg: %d: empty packet\n", i);
257 ret = ERROR_NACK;
258 continue;
259 } else if (ret < sizeof(struct nanohub_packet)) {
260 pr_debug("nanohub: read_msg: %d: too small\n", i);
261 ret = ERROR_NACK;
262 continue;
263 } else if (ret <
264 sizeof(struct nanohub_packet) + response->len +
265 sizeof(struct nanohub_packet_crc)) {
266 pr_debug("nanohub: read_msg: %d: too small length\n",
267 i);
268 ret = ERROR_NACK;
269 continue;
270 } else if (ret !=
271 sizeof(struct nanohub_packet) + response->len +
272 sizeof(struct nanohub_packet_crc)) {
273 pr_debug("nanohub: read_msg: %d: wrong length\n", i);
274 ret = ERROR_NACK;
275 break;
276 } else if (packet_verify(response) != 0) {
277 pr_debug("nanohub: read_msg: %d: invalid crc\n", i);
278 ret = ERROR_NACK;
279 break;
280 } else {
281 break;
282 }
283 }
284
285 return ret;
286 }
287
288 static int get_reply(struct nanohub_data *data, struct nanohub_packet *response,
289 uint32_t seq)
290 {
291 int ret;
292
293 ret = read_ack(data, response, data->comms.timeout_ack);
294
295 if (ret >= 0 && response->seq == seq) {
296 if (response->reason == CMD_COMMS_ACK) {
297 if (response->len == sizeof(data->interrupts))
298 memcpy(data->interrupts, response->data,
299 response->len);
300 ret =
301 read_msg(data, response, data->comms.timeout_reply);
302 if (ret < 0)
303 ret = ERROR_NACK;
304 } else {
305 int i;
306 uint8_t *b = (uint8_t *) response;
307
308 #ifdef CONFIG_NANOHUB_MAILBOX /* remove invalid error check */
309 if ((response->reason == CMD_COMMS_READ) || (response->reason == CMD_COMMS_WRITE))
310 return ret;
311 #endif
312 for (i = 0; i < ret; i += 25)
313 pr_debug(
314 "nanohub: %d: %d: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
315 ret, i, b[i], b[i + 1], b[i + 2], b[i + 3],
316 b[i + 4], b[i + 5], b[i + 6], b[i + 7],
317 b[i + 8], b[i + 9], b[i + 10], b[i + 11],
318 b[i + 12], b[i + 13], b[i + 14], b[i + 15],
319 b[i + 16], b[i + 17], b[i + 18], b[i + 19],
320 b[i + 20], b[i + 21], b[i + 22], b[i + 23],
321 b[i + 24]);
322 if (response->reason == CMD_COMMS_NACK)
323 ret = ERROR_NACK;
324 else if (response->reason == CMD_COMMS_BUSY)
325 ret = ERROR_BUSY;
326 }
327
328 if (response->seq != seq)
329 ret = ERROR_NACK;
330 } else {
331 if (ret >= 0) {
332 int i;
333 uint8_t *b = (uint8_t *) response;
334 for (i = 0; i < ret; i += 25)
335 pr_debug(
336 "nanohub: %d: %d: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
337 ret, i, b[i], b[i + 1], b[i + 2], b[i + 3],
338 b[i + 4], b[i + 5], b[i + 6], b[i + 7],
339 b[i + 8], b[i + 9], b[i + 10], b[i + 11],
340 b[i + 12], b[i + 13], b[i + 14], b[i + 15],
341 b[i + 16], b[i + 17], b[i + 18], b[i + 19],
342 b[i + 20], b[i + 21], b[i + 22], b[i + 23],
343 b[i + 24]);
344 }
345 ret = ERROR_NACK;
346 }
347
348 return ret;
349 }
350
351 static int nanohub_comms_tx_rx(struct nanohub_data *data,
352 struct nanohub_packet_pad *pad, int packet_size,
353 uint32_t seq, uint8_t *rx, size_t rx_len)
354 {
355 int ret;
356
357 ret = data->comms.write(data, (uint8_t *)&pad->packet, packet_size,
358 data->comms.timeout_write);
359
360 if (ret == packet_size) {
361 ret = get_reply(data, &pad->packet, seq);
362
363 if (ret >= 0) {
364 if (pad->packet.len > 0) {
365 if (pad->packet.len > rx_len) {
366 memcpy(rx, pad->packet.data, rx_len);
367 ret = rx_len;
368 } else {
369 memcpy(rx, pad->packet.data,
370 pad->packet.len);
371 ret = pad->packet.len;
372 }
373 } else {
374 ret = 0;
375 }
376 }
377 } else {
378 ret = ERROR_NACK;
379 }
380
381 return ret;
382 }
383
384 int nanohub_comms_rx_retrans_boottime(struct nanohub_data *data, uint32_t cmd,
385 uint8_t *rx, size_t rx_len,
386 int retrans_cnt, int retrans_delay)
387 {
388 int packet_size = 0;
389 struct nanohub_packet_pad *pad = packet_alloc(GFP_KERNEL);
390 int delay = 0;
391 int ret;
392 uint32_t seq;
393 struct timespec ts;
394 s64 boottime;
395
396 if (pad == NULL)
397 return ERROR_NACK;
398
399 seq = data->comms.seq++;
400
401 do {
402 data->comms.open(data);
403 get_monotonic_boottime(&ts);
404 boottime = timespec_to_ns(&ts);
405 packet_size =
406 packet_create(&pad->packet, seq, cmd, sizeof(boottime),
407 (uint8_t *)&boottime, false);
408
409 ret =
410 nanohub_comms_tx_rx(data, pad, packet_size, seq, rx,
411 rx_len);
412
413 if (nanohub_wakeup_eom(data,
414 (ret == ERROR_BUSY) ||
415 (ret == ERROR_NACK && retrans_cnt >= 0)))
416 ret = -EFAULT;
417
418 data->comms.close(data);
419
420 if (ret == ERROR_NACK) {
421 retrans_cnt--;
422 delay += retrans_delay;
423 if (retrans_cnt >= 0)
424 udelay(retrans_delay);
425 } else if (ret == ERROR_BUSY) {
426 usleep_range(RESEND_LONG_DELAY_US,
427 RESEND_LONG_DELAY_US * 2);
428 }
429 } while ((ret == ERROR_BUSY)
430 || (ret == ERROR_NACK && retrans_cnt >= 0));
431
432 packet_free(pad);
433
434 return ret;
435 }
436
437 int nanohub_comms_tx_rx_retrans(struct nanohub_data *data, uint32_t cmd,
438 const uint8_t *tx, uint8_t tx_len,
439 uint8_t *rx, size_t rx_len, bool user,
440 int retrans_cnt, int retrans_delay)
441 {
442 int packet_size = 0;
443 struct nanohub_packet_pad *pad = packet_alloc(GFP_KERNEL);
444 int delay = 0;
445 int ret;
446 uint32_t seq;
447
448 if (pad == NULL)
449 return ERROR_NACK;
450
451 seq = data->comms.seq++;
452
453 do {
454 packet_size =
455 packet_create(&pad->packet, seq, cmd, tx_len, tx, user);
456
457 data->comms.open(data);
458 ret =
459 nanohub_comms_tx_rx(data, pad, packet_size, seq, rx,
460 rx_len);
461
462 if (nanohub_wakeup_eom(data,
463 (ret == ERROR_BUSY) ||
464 (ret == ERROR_NACK && retrans_cnt >= 0)))
465 ret = -EFAULT;
466
467 data->comms.close(data);
468
469 if (ret == ERROR_NACK) {
470 retrans_cnt--;
471 delay += retrans_delay;
472 if (retrans_cnt >= 0)
473 udelay(retrans_delay);
474 } else if (ret == ERROR_BUSY) {
475 usleep_range(RESEND_LONG_DELAY_US,
476 RESEND_LONG_DELAY_US * 2);
477 }
478 } while ((ret == ERROR_BUSY)
479 || (ret == ERROR_NACK && retrans_cnt >= 0));
480
481 packet_free(pad);
482
483 return ret;
484 }
485
486 struct firmware_header {
487 uint32_t size;
488 uint32_t crc;
489 uint8_t type;
490 } __packed;
491
492 struct firmware_chunk {
493 uint32_t offset;
494 uint8_t data[128];
495 }
496 __packed;
497
498 static int nanohub_comms_download(struct nanohub_data *data,
499 const uint8_t *image, size_t length,
500 uint8_t type)
501 {
502 uint8_t accepted;
503 struct firmware_header header;
504 struct firmware_chunk chunk;
505 int max_chunk_size = sizeof(chunk.data);
506 int chunk_size;
507 uint32_t offset = 0;
508 int ret;
509 uint8_t chunk_reply, upload_reply = 0, last_reply = 0;
510 uint32_t clear_interrupts[8] = { 0x00000008 };
511 uint32_t delay;
512
513 header.type = type;
514 header.size = cpu_to_le32(length);
515 header.crc = cpu_to_le32(~crc32(image, length, ~0));
516
517 if (request_wakeup(data))
518 return -ERESTARTSYS;
519 ret = nanohub_comms_tx_rx_retrans(data, CMD_COMMS_START_KERNEL_UPLOAD,
520 (const uint8_t *)&header,
521 sizeof(header), &accepted,
522 sizeof(accepted), false, 10, 10);
523 release_wakeup(data);
524
525 if (ret == 1 && accepted == 1) {
526 do {
527 if (request_wakeup(data))
528 continue;
529
530 delay = 0;
531 chunk.offset = cpu_to_le32(offset);
532 if (offset + max_chunk_size > length)
533 chunk_size = length - offset;
534 else
535 chunk_size = max_chunk_size;
536 memcpy(chunk.data, image + offset, chunk_size);
537
538 ret =
539 nanohub_comms_tx_rx_retrans(data,
540 CMD_COMMS_KERNEL_CHUNK,
541 (const uint8_t *)&chunk,
542 sizeof(uint32_t) +
543 chunk_size,
544 &chunk_reply,
545 sizeof(chunk_reply),
546 false, 10, 10);
547
548 pr_debug("nanohub: ret=%d, chunk_reply=%d, offset=%d\n",
549 ret, chunk_reply, offset);
550 if (ret == sizeof(chunk_reply)) {
551 if (chunk_reply == CHUNK_REPLY_ACCEPTED) {
552 offset += chunk_size;
553 } else if (chunk_reply == CHUNK_REPLY_WAIT) {
554 ret = nanohub_wait_for_interrupt(data);
555 if (ret < 0) {
556 release_wakeup(data);
557 continue;
558 }
559 nanohub_comms_tx_rx_retrans(data,
560 CMD_COMMS_CLR_GET_INTR,
561 (uint8_t *)clear_interrupts,
562 sizeof(clear_interrupts),
563 (uint8_t *)data->interrupts,
564 sizeof(data->interrupts),
565 false, 10, 0);
566 } else if (chunk_reply == CHUNK_REPLY_RESEND) {
567 if (last_reply == CHUNK_REPLY_RESEND)
568 delay = RESEND_LONG_DELAY_US;
569 else
570 delay = RESEND_SHORT_DELAY_US;
571 } else if (chunk_reply == CHUNK_REPLY_RESTART)
572 offset = 0;
573 else if (chunk_reply == CHUNK_REPLY_CANCEL ||
574 chunk_reply ==
575 CHUNK_REPLY_CANCEL_NO_RETRY) {
576 release_wakeup(data);
577 break;
578 }
579 last_reply = chunk_reply;
580 } else if (ret <= 0) {
581 release_wakeup(data);
582 break;
583 }
584 release_wakeup(data);
585 if (delay > 0)
586 usleep_range(delay, delay * 2);
587 } while (offset < length);
588 }
589
590 do {
591 if (upload_reply == UPLOAD_REPLY_PROCESSING)
592 usleep_range(RESEND_LONG_DELAY_US,
593 RESEND_LONG_DELAY_US * 2);
594
595 if (request_wakeup(data)) {
596 ret = sizeof(upload_reply);
597 upload_reply = UPLOAD_REPLY_PROCESSING;
598 continue;
599 }
600 ret = nanohub_comms_tx_rx_retrans(data,
601 CMD_COMMS_FINISH_KERNEL_UPLOAD,
602 NULL, 0,
603 &upload_reply, sizeof(upload_reply),
604 false, 10, 10);
605 release_wakeup(data);
606 } while (ret == sizeof(upload_reply) &&
607 upload_reply == UPLOAD_REPLY_PROCESSING);
608
609 pr_info("nanohub: nanohub_comms_download: ret=%d, upload_reply=%d\n",
610 ret, upload_reply);
611
612 return 0;
613 }
614
615 int nanohub_comms_kernel_download(struct nanohub_data *data,
616 const uint8_t *image, size_t length)
617 {
618 return nanohub_comms_download(data, image, length,
619 COMMS_FLASH_KERNEL_ID);
620 }
621
622 int nanohub_comms_app_download(struct nanohub_data *data, const uint8_t *image,
623 size_t length)
624 {
625 return nanohub_comms_download(data, image, length, COMMS_FLASH_APP_ID);
626 }