aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/uart/uart_core.c
diff options
context:
space:
mode:
authorMarius Strobl <marius@FreeBSD.org>2015-07-24 17:01:16 +0000
committerMarius Strobl <marius@FreeBSD.org>2015-07-24 17:01:16 +0000
commit86fb54003393c8c3c586df44fc31d7861e121ef3 (patch)
tree2945ac6205826225ac9bc1eab79e139c39265d5e /sys/dev/uart/uart_core.c
parent6df1985625d5dcf68c756d9dc109492bce586d3b (diff)
downloadsrc-86fb54003393c8c3c586df44fc31d7861e121ef3.tar.gz
src-86fb54003393c8c3c586df44fc31d7861e121ef3.zip
- Since r253161, uart_intr() abuses FILTER_SCHEDULE_THREAD for signaling
uart_bus_attach() during its test that 20 iterations weren't sufficient for clearing all pending interrupts, assuming this means that hardware is broken and doesn't deassert interrupts. However, under pressure, 20 iterations also can be insufficient for clearing all pending interrupts, leading to a panic as intr_event_handle() tries to schedule an interrupt handler not registered. Solve this by introducing a flag that is set in test mode and otherwise restores pre-r253161 behavior of uart_intr(). The approach of additionally registering uart_intr() as handler as suggested in PR 194979 is not taken as that in turn would abuse special pccard and pccbb handling code of intr_event_handle(). [1] - Const'ify uart_driver_name. - Fix some minor style bugs. PR: 194979 [1] Reviewed by: marcel (earlier version) MFC after: 3 days
Notes
Notes: svn path=/head/; revision=285843
Diffstat (limited to 'sys/dev/uart/uart_core.c')
-rw-r--r--sys/dev/uart/uart_core.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c
index 4114f375986e..191244a2ae02 100644
--- a/sys/dev/uart/uart_core.c
+++ b/sys/dev/uart/uart_core.c
@@ -52,7 +52,7 @@ __FBSDID("$FreeBSD$");
#include "uart_if.h"
devclass_t uart_devclass;
-char uart_driver_name[] = "uart";
+const char uart_driver_name[] = "uart";
SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs =
SLIST_HEAD_INITIALIZER(uart_sysdevs);
@@ -260,13 +260,14 @@ static int
uart_intr(void *arg)
{
struct uart_softc *sc = arg;
- int cnt, ipend;
+ int cnt, ipend, testintr;
if (sc->sc_leaving)
return (FILTER_STRAY);
cnt = 0;
- while (cnt < 20 && (ipend = UART_IPEND(sc)) != 0) {
+ testintr = sc->sc_testintr;
+ while ((!testintr || cnt < 20) && (ipend = UART_IPEND(sc)) != 0) {
cnt++;
if (ipend & SER_INT_OVERRUN)
uart_intr_overrun(sc);
@@ -277,7 +278,7 @@ uart_intr(void *arg)
if (ipend & SER_INT_SIGCHG)
uart_intr_sigchg(sc);
if (ipend & SER_INT_TXIDLE)
- uart_intr_txidle(sc);
+ uart_intr_txidle(sc);
}
if (sc->sc_polled) {
@@ -286,7 +287,8 @@ uart_intr(void *arg)
}
return ((cnt == 0) ? FILTER_STRAY :
- ((cnt == 20) ? FILTER_SCHEDULE_THREAD : FILTER_HANDLED));
+ ((testintr && cnt == 20) ? FILTER_SCHEDULE_THREAD :
+ FILTER_HANDLED));
}
serdev_intr_t *
@@ -433,7 +435,7 @@ uart_bus_attach(device_t dev)
/*
* Protect ourselves against interrupts while we're not completely
* finished attaching and initializing. We don't expect interrupts
- * until after UART_ATTACH() though.
+ * until after UART_ATTACH(), though.
*/
sc->sc_leaving = 1;
@@ -513,7 +515,9 @@ uart_bus_attach(device_t dev)
pps_init(&sc->sc_pps);
sc->sc_leaving = 0;
+ sc->sc_testintr = 1;
filt = uart_intr(sc);
+ sc->sc_testintr = 0;
/*
* Don't use interrupts if we couldn't clear any pending interrupt