summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorknakahara <knakahara@NetBSD.org>2022-12-08 09:08:49 +0000
committerknakahara <knakahara@NetBSD.org>2022-12-08 09:08:49 +0000
commit2fd830dba3fe0846d272a6eab1b4102f8a6ffb4e (patch)
tree997a8a4e8b66fc3f9838c730032923b900038a79 /sys/dev/ic
parent8634f4f6fade2282975363954a3bc74ad7e063d7 (diff)
Fix hang up writing /dev/console rarely in specific environments.
Some BMC seems to require these syncronous operations. If not, it does not send transmit completion interrupts for some reason.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/com.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c
index a79e721e6d8..25446a67509 100644
--- a/sys/dev/ic/com.c
+++ b/sys/dev/ic/com.c
@@ -1,4 +1,4 @@
-/* $NetBSD: com.c,v 1.380 2022/12/03 11:28:38 skrll Exp $ */
+/* $NetBSD: com.c,v 1.381 2022/12/08 09:08:49 knakahara Exp $ */
/*-
* Copyright (c) 1998, 1999, 2004, 2008 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: com.c,v 1.380 2022/12/03 11:28:38 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: com.c,v 1.381 2022/12/08 09:08:49 knakahara Exp $");
#include "opt_com.h"
#include "opt_ddb.h"
@@ -206,6 +206,28 @@ static struct consdev comcons = {
.cn_pri = CN_NORMAL
};
+#define CSR_WRITE_1_SYNC(r, o, v) do { \
+ CSR_WRITE_1(r, o, v); \
+ switch(o) { \
+ case COM_REG_IER: \
+ (void)CSR_READ_1(r, COM_REG_IIR); \
+ break; \
+ case COM_REG_TXDATA: \
+ (void)CSR_READ_1(r, COM_REG_TLR); \
+ break; \
+ } \
+ } while(0)
+#define CSR_WRITE_MULTI_SYNC(r, o, p, n) do { \
+ CSR_WRITE_MULTI(r, o, p, n); \
+ switch(o) { \
+ case COM_REG_IER: \
+ (void)CSR_READ_1(r, COM_REG_IIR); \
+ break; \
+ case COM_REG_TXDATA: \
+ (void)CSR_READ_1(r, COM_REG_TLR); \
+ break; \
+ } \
+ } while(0)
const struct cdevsw com_cdevsw = {
.d_open = comopen,
@@ -1961,7 +1983,7 @@ comstart(struct tty *tp)
/* Enable transmit completion interrupts if necessary. */
if (!ISSET(sc->sc_ier, IER_ETXRDY)) {
SET(sc->sc_ier, IER_ETXRDY);
- CSR_WRITE_1(regsp, COM_REG_IER, sc->sc_ier);
+ CSR_WRITE_1_SYNC(regsp, COM_REG_IER, sc->sc_ier);
}
/* Output the first chunk of the contiguous buffer. */
@@ -1971,7 +1993,7 @@ comstart(struct tty *tp)
n = sc->sc_tbc;
if (n > sc->sc_fifolen)
n = sc->sc_fifolen;
- CSR_WRITE_MULTI(regsp, COM_REG_TXDATA, sc->sc_tba, n);
+ CSR_WRITE_MULTI_SYNC(regsp, COM_REG_TXDATA, sc->sc_tba, n);
sc->sc_tbc -= n;
sc->sc_tba += n;
}
@@ -2359,7 +2381,7 @@ again: do {
CLR(sc->sc_ier, IER_ERXRDY);
break;
}
- CSR_WRITE_1(regsp, COM_REG_IER, sc->sc_ier);
+ CSR_WRITE_1_SYNC(regsp, COM_REG_IER, sc->sc_ier);
}
} else {
if ((iir & (IIR_RXRDY|IIR_TXRDY)) == IIR_RXRDY) {
@@ -2443,14 +2465,14 @@ do_tx:
n = sc->sc_tbc;
if (n > sc->sc_fifolen)
n = sc->sc_fifolen;
- CSR_WRITE_MULTI(regsp, COM_REG_TXDATA, sc->sc_tba, n);
+ CSR_WRITE_MULTI_SYNC(regsp, COM_REG_TXDATA, sc->sc_tba, n);
sc->sc_tbc -= n;
sc->sc_tba += n;
} else {
/* Disable transmit completion interrupts if necessary. */
if (ISSET(sc->sc_ier, IER_ETXRDY)) {
CLR(sc->sc_ier, IER_ETXRDY);
- CSR_WRITE_1(regsp, COM_REG_IER, sc->sc_ier);
+ CSR_WRITE_1_SYNC(regsp, COM_REG_IER, sc->sc_ier);
}
if (sc->sc_tx_busy) {
sc->sc_tx_busy = 0;