* Introduce {reserve|allocate|free}_io_interrupt_vectors() that can generically

be used to mark certain io interrupt vectors as reserved and to allocate from
  the still free ones. It is a kernel private API for now though.
* Make the MSI code use that functionality instead of implementing its own which
  slims it down considerably and also removes quite a bit of hardcoded knowledge
  about the interrupt layout that didn't really belong there.
* Mark the various in-use interrupts as reserved from the components that
  actually know about them (PIC, IO-APIC, SMP, APIC timer and interrupt setup).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42832 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2011-10-12 20:55:28 +00:00
parent 6b0b621be9
commit fc2d7cb04d
8 changed files with 141 additions and 73 deletions

View File

@ -53,4 +53,8 @@ are_interrupts_enabled(void)
#define restore_interrupts(status) arch_int_restore_interrupts(status)
status_t reserve_io_interrupt_vectors(long count, long startVector);
status_t allocate_io_interrupt_vectors(long count, long *startVector);
void free_io_interrupt_vectors(long count, long startVector);
#endif /* _KERNEL_INT_H */

View File

@ -84,6 +84,7 @@ static desc_table* sIDTs[B_MAX_CPU_COUNT];
// table with functions handling respective interrupts
typedef void interrupt_handler_function(struct iframe* frame);
#define INTERRUPT_HANDLER_TABLE_SIZE 256
interrupt_handler_function* gInterruptHandlerTable[
INTERRUPT_HANDLER_TABLE_SIZE];
@ -653,6 +654,8 @@ arch_int_init(struct kernel_args *args)
set_trap_gate(0, 98, &trap98); // for performance testing only
set_trap_gate(0, 99, &trap99); // syscall interrupt
reserve_io_interrupt_vectors(2, 98);
// configurable msi or msi-x interrupts
set_interrupt_gate(0, 100, &trap100);
set_interrupt_gate(0, 101, &trap101);

View File

@ -90,6 +90,7 @@ arch_smp_init(kernel_args *args)
if (args->num_cpus > 1) {
// I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted
reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE);
install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &i386_ici_interrupt, NULL, B_NO_LOCK_VECTOR);
install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &i386_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR);
install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &i386_spurious_interrupt, NULL, B_NO_LOCK_VECTOR);

View File

@ -767,6 +767,14 @@ ioapic_init(kernel_args* args)
ioapic_enable_io_interrupt(i);
}
// mark the interrupt vectors reserved so they aren't used for other stuff
current = sIOAPICs;
while (current != NULL) {
reserve_io_interrupt_vectors(current->max_redirection_entry + 1,
current->global_interrupt_base);
current = current->next;
}
// prefer the ioapic over the normal pic
dprintf("using io-apics for interrupt routing\n");
arch_int_set_interrupt_controller(ioapicController);

View File

@ -4,20 +4,14 @@
*/
#include <arch/x86/apic.h>
#include <arch/x86/arch_int.h>
#include <arch/x86/ioapic.h>
#include <arch/x86/msi.h>
#include <debug.h>
#include <int.h>
#include <lock.h>
static const uint32 kVectorCount = 256 - ARCH_INTERRUPT_BASE;
static const uint8 kNumISAVectors = 16;
static bool sMSISupported = false;
static bool sAllocatedVectors[kVectorCount];
static mutex sMSIAllocationLock = MUTEX_INITIALIZER("msi_allocation");
void
@ -28,27 +22,6 @@ msi_init()
return;
}
// TODO: less hardcoding!
// the first 16 vectors are legacy ISA in all cases
for (uint16 i = 0; i < kNumISAVectors; i++)
sAllocatedVectors[i] = true;
for (uint16 i = kNumISAVectors; i < kVectorCount; i++) {
// if ioapics aren't in use this will always return false, leaving
// the vectors free for us; otherwise we'll avoid any vector that
// can be addressed by an IO-APIC
sAllocatedVectors[i] = ioapic_is_interrupt_available(i);
}
// performance testing and syscall interrupts
sAllocatedVectors[98 - ARCH_INTERRUPT_BASE] = true;
sAllocatedVectors[99 - ARCH_INTERRUPT_BASE] = true;
// the upper range is used by apic local (timer) and smp interrupts (ipi)
for (uint16 i = 251; i < 256; i++)
sAllocatedVectors[i - ARCH_INTERRUPT_BASE] = true;
dprintf("msi support enabled\n");
sMSISupported = true;
}
@ -68,46 +41,24 @@ msi_allocate_vectors(uint8 count, uint8 *startVector, uint64 *address,
if (!sMSISupported)
return B_UNSUPPORTED;
mutex_lock(&sMSIAllocationLock);
long vector;
status_t result = allocate_io_interrupt_vectors(count, &vector);
if (result != B_OK)
return result;
uint8 vector = 0;
bool runFound = true;
for (uint16 i = 0; i < kVectorCount - (count - 1); i++) {
if (!sAllocatedVectors[i]) {
vector = i;
runFound = true;
for (uint16 j = 1; j < count; j++) {
if (sAllocatedVectors[i + j]) {
runFound = false;
i += j;
break;
}
}
if (runFound)
break;
}
}
if (!runFound) {
mutex_unlock(&sMSIAllocationLock);
dprintf("found no free vectors to allocate %u msi messages\n", count);
if (vector >= 256) {
free_io_interrupt_vectors(count, vector);
return B_NO_MEMORY;
}
for (uint16 i = 0; i < count; i++)
sAllocatedVectors[i + vector] = true;
mutex_unlock(&sMSIAllocationLock);
*startVector = vector;
*startVector = (uint8)vector;
*address = MSI_ADDRESS_BASE | (0 << MSI_DESTINATION_ID_SHIFT)
| MSI_NO_REDIRECTION | MSI_DESTINATION_MODE_PHYSICAL;
*data = MSI_TRIGGER_MODE_EDGE | MSI_DELIVERY_MODE_FIXED
| (vector + ARCH_INTERRUPT_BASE);
| ((uint16)vector + ARCH_INTERRUPT_BASE);
dprintf("msi_allocate_vectors: allocated %u vectors starting from %u\n",
count, vector);
count, *startVector);
return B_OK;
}
@ -120,21 +71,8 @@ msi_free_vectors(uint8 count, uint8 startVector)
return;
}
if ((uint32)startVector + count > kVectorCount) {
panic("invalid start vector %u or count %u supplied to "
"msi_free_vectors\n", startVector, count);
}
dprintf("msi_free_vectors: freeing %u vectors starting from %u\n", count,
startVector);
mutex_lock(&sMSIAllocationLock);
for (uint16 i = 0; i < count; i++) {
if (!sAllocatedVectors[i + startVector])
panic("msi vector %u was not allocated\n", i + startVector);
sAllocatedVectors[i + startVector] = false;
}
mutex_unlock(&sMSIAllocationLock);
free_io_interrupt_vectors(count, startVector);
}

View File

@ -13,6 +13,8 @@
#include <arch/x86/arch_int.h>
#include <int.h>
//#define TRACE_PIC
#ifdef TRACE_PIC
@ -229,6 +231,8 @@ pic_init()
TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts));
reserve_io_interrupt_vectors(16, 0);
// make the pic controller the current one
arch_int_set_interrupt_controller(picController);
}
@ -243,4 +247,6 @@ pic_disable(uint16& enabledInterrupts)
// Mask off all interrupts on master and slave
out8(0xff, PIC_MASTER_MASK);
out8(0xff, PIC_SLAVE_MASK);
free_io_interrupt_vectors(16, 0);
}

View File

@ -105,6 +105,8 @@ apic_timer_init(struct kernel_args *args)
return B_ERROR;
sApicTicsPerSec = args->arch_args.apic_time_cv_factor;
reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE);
install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE,
&apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR);

View File

@ -1,4 +1,7 @@
/*
* Copyright 2011, Michael Lotz, mmlr@mlotz.ch.
* Distributed under the terms of the MIT License.
*
* Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
@ -17,6 +20,7 @@
#include <arch/int.h>
#include <boot/kernel_args.h>
#include <elf.h>
#include <util/AutoLock.h>
#include <util/kqueue.h>
#include <smp.h>
@ -56,6 +60,9 @@ struct io_vector {
};
static struct io_vector sVectors[NUM_IO_VECTORS];
static bool sAllocatedIOInterruptVectors[NUM_IO_VECTORS];
static mutex sIOInterruptVectorAllocationLock
= MUTEX_INITIALIZER("io_interrupt_vector_allocation");
#if DEBUG_INTERRUPTS
@ -421,3 +428,102 @@ remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data)
return status;
}
/* Mark \a count contigous interrupts starting at \a startVector as in use.
This will prevent them from being allocated by others. Only use this when
the reserved range is hardwired to the given vector, otherwise allocate
vectors using allocate_io_interrupt_vectors() instead.
*/
status_t
reserve_io_interrupt_vectors(long count, long startVector)
{
MutexLocker locker(&sIOInterruptVectorAllocationLock);
for (long i = 0; i < count; i++) {
if (sAllocatedIOInterruptVectors[startVector + i]) {
panic("reserved interrupt vector range %ld-%ld overlaps already "
"allocated vector %ld", startVector, startVector + count - 1,
startVector + i);
free_io_interrupt_vectors(i, startVector);
return B_BUSY;
}
sAllocatedIOInterruptVectors[startVector + i] = true;
}
dprintf("reserve_io_interrupt_vectors: reserved %ld vectors starting "
"from %ld\n", count, startVector);
return B_OK;
}
/*! Allocate \a count contigous interrupt vectors. The vectors are allocated
as available so that they do not overlap with any other reserved vector.
The first vector to be used is returned in \a startVector on success.
*/
status_t
allocate_io_interrupt_vectors(long count, long *startVector)
{
MutexLocker locker(&sIOInterruptVectorAllocationLock);
long vector = 0;
bool runFound = true;
for (long i = 0; i < NUM_IO_VECTORS - (count - 1); i++) {
if (sAllocatedIOInterruptVectors[i])
continue;
vector = i;
runFound = true;
for (uint16 j = 1; j < count; j++) {
if (sAllocatedIOInterruptVectors[i + j]) {
runFound = false;
i += j;
break;
}
}
if (runFound)
break;
}
if (!runFound) {
dprintf("found no free vectors to allocate %ld io interrupts\n", count);
return B_NO_MEMORY;
}
for (long i = 0; i < count; i++)
sAllocatedIOInterruptVectors[vector + i] = true;
*startVector = vector;
dprintf("allocate_io_interrupt_vectors: allocated %ld vectors starting "
"from %ld\n", count, vector);
return B_OK;
}
/*! Free/unreserve interrupt vectors previously allocated with the
{reserve|allocate}_io_interrupt_vectors() functions. The \a count and
\a startVector can be adjusted from the allocation calls to partially free
a vector range.
*/
void
free_io_interrupt_vectors(long count, long startVector)
{
if (startVector + count > NUM_IO_VECTORS) {
panic("invalid start vector %ld or count %ld supplied to "
"free_io_interrupt_vectors\n", startVector, count);
}
dprintf("free_io_interrupt_vectors: freeing %ld vectors starting "
"from %ld\n", count, startVector);
MutexLocker locker(sIOInterruptVectorAllocationLock);
for (long i = 0; i < count; i++) {
if (!sAllocatedIOInterruptVectors[startVector + i]) {
panic("io interrupt vector %ld was not allocated\n",
startVector + i);
}
sAllocatedIOInterruptVectors[startVector + i] = false;
}
}