git: 8c3d6917c1f1 - main - stand: eficom: Only set baudrate when it changes

From: Warner Losh <imp_at_FreeBSD.org>
Date: Thu, 11 May 2023 20:06:52 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=8c3d6917c1f127f70719193959ff42f3f1ab8f5f

commit 8c3d6917c1f127f70719193959ff42f3f1ab8f5f
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2023-05-11 20:04:00 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-05-11 20:06:03 +0000

    stand: eficom: Only set baudrate when it changes
    
    Only set the baudrate when it is different than what the device has
    reported. In addition, pass in the args to effect no change to the other
    parameters to the serial port. Some EFI firmware gets cranky when you
    set them to the same value, so avoid doing so (we likely can remove the
    HyperV workaround with this fix, but I kept it in place). Add comments
    to the code for why we do this too.
    
    Sponsored by:           Netflix
    Differential Revision:  https://reviews.freebsd.org/D40010
---
 stand/efi/libefi/eficom.c | 39 ++++++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 17 deletions(-)

diff --git a/stand/efi/libefi/eficom.c b/stand/efi/libefi/eficom.c
index b0fc0d8fbf6a..b1c84399a05d 100644
--- a/stand/efi/libefi/eficom.c
+++ b/stand/efi/libefi/eficom.c
@@ -41,6 +41,7 @@ static EFI_GUID serial = SERIAL_IO_PROTOCOL;
 #define	PNP0501		0x501		/* 16550A-compatible COM port */
 
 struct serial {
+	uint64_t	newbaudrate;
 	uint64_t	baudrate;
 	uint32_t	timeout;
 	uint32_t	receivefifodepth;
@@ -300,7 +301,8 @@ comc_probe(struct console *sc)
 		if (EFI_ERROR(status)) {
 			comc_port->sio = NULL;
 		} else {
-			comc_port->baudrate = comc_port->sio->Mode->BaudRate;
+			comc_port->newbaudrate =
+			    comc_port->baudrate = comc_port->sio->Mode->BaudRate;
 			comc_port->timeout = comc_port->sio->Mode->Timeout;
 			comc_port->receivefifodepth =
 			    comc_port->sio->Mode->ReceiveFifoDepth;
@@ -322,7 +324,7 @@ comc_probe(struct console *sc)
 		env = getenv("comconsole_speed");
 
 	if (comc_parse_intval(env, &val) == CMD_OK)
-		comc_port->baudrate = val;
+		comc_port->newbaudrate = val;
 
 	if (env != NULL)
 		unsetenv("efi_com_speed");
@@ -497,10 +499,9 @@ comc_speed_set(struct env_var *ev, int flags, const void *value)
 	if (comc_parse_intval(value, &speed) != CMD_OK) 
 		return (CMD_ERROR);
 
-	comc_port->baudrate = speed;
-	(void) comc_setup();
-
-	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+	comc_port->newbaudrate = speed;
+	if (comc_setup())
+		env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
 
 	return (CMD_OK);
 }
@@ -525,20 +526,24 @@ comc_setup(void)
 			return (false);
 	}
 
-	if (comc_port->sio->SetAttributes != NULL) {
+	/*
+	 * Avoid setting the baud rate on Hyper-V. Also, only set the baud rate
+	 * if the baud rate has changed from the default. And pass in '0' or
+	 * DefaultFoo when we're not changing those values. Some EFI
+	 * implementations get cranky when you set things to the values reported
+	 * back even when they are unchanged.
+	 */
+	if (comc_port->sio->SetAttributes != NULL &&
+	    comc_port->newbaudrate != comc_port->baudrate) {
 		ev = getenv("smbios.bios.version");
-		if (ev != NULL && strncmp(ev, "Hyper-V", 7) == 0) {
+		if (ev != NULL && strncmp(ev, "Hyper-V", 7) != 0) {
 			status = comc_port->sio->SetAttributes(comc_port->sio,
-			    0, 0, 0, DefaultParity, 0, DefaultStopBits);
-		} else {
-			status = comc_port->sio->SetAttributes(comc_port->sio,
-			    comc_port->baudrate, comc_port->receivefifodepth,
-			    comc_port->timeout, comc_port->parity,
-			    comc_port->databits, comc_port->stopbits);
+			    comc_port->newbaudrate, 0, 0, DefaultParity, 0,
+			    DefaultStopBits);
+			if (EFI_ERROR(status))
+				return (false);
+			comc_port->baudrate = comc_port->newbaudrate;
 		}
-
-		if (EFI_ERROR(status))
-			return (false);
 	}
 
 #ifdef EFI_FORCE_RTS