public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: "Pali Rohár" <pali@kernel.org>
To: "Stefan Roese" <sr@denx.de>, "Marek Behún" <marek.behun@nic.cz>,
	"Tony Dinh" <mibodhi@gmail.com>
Cc: u-boot@lists.denx.de
Subject: [PATCH u-boot-marvell 04/10] tools: kwboot: Use separate thread for sending boot message pattern
Date: Wed,  2 Mar 2022 11:49:21 +0100	[thread overview]
Message-ID: <20220302104927.18607-5-pali@kernel.org> (raw)
In-Reply-To: <20220302104927.18607-1-pali@kernel.org>

After BootROM successfully detects boot message pattern on UART it waits
until host stop sending data on UART. For example Armada 385 BootROM
requires that host does not send anything on UART at least 24 ms. If host
is still sending something then BootROM waits (possibly infinitely).

BootROM successfully detects boot message pattern if it receives it in
small period of time after power on.

So to ensure that host put BootROM into UART boot mode, host must send
continuous stream of boot message pattern with a small gap (for A385 at
least 24 ms) after series of pattern. But this gap cannot be too often or
too long to ensure that it does not cover whole BootROM time window when it
is detecting for boot message pattern.

Therefore it is needed to do following steps in cycle without any delay:
1. send series of boot message pattern over UART
2. wait until kernel transmit all data
3. sleep small period of time

At the same time, host needs to monitor input queue, data received on the
UART and checking if it contains NAK byte by which BootROM informs that
xmodem transfer is ready.

But it is not possible to wait until kernel transmit all data on UART and
at the same time in the one process to also wait for input data. This is
limitation of POSIX tty API and also by linux kernel that it does not
provide asynchronous function for waiting until all data are transmitted.
There is only synchronous variant tcdrain().

So to correctly implement this handshake on systems with linux kernel, it
is needed to use tcdrain() in separate thread.

Implement sending of boot message pattern in one thread and reading of
reply in the main thread. Use pthread library for threads.

This change makes UART booting on Armada 385 more reliable. It is possible
to start kwboot and power on board after minute and kwboot correctly put
board into UART boot mode.

Old implementation without separate thread has an issue that it read just
one byte from UART input queue and then it send 128 message pattern to the
output queue. If some noise was on UART then kwboot was not able to read
BootROM response as its input queue was just overflowed and kwboot was
sending more data than receiving.

This change basically fixed above issue too.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 tools/Makefile |   3 ++
 tools/kwboot.c | 120 +++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 104 insertions(+), 19 deletions(-)

diff --git a/tools/Makefile b/tools/Makefile
index df941e0dca8d..c4a06dd9ba36 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -199,6 +199,9 @@ hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
 hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
 HOSTCFLAGS_mkexynosspl.o := -pedantic
 
+HOSTCFLAGS_kwboot.o += -pthread
+HOSTLDLIBS_kwboot += -pthread
+
 ifdtool-objs := $(LIBFDT_OBJS) ifdtool.o
 hostprogs-$(CONFIG_X86) += ifdtool
 
diff --git a/tools/kwboot.c b/tools/kwboot.c
index 4e2acb52458a..9fd90b9bec71 100644
--- a/tools/kwboot.c
+++ b/tools/kwboot.c
@@ -28,6 +28,7 @@
 #include <stdint.h>
 #include <time.h>
 #include <sys/stat.h>
+#include <pthread.h>
 
 #ifdef __linux__
 #include "termios_linux.h"
@@ -717,37 +718,120 @@ out:
 	return rc;
 }
 
+static void *
+kwboot_msg_write_handler(void *arg)
+{
+	int tty = *(int *)((void **)arg)[0];
+	const void *msg = ((void **)arg)[1];
+	int rsp_timeo = msg_rsp_timeo;
+	int i, dummy_oldtype;
+
+	/* allow to cancel this thread at any time */
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy_oldtype);
+
+	while (1) {
+		/* write 128 samples of message pattern into the output queue without waiting */
+		for (i = 0; i < 128; i++) {
+			if (kwboot_tty_send(tty, msg, 8, 1) < 0) {
+				perror("\nFailed to send message pattern");
+				exit(1);
+			}
+		}
+		/* wait until output queue is transmitted and then make pause */
+		if (tcdrain(tty) < 0) {
+			perror("\nFailed to send message pattern");
+			exit(1);
+		}
+		/* BootROM requires pause on UART after it detects message pattern */
+		usleep(rsp_timeo * 1000);
+	}
+}
+
+static int
+kwboot_msg_start_thread(pthread_t *thread, int *tty, void *msg)
+{
+	void *arg[2];
+	int rc;
+
+	arg[0] = tty;
+	arg[1] = msg;
+	rc = pthread_create(thread, NULL, kwboot_msg_write_handler, arg);
+	if (rc) {
+		errno = rc;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+kwboot_msg_stop_thread(pthread_t thread)
+{
+	int rc;
+
+	rc = pthread_cancel(thread);
+	if (rc) {
+		errno = rc;
+		return -1;
+	}
+
+	rc = pthread_join(thread, NULL);
+	if (rc) {
+		errno = rc;
+		return -1;
+	}
+
+	return 0;
+}
+
 static int
 kwboot_bootmsg(int tty)
 {
 	struct kwboot_block block;
-	int rc;
+	pthread_t write_thread;
+	int rc, err;
 	char c;
-	int count;
-
-	kwboot_printv("Sending boot message. Please reboot the target...");
 
-	do {
-		rc = tcflush(tty, TCIOFLUSH);
-		if (rc)
-			break;
+	/* flush input and output queue */
+	tcflush(tty, TCIOFLUSH);
 
-		for (count = 0; count < 128; count++) {
-			rc = kwboot_tty_send(tty, kwboot_msg_boot, sizeof(kwboot_msg_boot), 0);
-			if (rc)
-				break;
-		}
+	rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_boot);
+	if (rc) {
+		perror("Failed to start write thread");
+		return rc;
+	}
 
-		rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
+	kwboot_printv("Sending boot message. Please reboot the target...");
 
+	err = 0;
+	while (1) {
 		kwboot_spinner();
 
-	} while (rc || c != NAK);
+		rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
+		if (rc && errno == ETIMEDOUT) {
+			continue;
+		} else if (rc) {
+			err = errno;
+			break;
+		}
+
+		if (c == NAK)
+			break;
+	}
 
 	kwboot_printv("\n");
 
-	if (rc)
+	rc = kwboot_msg_stop_thread(write_thread);
+	if (rc) {
+		perror("Failed to stop write thread");
 		return rc;
+	}
+
+	if (err) {
+		errno = err;
+		perror("Failed to read response for boot message pattern");
+		return -1;
+	}
 
 	/*
 	 * At this stage we have sent more boot message patterns and BootROM
@@ -1873,10 +1957,8 @@ main(int argc, char **argv)
 		}
 	} else if (bootmsg) {
 		rc = kwboot_bootmsg(tty);
-		if (rc) {
-			perror("bootmsg");
+		if (rc)
 			goto out;
-		}
 	}
 
 	if (img) {
-- 
2.20.1


  parent reply	other threads:[~2022-03-02 10:53 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-02 10:49 [PATCH u-boot-marvell 00/10] tools: kwboot: Fix boot and terminal mode Pali Rohár
2022-03-02 10:49 ` [PATCH u-boot-marvell 01/10] tools: kwboot: Check for return value of kwboot_tty_send() and tcflush() Pali Rohár
2022-03-04  7:48   ` Stefan Roese
2022-03-02 10:49 ` [PATCH u-boot-marvell 02/10] tools: kwboot: Remove msg_req_delay Pali Rohár
2022-03-04  7:48   ` Stefan Roese
2022-03-02 10:49 ` [PATCH u-boot-marvell 03/10] tools: kwboot: Cleanup bootmsg and debugmsg variables Pali Rohár
2022-03-04  7:48   ` Stefan Roese
2022-03-02 10:49 ` Pali Rohár [this message]
2022-03-04  7:49   ` [PATCH u-boot-marvell 04/10] tools: kwboot: Use separate thread for sending boot message pattern Stefan Roese
2022-03-02 10:49 ` [PATCH u-boot-marvell 05/10] tools: kwboot: Fix sending and processing debug message pattern (-d option) Pali Rohár
2022-03-04  7:49   ` Stefan Roese
2022-03-02 10:49 ` [PATCH u-boot-marvell 06/10] tools: kwboot: Add support for backspace key in mini terminal Pali Rohár
2022-03-04  7:49   ` Stefan Roese
2022-03-02 10:49 ` [PATCH u-boot-marvell 07/10] tools: kwboot: Update usage Pali Rohár
2022-03-04  7:49   ` Stefan Roese
2022-03-02 10:49 ` [PATCH u-boot-marvell 08/10] tools: kwboot: Update manpage Pali Rohár
2022-03-04  7:50   ` Stefan Roese
2022-03-02 10:49 ` [PATCH u-boot-marvell 09/10] tools: kwboot: Update doc about Avanta Pali Rohár
2022-03-04  7:50   ` Stefan Roese
2022-03-02 10:49 ` [PATCH u-boot-marvell 10/10] tools: kwboot: Update references with public links Pali Rohár
2022-03-04  7:50   ` Stefan Roese
2022-03-02 20:51 ` [PATCH u-boot-marvell 00/10] tools: kwboot: Fix boot and terminal mode Tony Dinh
2022-03-02 21:03   ` Pali Rohár
2022-03-02 21:18     ` Tony Dinh
2022-03-03 23:58       ` Tony Dinh
2022-03-04  0:05         ` Pali Rohár
2022-03-04  4:52           ` Tony Dinh
2022-03-04  7:47 ` Stefan Roese
2022-03-04 12:24 ` Stefan Roese

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220302104927.18607-5-pali@kernel.org \
    --to=pali@kernel.org \
    --cc=marek.behun@nic.cz \
    --cc=mibodhi@gmail.com \
    --cc=sr@denx.de \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox