summaryrefslogtreecommitdiffstats
path: root/sys/dev/uart
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2006-04-01 19:04:54 +0000
committermarcel <marcel@FreeBSD.org>2006-04-01 19:04:54 +0000
commit01ed5990aef062b97e91680895804b9689c8076b (patch)
treef866ed454b38b3e3ed100d7237faffef820e51f3 /sys/dev/uart
parent6d14bcd43fdc1e895dd4255bb9f88dba939296ce (diff)
downloadFreeBSD-src-01ed5990aef062b97e91680895804b9689c8076b.zip
FreeBSD-src-01ed5990aef062b97e91680895804b9689c8076b.tar.gz
Don't hold the hardware mutex across getc(). It can wait indefinitely
for a character to be received. Instead let getc() do any necesary locking.
Diffstat (limited to 'sys/dev/uart')
-rw-r--r--sys/dev/uart/uart_cpu.h8
-rw-r--r--sys/dev/uart/uart_dev_ns8250.c20
-rw-r--r--sys/dev/uart/uart_dev_sab82532.c16
-rw-r--r--sys/dev/uart/uart_dev_z8530.c21
4 files changed, 45 insertions, 20 deletions
diff --git a/sys/dev/uart/uart_cpu.h b/sys/dev/uart/uart_cpu.h
index 310d6b9..a3f0dcb 100644
--- a/sys/dev/uart/uart_cpu.h
+++ b/sys/dev/uart/uart_cpu.h
@@ -42,7 +42,7 @@ struct uart_ops {
void (*term)(struct uart_bas *);
void (*putc)(struct uart_bas *, int);
int (*poll)(struct uart_bas *);
- int (*getc)(struct uart_bas *);
+ int (*getc)(struct uart_bas *, struct mtx *);
};
extern struct uart_ops uart_i8251_ops;
@@ -150,12 +150,8 @@ uart_poll(struct uart_devinfo *di)
static __inline int
uart_getc(struct uart_devinfo *di)
{
- int res;
- uart_lock(di->hwmtx);
- res = di->ops.getc(&di->bas);
- uart_unlock(di->hwmtx);
- return (res);
+ return (di->ops.getc(&di->bas, di->hwmtx));
}
#endif /* _DEV_UART_CPU_H_ */
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index 378639f..adb4502 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -217,7 +217,7 @@ static void ns8250_init(struct uart_bas *bas, int, int, int, int);
static void ns8250_term(struct uart_bas *bas);
static void ns8250_putc(struct uart_bas *bas, int);
static int ns8250_poll(struct uart_bas *bas);
-static int ns8250_getc(struct uart_bas *bas);
+static int ns8250_getc(struct uart_bas *bas, struct mtx *);
struct uart_ops uart_ns8250_ops = {
.probe = ns8250_probe,
@@ -321,16 +321,26 @@ ns8250_poll(struct uart_bas *bas)
}
static int
-ns8250_getc(struct uart_bas *bas)
+ns8250_getc(struct uart_bas *bas, struct mtx *hwmtx)
{
- int delay;
+ int c, delay;
+
+ uart_lock(hwmtx);
/* 1/10th the time to transmit 1 character (estimate). */
delay = ns8250_delay(bas);
- while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) == 0)
+ while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) == 0) {
+ uart_unlock(hwmtx);
DELAY(delay);
- return (uart_getreg(bas, REG_DATA));
+ uart_lock(hwmtx);
+ }
+
+ c = uart_getreg(bas, REG_DATA);
+
+ uart_unlock(hwmtx);
+
+ return (c);
}
/*
diff --git a/sys/dev/uart/uart_dev_sab82532.c b/sys/dev/uart/uart_dev_sab82532.c
index 927a681..9ef0bd1 100644
--- a/sys/dev/uart/uart_dev_sab82532.c
+++ b/sys/dev/uart/uart_dev_sab82532.c
@@ -174,7 +174,7 @@ static void sab82532_init(struct uart_bas *bas, int, int, int, int);
static void sab82532_term(struct uart_bas *bas);
static void sab82532_putc(struct uart_bas *bas, int);
static int sab82532_poll(struct uart_bas *bas);
-static int sab82532_getc(struct uart_bas *bas);
+static int sab82532_getc(struct uart_bas *bas, struct mtx *);
struct uart_ops uart_sab82532_ops = {
.probe = sab82532_probe,
@@ -307,20 +307,25 @@ sab82532_poll(struct uart_bas *bas)
{
if (uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE)
- return (sab82532_getc(bas));
+ return (sab82532_getc(bas, NULL));
return (-1);
}
static int
-sab82532_getc(struct uart_bas *bas)
+sab82532_getc(struct uart_bas *bas, struct mtx *hwmtx)
{
int c, delay;
+ uart_lock(hwmtx);
+
/* 1/10th the time to transmit 1 character (estimate). */
delay = sab82532_delay(bas);
- while (!(uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE))
+ while (!(uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE)) {
+ uart_unlock(hwmtx);
DELAY(delay);
+ uart_lock(hwmtx);
+ }
while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
;
@@ -338,6 +343,9 @@ sab82532_getc(struct uart_bas *bas)
;
uart_setreg(bas, SAB_CMDR, SAB_CMDR_RMC);
uart_barrier(bas);
+
+ uart_unlock(hwmtx);
+
return (c);
}
diff --git a/sys/dev/uart/uart_dev_z8530.c b/sys/dev/uart/uart_dev_z8530.c
index 09895eb..4bde071 100644
--- a/sys/dev/uart/uart_dev_z8530.c
+++ b/sys/dev/uart/uart_dev_z8530.c
@@ -178,7 +178,7 @@ static void z8530_init(struct uart_bas *bas, int, int, int, int);
static void z8530_term(struct uart_bas *bas);
static void z8530_putc(struct uart_bas *bas, int);
static int z8530_poll(struct uart_bas *bas);
-static int z8530_getc(struct uart_bas *bas);
+static int z8530_getc(struct uart_bas *bas, struct mtx *);
struct uart_ops uart_z8530_ops = {
.probe = z8530_probe,
@@ -229,12 +229,23 @@ z8530_poll(struct uart_bas *bas)
}
static int
-z8530_getc(struct uart_bas *bas)
+z8530_getc(struct uart_bas *bas, struct mtx *hwmtx)
{
+ int c;
- while (!(uart_getreg(bas, REG_CTRL) & BES_RXA))
- ;
- return (uart_getreg(bas, REG_DATA));
+ uart_lock(hwmtx);
+
+ while (!(uart_getreg(bas, REG_CTRL) & BES_RXA)) {
+ uart_unlock(hwmtx);
+ DELAY(10);
+ uart_lock(hwmtx);
+ }
+
+ c = uart_getreg(bas, REG_DATA);
+
+ uart_unlock(hwmtx);
+
+ return (c);
}
/*
OpenPOWER on IntegriCloud