misc/74786: Smartlink Modem causes interrupt storm on RELENG_4 and RELENG_5

Bruce Evans bde at zeta.org.au
Tue Dec 7 23:22:24 PST 2004


On Tue, 7 Dec 2004, Mike Tancsa wrote:

> At 06:55 PM 06/12/2004, Bruce Evans wrote:
> >On Mon, 6 Dec 2004, Mike Tancsa wrote:
> ...
> > > where irq12 is the IRQ shared by the modem and the USB port.  However,
> > because all IRQ 12s get throttled, the modem is unusable. e.g. trying to
> > cu -l /dev/cuaa4 and typing atz takes about 5 seconds.
> >
> >Does a storm occur when both devices are successfully attached?  Hmm, the
> >above is consistent with the following combination:
> >1. only usb being attached
> >2. the sio device still driving the interrupt but sio not being called to
> >    handle the interrupt
> Yes, that sounds correct.

I think I understand this now.  sio can indeed drive the interrupt (after
you open an sio device, but not immediately at the end of the attach
except in the serial console case).  The main bugs are:
1. sio asks for exclusive access to the interrupt for no good reason
   (some buses like isa might only support exclusive accesses, but sio
   doesn't care).  uhci gets access first in your configuration, so
   allocation of the interrupt resource fails.
2. Error handling for the failure in (1) is null, so both devices are
   "successfully" attached.
3. sio sets a flag to tell it to use polling if there is no interrupt
   resource, but it doesn't set the flag if the interrupt resource
   couldn't be allocated or if the interrupt couldn't be set up.
4. Upper layers provide negative help for debugging (3) using their
   own version of (3).  They print "irq N" in boot messages if an
   interrupt resource justs exists.  This doesn't mean that the device
   is using it.
5. Device interrupts are still enabled in polling mode.  This depends
   on nothing else sucessfully setting up the (shared) interrupt.

Try this fix.  For the uhci-sio conflict, it should avoid problem (1)
(please try it with the RF_SHAREABLE flag removed so that if this is
indeed the primary problem then the new diagnostic will verify it).
This should move the conflict later, to one between usb's use of
normal interrupt mode and sio's request for fast interrupt mode.
There were already sufficient diagnostics for this.  The patch adds
some more.  Since usb got the interrupt first, sio will fall back
to normal mode.  If sio goes first then the attach of usb would
probably fail.  The patch doesn't change these bevhaviours.  The
patch adds another fallback to polled mode if setup of normal mode
mode fails and fixes some related resource leaks.  It also increases
the polling frequency if possible.  Polled mode mostly works at
115200 bps provided the UART is buffered and HZ >= 1000.  With
unbuffered UARTs and HZ = 100, only 4800 bos mostly works.

I only tested with some fudged isa conflicts because all my machines
are configured to not have any shared irqs for serial devices and
hints are just hints so they can't be used to force conflicts excet
for isa.

%%%
Index: sio.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sio/sio.c,v
retrieving revision 1.442
diff -u -2 -r1.442 sio.c
--- sio.c	25 Jun 2004 10:51:33 -0000	1.442
+++ sio.c	8 Dec 2004 06:09:12 -0000
@@ -1165,7 +1165,14 @@
 	pps_init(&com->pps);

+	if (com->no_irq)
+		goto over_irq_setup;
 	rid = 0;
-	com->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
-	if (com->irqres) {
+	com->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+					     RF_SHAREABLE | RF_ACTIVE);
+	if (com->irqres == NULL) {
+		device_printf(dev, "interrupt resource allocation failed\n");
+		device_printf(dev, "falling back to polled mode\n");
+		com->no_irq = TRUE;
+	} else {
 		ret = BUS_SETUP_INTR(device_get_parent(dev), dev, com->irqres,
 				     INTR_TYPE_TTY | INTR_FAST,
@@ -1178,6 +1185,11 @@
 				device_printf(dev, "unable to activate interrupt in fast mode - using normal mode\n");
 		}
-		if (ret)
+		if (ret != 0) {
 			device_printf(dev, "could not activate interrupt\n");
+			bus_release_resource(dev, SYS_RES_IRQ, 0, com->irqres);
+			com->irqres = NULL;
+			device_printf(dev, "falling back to polled mode\n");
+			com->no_irq = TRUE;
+		}
 #if defined(DDB) && (defined(BREAK_TO_DEBUGGER) || \
     defined(ALT_BREAK_TO_DEBUGGER))
@@ -1191,4 +1203,9 @@
 #endif
 	}
+over_irq_setup:
+	if (com->no_irq) {
+		outb(com->modem_ctl_port, com->mcr_image &= ~MCR_IENABLE);
+		device_printf(dev, "polled mode\n");
+	}

 	return (0);
@@ -2647,5 +2664,5 @@
 	/*
 	 * Set our timeout period to 1 second if no polled devices are open.
-	 * Otherwise set it to max(1/200, 1/hz).
+	 * Otherwise, set it to max(1/1000, 1/hz).
 	 * Enable timeouts iff some device is open.
 	 */
@@ -2659,5 +2676,5 @@
 			someopen = TRUE;
 			if (com->poll || com->poll_output) {
-				sio_timeout = hz > 200 ? hz / 200 : 1;
+				sio_timeout = hz > 1000 ? hz / 1000 : 1;
 				break;
 			}
%%%

Bruce


More information about the freebsd-bugs mailing list