Subject: port-i386/7331: i386 isa/isapnp interrupt sharing issues
To: None <gnats-bugs@gnats.netbsd.org>
From: John Darrow <John.P.Darrow@wheaton.edu>
List: netbsd-bugs
Date: 04/06/1999 20:12:05
>Number:         7331
>Category:       port-i386
>Synopsis:       i386 isa/isapnp interrupt sharing doesn't work
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-i386-maintainer (NetBSD/i386 Portmaster)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Apr  6 18:20:02 1999
>Last-Modified:
>Originator:     John Darrow
>Organization:
Computing Services, Wheaton College, Wheaton, IL
>Release:        NetBSD 1.4_ALPHA
>Environment:
System: NetBSD jdarrow.wheaton.edu 1.4_ALPHA NetBSD 1.4_ALPHA (JDARROW) #1: Mon Apr 5 22:24:15 CDT 1999 jdarrow@jdarrow.wheaton.edu:/var/src/sys/arch/i386/compile/JDARROW i386


>Description:
I recently obtained a new isapnp modem for my PC, which has a ym0 OPL3-SA3
sound system built into the motherboard.  After I added its id to isapnpdevs,
I was able to get the modem to work.  However, the sound system stopped
working.

Looking at the probe messages, I noticed that both ym0 and com2 used irq 5.

I enabled DEBUG_ISAPNP to get some more info, and noticed that com2 (which
probed first) simply used one of its 'acceptable' configs, while ym0 then
used its 'preferred' config.  Both used 'E+' edge-triggered interrupts.

Given that I'd heard comments before that isa on i386 doesn't really like
to share interrupts, I modified sys/arch/i386/isa/isa_machdep.c to make
IST_EDGE unsharable (like IST_PULSE) instead of sharable (like IST_LEVEL).
I'm not sure, however, if even IST_LEVEL should be sharable on i386.
(Note that pr port-i386/6642 is a special case of this problem.)

After doing this, com2 still used irq 5.  ym0 now came up as irq 9.
However, as this is only one of the 'acceptable' configs for ym0, some
of the functions didn't come up correctly.  What I really wanted was to
have com2 use irq 10, and leave irq 5 for ym0.

I tried modifying the com* at isapnp? line in the config file to include
a locator (com2 at isapnp? irq 10), but the autoconfiguration simply
ignored the locator and still came up as irq 5.  (Further code examination
revealed that the isapnp attach function simply ignores the cfdata provided
from the config file, unlike the isa attach function.)

Because my OPL3 is built into the motherboard, I could not simply reorder
the boards within the machine to get the ym0 to probe first.  I ended up
reversing the order of the card-configuring loop in sys/dev/isapnp/isapnp.c
to go down from sc->sc_ncards instead of up from 0.  However, this
"solution" could cause others whose devices probe in the correct order
now to have the same problem I have.

>How-To-Repeat:
Install new isapnp device, see irq shared, modify code to prevent irq
sharing, see wrong device get irq modified, examine lots of code.

>Fix:
For the irq sharing problem:
*** /xtra/NetBSD-current/src/sys/arch/i386/isa/isa_machdep.c	Fri Mar 19 18:38:00 1999
--- /var/src/sys/arch/i386/isa/isa_machdep.c	Tue Apr  6 02:22:18 1999
***************
*** 379,385 ****
  			*irq = i;
  			return (0);
  
- 		case IST_EDGE:
  		case IST_LEVEL:
  			if (type != intrtype[i])
  				continue;
--- 379,384 ----
***************
*** 401,406 ****
--- 400,406 ----
  			}
  			break;
  
+ 		case IST_EDGE:
  		case IST_PULSE:
  			/* this just isn't shareable */
  			continue;
***************
*** 444,453 ****
  	case IST_NONE:
  		intrtype[irq] = type;
  		break;
- 	case IST_EDGE:
  	case IST_LEVEL:
  		if (type == intrtype[irq])
  			break;
  	case IST_PULSE:
  		if (type != IST_NONE)
  			panic("intr_establish: irq %d can't share %s with %s",
--- 444,453 ----
  	case IST_NONE:
  		intrtype[irq] = type;
  		break;
  	case IST_LEVEL:
  		if (type == intrtype[irq])
  			break;
+ 	case IST_EDGE:
  	case IST_PULSE:
  		if (type != IST_NONE)
  			panic("intr_establish: irq %d can't share %s with %s",

My Quick Hack of reversing the order of the isapnp configuration probe:
*** /xtra/NetBSD-current/src/sys/dev/isapnp/isapnp.c	Tue Mar 23 15:53:59 1999
--- /var/src/sys/dev/isapnp/isapnp.c	Tue Apr  6 15:37:06 1999
***************
*** 984,994 ****
  	/*
  	 * Now configure all of the cards.
  	 */
! 	for (c = 0; c < sc->sc_ncards; c++) {
  		/* Good morning card c */
! 		isapnp_write_reg(sc, ISAPNP_WAKE, c + 1);
  
! 		if ((ipa = isapnp_get_resource(sc, c)) == NULL)
  			continue;
  
  		DPRINTF(("Selecting attachments\n"));
--- 984,994 ----
  	/*
  	 * Now configure all of the cards.
  	 */
! 	for (c = sc->sc_ncards; c > 0; c--) {
  		/* Good morning card c */
! 		isapnp_write_reg(sc, ISAPNP_WAKE, c);
  
! 		if ((ipa = isapnp_get_resource(sc, c - 1)) == NULL)
  			continue;
  
  		DPRINTF(("Selecting attachments\n"));


I thought of two possible partial solutions to the configuration ordering
problem.

1. Run through the isapnp card list multiple times, once configuring all
those which have 'preferred' configs to that configuration, and then again
setting all still-unconfigured devices to 'acceptable' configurations
(and maybe a third pass for 'functional' configurations?)  Note that
this still leaves a possibility of conflict among two devices' 'preferred'
configurations.

2. Add code to isapnp to check for locators in the config file and
use these to override the configuration checks during probing (by ignoring
for possible configurations which don't include this locator's value, and
overriding the available values for those configurations which do).  This
should be just a SMOP (modeling some of the code after that found in isa.c),
the isa and isapnp codes are enough different to make it require more that
just a Quick Hack.
>Audit-Trail:
>Unformatted: