summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2016-10-04 08:35:11 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-10-04 21:13:54 +0200
commit331391d686ad87915a69a686220f01a20a7fd8e1 (patch)
tree569d86153ecbbf2b06005f5f7d4ee168f4c62406 /scripts
parent1a43860506f293498b989822fb16444c602d0000 (diff)
downloadbarebox-331391d686ad87915a69a686220f01a20a7fd8e1.tar.gz
barebox-331391d686ad87915a69a686220f01a20a7fd8e1.tar.xz
scripts: kwboot: try to resync on packet boundary after receiving a NAK
If we sent the boot message too often the CPU might already have started to interpret this as an xmodem packet. As sender and receiver are not in sync it's impossible to transfer a packet successfully. So when we get a NAK send '\xff' bytes until the receiver reaches the packet boundary. When we send too many the SoC replies with a NAK for each byte and doesn't interpret it as the start of a new package (which must start with SOH == '\x01'). A slower alternative would be to wait for another NAK which is sent when reception of the already started packet times out. This was tested on an Armada XP based machine with bootrom version 1.20. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/kwboot.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/scripts/kwboot.c b/scripts/kwboot.c
index 9b0d1d0602..9d680dc576 100644
--- a/scripts/kwboot.c
+++ b/scripts/kwboot.c
@@ -349,6 +349,48 @@ kwboot_xm_makeblock(struct kwboot_block *block, const void *data,
return n;
}
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static int
+kwboot_xm_resync(int fd)
+{
+ /*
+ * When the SoC has a different perception of where the package boundary
+ * is, just resending the packet doesn't help. To resync send 0xff until
+ * we get another NAK.
+ * The BootROM code (of the Armada XP at least) doesn't interpret 0xff
+ * as a start of a package and sends a NAK for each 0xff when waiting
+ * for SOH, so it's possible to send >1 byte without the SoC starting a
+ * new frame.
+ * When there is no response after sizeof(struct kwboot_block) bytes,
+ * there is another problem.
+ */
+ int rc;
+ char buf[sizeof(struct kwboot_block)];
+ unsigned interval = 1;
+ unsigned len;
+ char *p = buf;
+
+ memset(buf, 0xff, sizeof(buf));
+
+ while (interval <= sizeof(buf)) {
+ len = min(interval, buf + sizeof(buf) - p);
+ rc = kwboot_tty_send(fd, p, len);
+ if (rc)
+ return rc;
+
+ kwboot_tty_recv(fd, p, len, KWBOOT_BLK_RSP_TIMEO);
+ if (*p != 0xff)
+ /* got at least one char, if it's a NAK we're synced. */
+ return (*p == NAK);
+
+ p += len;
+ interval *= 2;
+ }
+
+ return 0;
+}
+
static int
kwboot_xm_sendblock(int fd, struct kwboot_block *block)
{
@@ -371,7 +413,9 @@ kwboot_xm_sendblock(int fd, struct kwboot_block *block)
} while (c != ACK && c != NAK && c != CAN);
- if (c != ACK)
+ if (c == NAK && kwboot_xm_resync(fd))
+ kwboot_progress(-1, 'S');
+ else if (c != ACK)
kwboot_progress(-1, '+');
} while (c == NAK && retries-- > 0);