2 * Copyright (C) 2016 Google, Inc.
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.
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.
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>
26 #if defined(CONFIG_NANOHUB_MAILBOX)
30 #define READ_ACK_TIMEOUT_MS 10
31 #define READ_MSG_TIMEOUT_MS 70
33 #define RESEND_SHORT_DELAY_US 500 /* 500us - 1ms */
34 #define RESEND_LONG_DELAY_US 100000 /* 100ms - 200ms */
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
43 static uint32_t crc32_word(uint32_t crc
, uint32_t data
, int cnt
)
48 for (i
= 0; i
< cnt
; i
++)
49 crc
= (crc
<< 4) ^ crc_table
[crc
>> 28];
54 uint32_t crc32(const uint8_t *buffer
, int length
, uint32_t crc
)
56 uint32_t *data
= (uint32_t *)buffer
;
60 /* word by word crc32 */
61 for (i
= 0; i
< (length
>> 2); i
++)
62 crc
= crc32_word(crc
, data
[i
], 8);
64 /* zero pad last word if required */
66 for (i
*= 4, word
= 0; i
< length
; i
++)
67 word
|= buffer
[i
] << ((i
& 0x3) * 8);
68 crc
= crc32_word(crc
, word
, 8);
74 static inline size_t pad(size_t length
)
76 return (length
+ 3) & ~3;
79 static inline size_t tot_len(size_t length
)
81 /* [TYPE:1] [LENGTH:3] [DATA] [PAD:0-3] [CRC:4] */
82 return sizeof(uint32_t) + pad(length
) + sizeof(uint32_t);
85 static struct nanohub_packet_pad
*packet_alloc(int flags
)
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
;
95 #ifdef PACKET_LOW_DEBUG
102 #define GET_ACT_STRING(act) \
103 ((act) == ca_tx ? 'W' : ((act) == ca_rx_ack ? 'A' : 'R'))
105 /* This function is from hostIntfGetFooter function on nanohub kernel. */
106 static inline struct nanohub_packet_crc
*get_footer(struct nanohub_packet
*packet
)
108 return (void *)(packet
+ sizeof(*packet
) + packet
->len
);
111 static inline void packet_disassemble(void *buf
, int ret
, enum comms_action act
)
113 struct nanohub_packet
*packet
= (struct nanohub_packet
*)buf
;
114 struct nanohub_packet_crc
*footer
= get_footer(packet
);
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
);
124 #define packet_disassemble(a, b, c) do {} while (0)
127 static int packet_create(struct nanohub_packet
*packet
, uint32_t seq
,
128 uint32_t reason
, uint8_t len
, const uint8_t *data
,
131 struct nanohub_packet_crc crc
;
132 int ret
= sizeof(struct nanohub_packet
) + len
+
133 sizeof(struct nanohub_packet_crc
);
136 packet
->sync
= COMMS_SYNC
;
138 packet
->reason
= reason
;
142 if (copy_from_user(packet
->data
, data
, len
) !=
146 memcpy(packet
->data
, data
, len
);
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
));
157 packet_disassemble(packet
, ret
, ca_tx
);
162 static int packet_verify(struct nanohub_packet
*packet
)
164 struct nanohub_packet_crc crc
;
168 crc32((uint8_t *) packet
,
169 sizeof(struct nanohub_packet
) + packet
->len
, ~0);
172 memcmp(&crc
.crc
, &packet
->data
[packet
->len
],
173 sizeof(struct nanohub_packet_crc
));
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
]);
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],
189 static void packet_free(struct nanohub_packet_pad
*packet
)
194 static int read_ack(struct nanohub_data
*data
, struct nanohub_packet
*response
,
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
);
202 for (i
= 0; time_before_eq(jiffies
, end
); i
++) {
204 data
->comms
.read(data
, (uint8_t *) response
, max_size
,
206 packet_disassemble(response
, ret
, ca_rx_ack
);
209 pr_debug("nanohub: read_ack: %d: empty packet\n", i
);
212 } else if (ret
< sizeof(struct nanohub_packet
)) {
213 pr_debug("nanohub: read_ack: %d: too small\n", i
);
217 sizeof(struct nanohub_packet
) + response
->len
+
218 sizeof(struct nanohub_packet_crc
)) {
219 pr_debug("nanohub: read_ack: %d: too small length\n",
224 sizeof(struct nanohub_packet
) + response
->len
+
225 sizeof(struct nanohub_packet_crc
)) {
226 pr_debug("nanohub: read_ack: %d: wrong length\n", i
);
229 } else if (packet_verify(response
) != 0) {
230 pr_debug("nanohub: read_ack: %d: invalid crc\n", i
);
241 static int read_msg(struct nanohub_data
*data
, struct nanohub_packet
*response
,
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
);
249 for (i
= 0; time_before_eq(jiffies
, end
); i
++) {
251 data
->comms
.read(data
, (uint8_t *) response
, max_size
,
253 packet_disassemble(response
, ret
, ca_rx
);
256 pr_debug("nanohub: read_msg: %d: empty packet\n", i
);
259 } else if (ret
< sizeof(struct nanohub_packet
)) {
260 pr_debug("nanohub: read_msg: %d: too small\n", i
);
264 sizeof(struct nanohub_packet
) + response
->len
+
265 sizeof(struct nanohub_packet_crc
)) {
266 pr_debug("nanohub: read_msg: %d: too small length\n",
271 sizeof(struct nanohub_packet
) + response
->len
+
272 sizeof(struct nanohub_packet_crc
)) {
273 pr_debug("nanohub: read_msg: %d: wrong length\n", i
);
276 } else if (packet_verify(response
) != 0) {
277 pr_debug("nanohub: read_msg: %d: invalid crc\n", i
);
288 static int get_reply(struct nanohub_data
*data
, struct nanohub_packet
*response
,
293 ret
= read_ack(data
, response
, data
->comms
.timeout_ack
);
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
,
301 read_msg(data
, response
, data
->comms
.timeout_reply
);
306 uint8_t *b
= (uint8_t *) response
;
308 #ifdef CONFIG_NANOHUB_MAILBOX /* remove invalid error check */
309 if ((response
->reason
== CMD_COMMS_READ
) || (response
->reason
== CMD_COMMS_WRITE
))
312 for (i
= 0; i
< ret
; i
+= 25)
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],
322 if (response
->reason
== CMD_COMMS_NACK
)
324 else if (response
->reason
== CMD_COMMS_BUSY
)
328 if (response
->seq
!= seq
)
333 uint8_t *b
= (uint8_t *) response
;
334 for (i
= 0; i
< ret
; i
+= 25)
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],
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
)
357 ret
= data
->comms
.write(data
, (uint8_t *)&pad
->packet
, packet_size
,
358 data
->comms
.timeout_write
);
360 if (ret
== packet_size
) {
361 ret
= get_reply(data
, &pad
->packet
, seq
);
364 if (pad
->packet
.len
> 0) {
365 if (pad
->packet
.len
> rx_len
) {
366 memcpy(rx
, pad
->packet
.data
, rx_len
);
369 memcpy(rx
, pad
->packet
.data
,
371 ret
= pad
->packet
.len
;
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
)
389 struct nanohub_packet_pad
*pad
= packet_alloc(GFP_KERNEL
);
399 seq
= data
->comms
.seq
++;
402 data
->comms
.open(data
);
403 get_monotonic_boottime(&ts
);
404 boottime
= timespec_to_ns(&ts
);
406 packet_create(&pad
->packet
, seq
, cmd
, sizeof(boottime
),
407 (uint8_t *)&boottime
, false);
410 nanohub_comms_tx_rx(data
, pad
, packet_size
, seq
, rx
,
413 if (nanohub_wakeup_eom(data
,
414 (ret
== ERROR_BUSY
) ||
415 (ret
== ERROR_NACK
&& retrans_cnt
>= 0)))
418 data
->comms
.close(data
);
420 if (ret
== ERROR_NACK
) {
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);
429 } while ((ret
== ERROR_BUSY
)
430 || (ret
== ERROR_NACK
&& retrans_cnt
>= 0));
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
)
443 struct nanohub_packet_pad
*pad
= packet_alloc(GFP_KERNEL
);
451 seq
= data
->comms
.seq
++;
455 packet_create(&pad
->packet
, seq
, cmd
, tx_len
, tx
, user
);
457 data
->comms
.open(data
);
459 nanohub_comms_tx_rx(data
, pad
, packet_size
, seq
, rx
,
462 if (nanohub_wakeup_eom(data
,
463 (ret
== ERROR_BUSY
) ||
464 (ret
== ERROR_NACK
&& retrans_cnt
>= 0)))
467 data
->comms
.close(data
);
469 if (ret
== ERROR_NACK
) {
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);
478 } while ((ret
== ERROR_BUSY
)
479 || (ret
== ERROR_NACK
&& retrans_cnt
>= 0));
486 struct firmware_header
{
492 struct firmware_chunk
{
498 static int nanohub_comms_download(struct nanohub_data
*data
,
499 const uint8_t *image
, size_t length
,
503 struct firmware_header header
;
504 struct firmware_chunk chunk
;
505 int max_chunk_size
= sizeof(chunk
.data
);
509 uint8_t chunk_reply
, upload_reply
= 0, last_reply
= 0;
510 uint32_t clear_interrupts
[8] = { 0x00000008 };
514 header
.size
= cpu_to_le32(length
);
515 header
.crc
= cpu_to_le32(~crc32(image
, length
, ~0));
517 if (request_wakeup(data
))
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
);
525 if (ret
== 1 && accepted
== 1) {
527 if (request_wakeup(data
))
531 chunk
.offset
= cpu_to_le32(offset
);
532 if (offset
+ max_chunk_size
> length
)
533 chunk_size
= length
- offset
;
535 chunk_size
= max_chunk_size
;
536 memcpy(chunk
.data
, image
+ offset
, chunk_size
);
539 nanohub_comms_tx_rx_retrans(data
,
540 CMD_COMMS_KERNEL_CHUNK
,
541 (const uint8_t *)&chunk
,
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
);
556 release_wakeup(data
);
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
),
566 } else if (chunk_reply
== CHUNK_REPLY_RESEND
) {
567 if (last_reply
== CHUNK_REPLY_RESEND
)
568 delay
= RESEND_LONG_DELAY_US
;
570 delay
= RESEND_SHORT_DELAY_US
;
571 } else if (chunk_reply
== CHUNK_REPLY_RESTART
)
573 else if (chunk_reply
== CHUNK_REPLY_CANCEL
||
575 CHUNK_REPLY_CANCEL_NO_RETRY
) {
576 release_wakeup(data
);
579 last_reply
= chunk_reply
;
580 } else if (ret
<= 0) {
581 release_wakeup(data
);
584 release_wakeup(data
);
586 usleep_range(delay
, delay
* 2);
587 } while (offset
< length
);
591 if (upload_reply
== UPLOAD_REPLY_PROCESSING
)
592 usleep_range(RESEND_LONG_DELAY_US
,
593 RESEND_LONG_DELAY_US
* 2);
595 if (request_wakeup(data
)) {
596 ret
= sizeof(upload_reply
);
597 upload_reply
= UPLOAD_REPLY_PROCESSING
;
600 ret
= nanohub_comms_tx_rx_retrans(data
,
601 CMD_COMMS_FINISH_KERNEL_UPLOAD
,
603 &upload_reply
, sizeof(upload_reply
),
605 release_wakeup(data
);
606 } while (ret
== sizeof(upload_reply
) &&
607 upload_reply
== UPLOAD_REPLY_PROCESSING
);
609 pr_info("nanohub: nanohub_comms_download: ret=%d, upload_reply=%d\n",
615 int nanohub_comms_kernel_download(struct nanohub_data
*data
,
616 const uint8_t *image
, size_t length
)
618 return nanohub_comms_download(data
, image
, length
,
619 COMMS_FLASH_KERNEL_ID
);
622 int nanohub_comms_app_download(struct nanohub_data
*data
, const uint8_t *image
,
625 return nanohub_comms_download(data
, image
, length
, COMMS_FLASH_APP_ID
);