[this is long, and hppa-specific, feel free to ignore if you don't care
about OpenBSD/hppa. Noone does anyway nowadays]
At the beginning of the hppa port, no interrupts were shared - the
processor allows for 32 interrupt sources and the existing designs made
sure to allocate distinct interrupts to every device.
Every device, but the PS/2 keyboard and mouse controller. So mickey
added a kluge about 15 years ago for them when I wrote the keyboard
controller driver. [Yes, really 15 years ago now... time flies]
And then the port grew PCI bus support, where interrupts have to be
shareable, by design. So the interrupt code got some form of shared
interrupts, but, well, the interrupt handling code is definitely not for
the faint of heart. Yet it works... to some extent. This mostly involves
magic, and the ability to understand locore0.s.
Because most of the native hppa drivers have been designed with
exclusive interrupts in mind, the hppa kernel configuration has many
hardwired interrupt vector lines (`irq' locators).
This is the reason why you have distinct foo0 and foo1 lines in the
kernel configuration, even for devices which driver do not use
interrupts at all, such as sti(4).
While working on ``card-mode'' dino(4) support [coming soon], I ended up
with having more than one dino(4) attachment to the same parent. To my
surprise, both were using the same interrupt, which - in the current
state of the interrupt handling code, which I won't touch without a
ten-feet pole - meant interrupts from the first device were completely
ignored, because the second one would happily overwrite all the relevant
interrupt structures for that interrupt bit.
This happens, because of this in mbsubmatch() in
sys/arch/hppa/hppa/mainbus.c:
int
mbsubmatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
[..]
if ((ret = (*cf->cf_attach->ca_match)(parent, match, aux)))
ca->ca_irq = cf->hppacf_irq;
return ret;
}
This means that "everytime a kernel configuration line matches, we pick
its irq value". And while many devices have stricter checks based on
their physical addresses, PCI bridges such as dino(4) don't.
So, with a kernel configuration having
dino0 at phantomas? irq 26 # PCI bus bridge on [AB]*
dino1 at phantomas? irq 25
both lines would match, and both dino controllers would end up using -
but not sharing! - irq 25.
This was not noticed because systems with two dino attachments AT THE
SAME PARENT do not exist in their DEFAULT configuration.
However, adding support for cardmode dino changes the rules. And one can
end up with THREE dino controllers although the kernel only allows for
dino0 and dino1.
The only correct way to address this is to relax this fixed irq
assignments and let the kernel pick unused interrupt vectors. In fact,
this logic was already in use on higher-end elroy(4) systems.
The following diff does:
- dynamic allocation of interrupts for dino(4) and gsc(4).
- only mention irq locators for devices which use interrupts.
- for gsc(4), this actually postpones interrupt allocation until gsc(4)
attaches, so asp(4)/lasi(4)/wax(4) won't route the interrupt yet, but
the gsc(4) child will take care of this.
- because of hardwired interrupt line assignment on the pre-PCI systems,
the logic looking for a free interrupt pin looks from 31 to 0, while
it used to search in the opposite order. This WILL affect all elroy
systems (C3xxx, Jxxxx) but shouldn't have any noticeable effect. Even
though gsckbc will pick interrupt 26, systems with gsckbc will have
the asp/lasi/wax controller attaching early enough to leave irq 26
available by the time gsckbc attacheѕ.
- remove the irq locator for the drivers which do not need a fixed
assignment. siop and moongoose could benefit from this but don't work
at the moment so this is left as an exercize to future kernel hackers.
A side effect from this is that we do not need multiple sti(4)
attachment lines, so PCI sti(4) devices will now attach as sti0 rather
than sti2.
With this diff, multiple dino(4) devices attached to the same parent
will use different interrupt sources, and more than two dino(4) devices
can attach.
Tested on 715/75 (old-gen using asp), 715/100/XC (new-gen using lasi),
B132L+, B180L, C240, B2000, C3650.
B2000 and C3650 test have been done with sys/dev/ic/com.c downgraded to
1.166 in order to avoid freezes (bug resolution ongoing and not related
to this diff).
715 and B1xx tests have been done with sys/dev/pckbc/pckbd.c downgraded
to 1.43 (bug resolution ongoing and not related to this diff).
$ cat levandes.vari
Index: conf/GENERIC
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/conf/GENERIC,v
retrieving revision 1.175
diff -u -p -r1.175 GENERIC
--- conf/GENERIC 14 Feb 2018 23:51:49 -0000 1.175
+++ conf/GENERIC 1 May 2018 20:03:14 -0000
@@ -46,21 +46,19 @@ uturn0 at mainbus0 # U2/UTurn Runway IO
uturn1 at mainbus0
astro* at mainbus0 # Astro memory & I/O controller
-lasi0 at mainbus0 offset 0x100000 irq 28 # LASI host adapter
-lasi0 at mainbus0 offset 0xfd00000 irq 28 # LASI on C1[01]0, J2[01]0
-lasi0 at phantomas0 offset 0xfd00000 irq 28 # LASI on [AB]*
-lasi0 at uturn? offset 0xfd00000 irq 28 # LASI on [CJ]*
-lasi1 at mainbus0 offset 0x500000 irq 27 # 712 GIO card
-asp* at mainbus0 irq 28 # this one comes w/ Viper and LEDs
-wax* at mainbus0 irq 24 # Wax may host EISA as well
-wax* at phantomas0 irq 24 # Wax on [AB]*
-wax* at uturn? irq 24 # Wax on C*
+lasi0 at mainbus0 offset 0x100000 # LASI host adapter
+lasi0 at mainbus0 offset 0xfd00000 # LASI on C1[01]0, J2[01]0
+lasi0 at phantomas0 offset 0xfd00000 # LASI on [AB]*
+lasi0 at uturn? offset 0xfd00000 # LASI on [CJ]*
+lasi1 at mainbus0 offset 0x500000 # 712 GIO card
+asp* at mainbus0 # this one comes w/ Viper and LEDs
+wax* at mainbus0 # Wax may host EISA as well
+wax* at phantomas0 # Wax on [AB]*
+wax* at uturn? # Wax on C*
mongoose* at mainbus0 irq 17 # EISA Bus Adapter (i82350 or TI???)
#vmeb* at mainbus0 irq ? # VME bus adapter
-dino0 at phantomas? irq 26 # PCI bus bridge on [AB]*
-dino1 at phantomas? irq 25
-dino0 at uturn0 irq 26 # PCI bus bridge on [CJ]*
-dino1 at uturn1 irq 25
+dino* at phantomas? # PCI bus bridge on [AB]*
+dino* at uturn? # PCI bus bridge on [CJ]*
pci* at dino?
option PCIVERBOSE
#pckbc0 at dino? irq 9
@@ -176,12 +174,9 @@ onewire* at uow?
udl* at uhub? # DisplayLink USB displays
wsdisplay* at udl?
-sti0 at mainbus0 irq 11 # [H]CRX-{8,24,48}[Z] graphics
-sti0 at phantomas0 irq 11 # builtin graphics on BC*
-sti0 at uturn? irq 11
-sti1 at mainbus0 irq 12
-sti1 at phantomas0 irq 12
-sti1 at uturn? irq 12
+sti* at mainbus0 # [H]CRX-{8,24,48}[Z] graphics
+sti* at phantomas0 # builtin graphics on BC*
+sti* at uturn?
sti* at pci? # EG-PCI, FX*
# internal i/o space
Index: conf/RAMDISK
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/conf/RAMDISK,v
retrieving revision 1.109
diff -u -p -r1.109 RAMDISK
--- conf/RAMDISK 30 Dec 2016 22:36:07 -0000 1.109
+++ conf/RAMDISK 1 May 2018 20:03:14 -0000
@@ -48,20 +48,18 @@ uturn0 at mainbus0 # U2/UTurn
Runway I
uturn1 at mainbus0
astro* at mainbus0 # Astro memory & I/O controller
-lasi0 at mainbus0 offset 0x100000 irq 28 # LASI host adapter
-lasi0 at mainbus0 offset 0xfd00000 irq 28 # LASI on C1[01]0,
J2[01]0
-lasi0 at phantomas0 offset 0xfd00000 irq 28 # LASI on [AB]*
-lasi0 at uturn? offset 0xfd00000 irq 28 # LASI on [CJ]*
-lasi1 at mainbus0 offset 0x500000 irq 27 # 712 GIO card
-asp* at mainbus0 irq 28 # this one comes w/ Viper and LEDs
-wax* at mainbus0 irq 24 # Wax may host EISA as well
-wax* at phantomas0 irq 24 # Wax on [AB]*
-wax* at uturn? irq 24 # Wax on C*
+lasi0 at mainbus0 offset 0x100000 # LASI host adapter
+lasi0 at mainbus0 offset 0xfd00000 # LASI on C1[01]0, J2[01]0
+lasi0 at phantomas0 offset 0xfd00000 # LASI on [AB]*
+lasi0 at uturn? offset 0xfd00000 # LASI on [CJ]*
+lasi1 at mainbus0 offset 0x500000 # 712 GIO card
+asp* at mainbus0 # this one comes w/ Viper and LEDs
+wax* at mainbus0 # Wax may host EISA as well
+wax* at phantomas0 # Wax on [AB]*
+wax* at uturn? # Wax on C*
mongoose* at mainbus0 irq 17 # EISA Bus Adapter (i82350 or TI???)
-dino0 at phantomas? irq 26 # PCI bus bridge on [AB]*
-dino1 at phantomas? irq 25
-dino0 at uturn0 irq 26 # PCI bus bridge on [CJ]*
-dino1 at uturn1 irq 25
+dino* at phantomas? # PCI bus bridge on [AB]*
+dino* at uturn0 # PCI bus bridge on [CJ]*
pci* at dino?
com1 at dino? irq 11
@@ -112,12 +110,9 @@ ugl* at uhub? # Genesys Logic
GL620USB
wi* at uhub? # WaveLAN IEEE 802.11DS
ural* at uhub? # Ralink RT2500
-sti0 at mainbus0 irq 11 # [H]CRX-{8,24,48}[Z] graphics
-sti0 at phantomas0 irq 11 # builtin graphics on BC*
-sti0 at uturn? irq 11
-sti1 at mainbus0 irq 12
-sti1 at phantomas0 irq 12
-sti1 at uturn? irq 12
+sti* at mainbus0 # [H]CRX-{8,24,48}[Z] graphics
+sti* at phantomas0 # builtin graphics on BC*
+sti* at uturn?
sti* at pci? # EG-PCI, FX*
gsc0 at asp? # Snakes, old 715, old 725, 735/755
Index: dev/apic.c
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/dev/apic.c,v
retrieving revision 1.18
diff -u -p -r1.18 apic.c
--- dev/apic.c 8 Sep 2015 07:14:04 -0000 1.18
+++ dev/apic.c 1 May 2018 20:03:14 -0000
@@ -134,8 +134,10 @@ apic_intr_map(struct pci_attach_args *pa
PCI_INTERRUPT_LINE(reg));
#endif
line = PCI_INTERRUPT_LINE(reg);
- if (sc->sc_irq[line] == 0)
- sc->sc_irq[line] = cpu_intr_findirq();
+ if (sc->sc_irq[line] <= 0) {
+ if ((sc->sc_irq[line] = cpu_intr_findirq()) == -1)
+ return 1;
+ }
*ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line];
return (APIC_INT_IRQ(*ihp) == 0);
}
Index: dev/asp.c
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/dev/asp.c,v
retrieving revision 1.14
diff -u -p -r1.14 asp.c
--- dev/asp.c 9 Jun 2005 18:01:36 -0000 1.14
+++ dev/asp.c 1 May 2018 20:03:14 -0000
@@ -45,7 +45,6 @@
#include <machine/cpufunc.h>
#include <hppa/dev/cpudevs.h>
-#include <hppa/dev/viper.h>
#include <hppa/gsc/gscbusvar.h>
@@ -181,8 +180,6 @@ aspattach(parent, self, aux)
/* delay(400000); */
s = splhigh();
- viper_setintrwnd(1 << ca->ca_irq);
-
sc->sc_trs->asp_imr = ~0;
irr = sc->sc_trs->asp_irr;
sc->sc_trs->asp_imr = 0;
Index: dev/dino.c
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/dev/dino.c,v
retrieving revision 1.31
diff -u -p -r1.31 dino.c
--- dev/dino.c 29 Mar 2014 18:09:29 -0000 1.31
+++ dev/dino.c 1 May 2018 20:03:14 -0000
@@ -394,7 +394,7 @@ dino_intr_string(void *v, pci_intr_handl
{
static char buf[32];
- snprintf(buf, 32, "irq %ld", ih);
+ snprintf(buf, 32, "dino irq %ld", ih);
return (buf);
}
@@ -1681,7 +1681,7 @@ dinoattach(parent, self, aux)
volatile struct dino_regs *r;
const char *p = NULL;
u_int data;
- int s;
+ int s, irqbit;
sc->sc_bt = ca->ca_iot;
sc->sc_dmat = ca->ca_dmatag;
@@ -1731,20 +1731,6 @@ dinoattach(parent, self, aux)
/* TODO reserve dino's pci space ? */
- s = splhigh();
- r->imr = ~0;
- data = r->irr0;
- data = r->irr1;
- r->imr = 0;
- __asm volatile ("" ::: "memory");
- r->icr = 0;
- r->iar0 = cpu_gethpa(0) | (31 - ca->ca_irq);
- splx(s);
-
- sc->sc_ih = cpu_intr_establish(IPL_NESTED, ca->ca_irq,
- dino_intr, (void *)sc->sc_regs, sc->sc_dv.dv_xname);
- /* TODO establish the bus error interrupt */
-
sc->sc_ver = ca->ca_type.iodc_revision;
switch ((ca->ca_type.iodc_model << 4) |
(ca->ca_type.iodc_revision >> 4)) {
@@ -1774,8 +1760,39 @@ dinoattach(parent, self, aux)
break;
}
+ irqbit = cpu_intr_findirq();
+ if (irqbit >= 0)
+ printf(" irq %d", irqbit);
+
printf(": %s V%d.%d\n", p, sc->sc_ver >> 4, sc->sc_ver & 0xf);
+ s = splhigh();
+ r->imr = ~0;
+ data = r->irr0;
+ data = r->irr1;
+ r->imr = 0;
+ __asm volatile ("" ::: "memory");
+ r->icr = 0;
+ if (irqbit >= 0)
+ r->iar0 = cpu_gethpa(0) | (31 - irqbit);
+ splx(s);
+
+ if (irqbit < 0)
+ sc->sc_ih = NULL;
+ else
+ sc->sc_ih = cpu_intr_establish(IPL_NESTED, irqbit,
+ dino_intr, (void *)sc->sc_regs, sc->sc_dv.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf("%s: can't establish interrupt\n", sc->sc_dv.dv_xname);
+ return;
+ }
+
+ /* TODO establish the bus error interrupt */
+
+ /* scan for ps2 kbd/ms, serial, and flying toasters */
+ ca->ca_hpamask = -1;
+ pdc_scanbus(self, ca, MAXMODBUS, 0, 0);
+
sc->sc_iot = dino_iomemt;
sc->sc_iot.hbt_cookie = sc;
sc->sc_iot.hbt_map = dino_iomap;
@@ -1788,10 +1805,6 @@ dinoattach(parent, self, aux)
sc->sc_pc._cookie = sc;
sc->sc_dmatag = dino_dmat;
sc->sc_dmatag._cookie = sc;
-
- /* scan for ps2 kbd/ms, serial, and flying toasters */
- ca->ca_hpamask = -1;
- pdc_scanbus(self, ca, MAXMODBUS, 0, 0);
bzero(&pba, sizeof(pba));
pba.pba_busname = "pci";
Index: dev/lasi.c
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/dev/lasi.c,v
retrieving revision 1.22
diff -u -p -r1.22 lasi.c
--- dev/lasi.c 15 Sep 2004 20:11:28 -0000 1.22
+++ dev/lasi.c 1 May 2018 20:03:14 -0000
@@ -55,11 +55,11 @@ struct lasi_hwr {
};
struct lasi_trs {
- u_int32_t lasi_irr; /* int requset register */
+ u_int32_t lasi_irr; /* int request register */
u_int32_t lasi_imr; /* int mask register */
u_int32_t lasi_ipr; /* int pending register */
- u_int32_t lasi_icr; /* int command? register */
- u_int32_t lasi_iar; /* int acquire? register */
+ u_int32_t lasi_icr; /* int control register */
+ u_int32_t lasi_iar; /* int address register */
};
struct lasi_softc {
@@ -135,7 +135,7 @@ lasiattach(parent, self, aux)
/* interrupts guts */
s = splhigh();
- sc->sc_trs->lasi_iar = cpu_gethpa(0) | (31 - ca->ca_irq);
+ sc->sc_trs->lasi_iar = 0; /* will be set up by gsc when attaching */
sc->sc_trs->lasi_icr = 0;
sc->sc_trs->lasi_imr = ~0U;
in = sc->sc_trs->lasi_irr;
Index: dev/wax.c
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/dev/wax.c,v
retrieving revision 1.10
diff -u -p -r1.10 wax.c
--- dev/wax.c 8 Nov 2004 20:53:25 -0000 1.10
+++ dev/wax.c 1 May 2018 20:03:14 -0000
@@ -44,8 +44,8 @@ struct wax_regs {
u_int32_t wax_irr; /* int request register */
u_int32_t wax_imr; /* int mask register */
u_int32_t wax_ipr; /* int pending register */
- u_int32_t wax_icr; /* int command? register */
- u_int32_t wax_iar; /* int acquire? register */
+ u_int32_t wax_icr; /* int control register */
+ u_int32_t wax_iar; /* int address register */
};
struct wax_softc {
@@ -108,7 +108,7 @@ waxattach(parent, self, aux)
/* interrupts guts */
s = splhigh();
- sc->sc_regs->wax_iar = cpu_gethpa(0) | (31 - ca->ca_irq);
+ sc->sc_regs->wax_iar = 0; /* will be set up by gsc when attaching */
sc->sc_regs->wax_icr = 0;
sc->sc_regs->wax_imr = ~0U;
in = sc->sc_regs->wax_irr;
Index: gsc/gscbus.c
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/gsc/gscbus.c,v
retrieving revision 1.30
diff -u -p -r1.30 gscbus.c
--- gsc/gscbus.c 28 Nov 2010 20:09:40 -0000 1.30
+++ gsc/gscbus.c 1 May 2018 20:03:14 -0000
@@ -38,6 +38,7 @@
#include <machine/iomod.h>
#include <machine/autoconf.h>
#include <machine/cpufunc.h>
+#include <hppa/dev/viper.h>
#include <hppa/gsc/gscbusvar.h>
@@ -71,18 +72,43 @@ gscattach(parent, self, aux)
{
struct gsc_softc *sc = (struct gsc_softc *)self;
struct gsc_attach_args *ga = aux;
+ int s, irqbit;
sc->sc_iot = ga->ga_iot;
sc->sc_ic = ga->ga_ic;
+ irqbit = cpu_intr_findirq();
+ if (irqbit >= 0)
+ printf(" irq %d", irqbit);
+
#ifdef USELEDS
if (machine_ledaddr)
printf(": %sleds", machine_ledword? "word" : "");
#endif
printf ("\n");
- sc->sc_ih = cpu_intr_establish(IPL_NESTED, ga->ga_irq,
- gsc_intr, (void *)sc->sc_ic->gsc_base, sc->sc_dev.dv_xname);
+ if (irqbit < 0)
+ sc->sc_ih = NULL;
+ else
+ sc->sc_ih = cpu_intr_establish(IPL_NESTED, irqbit,
+ gsc_intr, (void *)sc->sc_ic->gsc_base, sc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ s = splhigh();
+ /*
+ * On ASP, the IAR register is not writable; we need to go through
+ * the memory controller to achieve proper routing.
+ */
+ if (sc->sc_ic->gsc_type == gsc_asp) {
+ viper_setintrwnd(1 << irqbit);
+ } else {
+ volatile u_int32_t *r = sc->sc_ic->gsc_base;
+ r[4] = cpu_gethpa(0) | (31 - irqbit); /* iar */
+ }
+ splx(s);
pdc_scanbus(self, &ga->ga_ca, MAXMODBUS, 0, 0);
}
Index: hppa/intr.c
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/hppa/intr.c,v
retrieving revision 1.49
diff -u -p -r1.49 intr.c
--- hppa/intr.c 13 Sep 2015 14:58:20 -0000 1.49
+++ hppa/intr.c 1 May 2018 20:03:14 -0000
@@ -134,12 +134,16 @@ cpu_intr_init(void)
ssm(PSL_I, mask);
}
+/*
+ * Find an available, non-shared interrupt bit.
+ * Returns -1 if all interrupt bits are in use.
+ */
int
cpu_intr_findirq(void)
{
int irq;
- for (irq = 0; irq < CPU_NINTS; irq++)
+ for (irq = CPU_NINTS - 1; irq >= 0; irq--)
if (intr_table[irq].handler == NULL &&
intr_table[irq].pri == 0)
return irq;
Index: hppa/mainbus.c
===================================================================
RCS file: /OpenBSD/src/sys/arch/hppa/hppa/mainbus.c,v
retrieving revision 1.87
diff -u -p -r1.87 mainbus.c
--- hppa/mainbus.c 13 Sep 2015 11:40:01 -0000 1.87
+++ hppa/mainbus.c 1 May 2018 20:03:14 -0000
@@ -1238,7 +1238,7 @@ mbattach(parent, self, aux)
}
/*
- * retrive CPU #N HPA value
+ * Retrieve CPU #N HPA value
*/
hppa_hpa_t
cpu_gethpa(n)