* 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:
parent
6b0b621be9
commit
fc2d7cb04d
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user