Sync with the following OpenBSD changes, but do the shared interrupt

reporting differently.  Each cpu and device interrupt gets its own
counter.

revision 1.14
Fix counting of interrupts for devices that attach to elroy(4).  Shared
interrupts would be counted double, once for the interrupting device and
once for the device at the head of the chain.  The handlers would run properly
though.  Avoid this by giving each device its own interrupt counter instead
of using the counter provided by the generic interrupt handling code for the
head of the chain.

revision 1.13
Stop calling shared interrupt handlers as soon as one of them return 1
(positive interrupt was for me), like we do on other architectures.
This is done here, at the elroy(4) driver level, since this is where shared
PCI interrupts are handled.  We could do something similar for dino(4) but
this optimization is probably not very relevant there.
This commit is contained in:
skrll 2012-04-14 10:43:19 +00:00
parent ec32c33db9
commit d2c7e180a1
1 changed files with 44 additions and 36 deletions

View File

@ -1,6 +1,6 @@
/* $NetBSD: apic.c,v 1.13 2012/04/03 12:07:26 skrll Exp $ */
/* $NetBSD: apic.c,v 1.14 2012/04/14 10:43:19 skrll Exp $ */
/* $OpenBSD: apic.c,v 1.7 2007/10/06 23:50:54 krw Exp $ */
/* $OpenBSD: apic.c,v 1.14 2011/05/01 21:59:39 kettenis Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
@ -178,53 +178,61 @@ apic_intr_establish(void *v, pci_intr_handle_t ih,
if (aiv == NULL)
return NULL;
cnt = malloc(sizeof(struct evcnt), M_DEVBUF, M_NOWAIT);
if (cnt == NULL) {
free(aiv, M_DEVBUF);
return NULL;
}
aiv->sc = sc;
aiv->ih = ih;
aiv->handler = handler;
aiv->arg = arg;
aiv->next = NULL;
aiv->cnt = NULL;
if (apic_intr_list[irq]) {
cnt = malloc(sizeof(struct evcnt), M_DEVBUF, M_NOWAIT);
if (cnt == NULL) {
aiv->cnt = cnt;
biv = apic_intr_list[irq];
if (biv == NULL) {
iv = hp700_intr_establish(pri, apic_intr, aiv, &ir_cpu, irq);
if (iv == NULL) {
free(aiv, M_DEVBUF);
free(cnt, M_DEVBUF);
return NULL;
}
}
snprintf(aiv->aiv_name, sizeof(aiv->aiv_name), "line %d irq %d",
line, irq);
snprintf(aiv->aiv_name, sizeof(aiv->aiv_name), "line %d irq %d",
line, irq);
evcnt_attach_dynamic(cnt, EVCNT_TYPE_INTR, NULL,
device_xname(sc->sc_dv), aiv->aiv_name);
biv = apic_intr_list[irq];
evcnt_attach_dynamic(cnt, EVCNT_TYPE_INTR, NULL,
device_xname(sc->sc_dv), aiv->aiv_name);
if (biv) {
while (biv->next)
biv = biv->next;
biv->next = aiv;
aiv->cnt = cnt;
return arg;
}
iv = hp700_intr_establish(pri, apic_intr, aiv, &ir_cpu, irq);
if (iv) {
ent0 = (31 - irq) & APIC_ENT0_VEC;
ent0 |= apic_get_int_ent0(sc, line);
ent0 = (31 - irq) & APIC_ENT0_VEC;
ent0 |= apic_get_int_ent0(sc, line);
#if 0
if (cold) {
sc->sc_imr |= (1 << irq);
ent0 |= APIC_ENT0_MASK;
}
#endif
apic_write(sc->sc_regs, APIC_ENT0(line), APIC_ENT0_MASK);
apic_write(sc->sc_regs, APIC_ENT1(line),
((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12));
apic_write(sc->sc_regs, APIC_ENT0(line), ent0);
/* Signal EOI. */
elroy_write32(&r->apic_eoi,
htole32((31 - irq) & APIC_ENT0_VEC));
apic_intr_list[irq] = aiv;
if (cold) {
sc->sc_imr |= (1 << irq);
ent0 |= APIC_ENT0_MASK;
}
#endif
apic_write(sc->sc_regs, APIC_ENT0(line), APIC_ENT0_MASK);
apic_write(sc->sc_regs, APIC_ENT1(line),
((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12));
apic_write(sc->sc_regs, APIC_ENT0(line), ent0);
/* Signal EOI. */
elroy_write32(&r->apic_eoi,
htole32((31 - irq) & APIC_ENT0_VEC));
apic_intr_list[irq] = aiv;
return (arg);
}
@ -244,11 +252,11 @@ apic_intr(void *v)
int claimed = 0;
while (iv) {
if (iv->handler(iv->arg)) {
if (iv->cnt)
iv->cnt->ev_count++;
claimed = 1;
}
claimed = iv->handler(iv->arg);
if (claimed && iv->cnt)
iv->cnt->ev_count++;
if (claimed)
break;
iv = iv->next;
}
/* Signal EOI. */