Restore the behaviour intended by rev 1.51 with the patch I actually
send out for testing. The wrong version ended up in the commit. Original description: Don't use the legacy interrupt when deciding how to route IOAPIC pins. On some modern systems not all devices have the PCI interrupt line set, typically the cardbus bridge is affected and it would result in different interrupt vectors used for the same IOAPIC pin. To allow this, simplify the code by checking for an existing match first and only allocate a new entry if that doesn't exist. For the IOAPIC case don't bother with the reserveration on the primary CPU for ISA interrupts, just use them.
This commit is contained in:
parent
e04f8f6085
commit
816cef7d46
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: intr.c,v 1.52 2008/05/13 12:14:06 ad Exp $ */
|
||||
/* $NetBSD: intr.c,v 1.53 2008/05/13 14:29:17 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
|
||||
@ -133,7 +133,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.52 2008/05/13 12:14:06 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.53 2008/05/13 14:29:17 joerg Exp $");
|
||||
|
||||
#include "opt_multiprocessor.h"
|
||||
#include "opt_acpi.h"
|
||||
@ -468,28 +468,33 @@ static int
|
||||
intr_allocate_slot_cpu(struct cpu_info *ci, struct pic *pic, int pin,
|
||||
int *index)
|
||||
{
|
||||
int start, slot, i;
|
||||
int slot, i;
|
||||
struct intrsource *isp;
|
||||
|
||||
start = CPU_IS_PRIMARY(ci) ? NUM_LEGACY_IRQS : 0;
|
||||
slot = -1;
|
||||
if (pic == &i8259_pic) {
|
||||
if (!CPU_IS_PRIMARY(ci))
|
||||
return EBUSY;
|
||||
slot = pin;
|
||||
mutex_enter(&x86_intr_lock);
|
||||
} else {
|
||||
slot = -1;
|
||||
|
||||
mutex_enter(&x86_intr_lock);
|
||||
for (i = start; i < MAX_INTR_SOURCES ; i++) {
|
||||
isp = ci->ci_isources[i];
|
||||
if (isp != NULL && isp->is_pic == pic && isp->is_pin == pin) {
|
||||
slot = i;
|
||||
break;
|
||||
mutex_enter(&x86_intr_lock);
|
||||
/*
|
||||
* intr_allocate_slot has checked for an existing mapping.
|
||||
* Now look for a free slot.
|
||||
*/
|
||||
for (i = 0; i < MAX_INTR_SOURCES ; i++) {
|
||||
if (ci->ci_isources[i] == NULL) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isp == NULL && slot == -1) {
|
||||
slot = i;
|
||||
continue;
|
||||
if (slot == -1) {
|
||||
mutex_exit(&x86_intr_lock);
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
||||
if (slot == -1) {
|
||||
mutex_exit(&x86_intr_lock);
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
isp = ci->ci_isources[slot];
|
||||
if (isp == NULL) {
|
||||
@ -515,7 +520,7 @@ intr_allocate_slot_cpu(struct cpu_info *ci, struct pic *pic, int pin,
|
||||
* A simple round-robin allocator to assign interrupts to CPUs.
|
||||
*/
|
||||
static int
|
||||
intr_allocate_slot(struct pic *pic, int legacy_irq, int pin, int level,
|
||||
intr_allocate_slot(struct pic *pic, int pin, int level,
|
||||
struct cpu_info **cip, int *index, int *idt_slot)
|
||||
{
|
||||
CPU_INFO_ITERATOR cii;
|
||||
@ -523,69 +528,44 @@ intr_allocate_slot(struct pic *pic, int legacy_irq, int pin, int level,
|
||||
struct intrsource *isp;
|
||||
int slot, idtvec, error;
|
||||
|
||||
/*
|
||||
* If a legacy IRQ is wanted, try to use a fixed slot pointing
|
||||
* at the primary CPU. In the case of IO APICs, multiple pins
|
||||
* may map to one legacy IRQ, but they should not be shared
|
||||
* in that case, so the first one gets the legacy slot, but
|
||||
* a subsequent allocation with a different pin will get
|
||||
* a different slot.
|
||||
*/
|
||||
if (legacy_irq != -1) {
|
||||
ci = &cpu_info_primary;
|
||||
/* must check for duplicate pic + pin first */
|
||||
/* First check if this pin is already used by an interrupt vector. */
|
||||
for (CPU_INFO_FOREACH(cii, ci)) {
|
||||
for (slot = 0 ; slot < MAX_INTR_SOURCES ; slot++) {
|
||||
isp = ci->ci_isources[slot];
|
||||
if (isp != NULL && isp->is_pic == pic &&
|
||||
isp->is_pin == pin ) {
|
||||
goto duplicate;
|
||||
if ((isp = ci->ci_isources[slot]) == NULL)
|
||||
continue;
|
||||
if (isp->is_pic == pic && isp->is_pin == pin) {
|
||||
*idt_slot = isp->is_idtvec;
|
||||
*index = slot;
|
||||
*cip = ci;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
slot = legacy_irq;
|
||||
isp = ci->ci_isources[slot];
|
||||
if (isp == NULL) {
|
||||
MALLOC(isp, struct intrsource *,
|
||||
sizeof (struct intrsource), M_DEVBUF,
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (isp == NULL)
|
||||
return ENOMEM;
|
||||
snprintf(isp->is_evname, sizeof (isp->is_evname),
|
||||
"pin %d", pin);
|
||||
evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR,
|
||||
NULL, device_xname(&pic->pic_dev), isp->is_evname);
|
||||
mutex_enter(&x86_intr_lock);
|
||||
ci->ci_isources[slot] = isp;
|
||||
mutex_exit(&x86_intr_lock);
|
||||
} else {
|
||||
if (isp->is_pin != pin) {
|
||||
if (pic == &i8259_pic)
|
||||
return EINVAL;
|
||||
goto other;
|
||||
}
|
||||
}
|
||||
duplicate:
|
||||
if (pic == &i8259_pic)
|
||||
idtvec = ICU_OFFSET + legacy_irq;
|
||||
else {
|
||||
if (isp->is_minlevel == 0 || level < isp->is_minlevel) {
|
||||
idtvec = idt_vec_alloc(APIC_LEVEL(level),
|
||||
IDT_INTR_HIGH);
|
||||
if (idtvec == 0)
|
||||
return EBUSY;
|
||||
} else
|
||||
idtvec = isp->is_idtvec;
|
||||
}
|
||||
} else {
|
||||
other:
|
||||
/*
|
||||
* Otherwise, look for a free slot elsewhere. Do the primary
|
||||
* CPU first.
|
||||
*/
|
||||
ci = &cpu_info_primary;
|
||||
error = intr_allocate_slot_cpu(ci, pic, pin, &slot);
|
||||
if (error == 0)
|
||||
goto found;
|
||||
}
|
||||
|
||||
/*
|
||||
* The pic/pin combination doesn't have an existing mapping.
|
||||
* Find a slot for a new interrupt source and allocate an IDT
|
||||
* vector.
|
||||
*
|
||||
* For the i8259 case, this always uses the reserved slots
|
||||
* of the primary CPU and fixed IDT vectors. This is required
|
||||
* by other parts of the code, see x86/intr.h for more details.
|
||||
*
|
||||
* For the IOAPIC case, interrupts are assigned to the
|
||||
* primary CPU by default, until it runs out of slots.
|
||||
*
|
||||
* PIC and APIC usage are essentially exclusive, so the reservation
|
||||
* of the ISA slots is ignored when assigning IOAPIC slots.
|
||||
*
|
||||
* XXX Fix interrupt allocation to Application Processors.
|
||||
* XXX Check how many interrupts each CPU got and assign it to
|
||||
* XXX the least loaded CPU. Consider adding options to bind
|
||||
* XXX interrupts to specific CPUs.
|
||||
* XXX Drop apic level support, just assign IDT vectors sequentially.
|
||||
*/
|
||||
ci = &cpu_info_primary;
|
||||
error = intr_allocate_slot_cpu(ci, pic, pin, &slot);
|
||||
if (error != 0) {
|
||||
/*
|
||||
* ..now try the others.
|
||||
*/
|
||||
@ -594,19 +574,27 @@ other:
|
||||
continue;
|
||||
error = intr_allocate_slot_cpu(ci, pic, pin, &slot);
|
||||
if (error == 0)
|
||||
goto found;
|
||||
break;
|
||||
}
|
||||
return EBUSY;
|
||||
found:
|
||||
idtvec = idt_vec_alloc(APIC_LEVEL(level), IDT_INTR_HIGH);
|
||||
if (idtvec == 0) {
|
||||
mutex_enter(&x86_intr_lock);
|
||||
FREE(ci->ci_isources[slot], M_DEVBUF);
|
||||
ci->ci_isources[slot] = NULL;
|
||||
mutex_exit(&x86_intr_lock);
|
||||
if (error != 0)
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
if (pic == &i8259_pic)
|
||||
idtvec = ICU_OFFSET + pin;
|
||||
else
|
||||
idtvec = idt_vec_alloc(APIC_LEVEL(level), IDT_INTR_HIGH);
|
||||
|
||||
if (idtvec == 0) {
|
||||
mutex_enter(&x86_intr_lock);
|
||||
evcnt_detach(&ci->ci_isources[slot]->is_evcnt);
|
||||
FREE(ci->ci_isources[slot], M_DEVBUF);
|
||||
ci->ci_isources[slot] = NULL;
|
||||
mutex_exit(&x86_intr_lock);
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
ci->ci_isources[slot]->is_idtvec = idtvec;
|
||||
*idt_slot = idtvec;
|
||||
*index = slot;
|
||||
*cip = ci;
|
||||
@ -673,7 +661,7 @@ intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level,
|
||||
panic("intr_establish: non-legacy IRQ on i8259");
|
||||
#endif
|
||||
|
||||
error = intr_allocate_slot(pic, legacy_irq, pin, level, &ci, &slot,
|
||||
error = intr_allocate_slot(pic, pin, level, &ci, &slot,
|
||||
&idt_vec);
|
||||
if (error != 0) {
|
||||
printf("failed to allocate interrupt slot for PIC %s pin %d\n",
|
||||
|
Loading…
Reference in New Issue
Block a user