* Don't map the IO-APIC within the bootloader. We don't need it to set up SMP

at all and, since there can be multiple IO-APICs, we need to do the
  enumeration again in the kernel anyway. Also only set ioapic_phys the first
  time we encounter an IO-APIC object as it looks cleaner when we arrive at the
  first IO-APIC default address.
* Therefore we don't have to worry about already mapped IO-APICs when
  enumerating them in the kernel.
* Also remove the mapping function that is now not used anymore.
* We still use the ioapic_phys field of the kernel args to determine whether
  there is an IO-APIC at all to avoid needlessly doing the enumeration again.

This fixes multi IO-APIC configurations, because before we would indeed map
the last IO-APIC listed in the MADT, but then in the kernel assumed we mapped
the first one. We'd end up with mapping the last listed IO-APIC twice and the
first IO-APIC never, always programming the last one when we actually targetted
the first one.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41476 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2011-05-13 16:31:31 +00:00
parent c75f313fbd
commit 8908aef9c2
4 changed files with 25 additions and 55 deletions

View File

@ -11,7 +11,6 @@ struct kernel_args;
bool ioapic_is_interrupt_available(int32 gsi);
void ioapic_map(kernel_args* args);
void ioapic_init(kernel_args* args);
#endif // _KERNEL_ARCH_x86_IOAPIC_H

View File

@ -204,7 +204,8 @@ smp_do_mp_config(mp_floating_struct *floatingStruct)
struct mp_base_ioapic *io = (struct mp_base_ioapic *)pointer;
pointer += sizeof(struct mp_base_ioapic);
gKernelArgs.arch_args.ioapic_phys = (uint32)io->addr;
if (gKernelArgs.arch_args.ioapic_phys != 0)
gKernelArgs.arch_args.ioapic_phys = (uint32)io->addr;
TRACE(("smp: found io apic with apic id %d, version %d\n",
io->ioapic_id, io->ioapic_version));
@ -290,7 +291,8 @@ smp_do_acpi_config(void)
acpi_io_apic *ioApic = (acpi_io_apic *)apic;
TRACE(("smp: found io APIC with id %u and address 0x%lx\n",
ioApic->io_apic_id, ioApic->io_apic_address));
gKernelArgs.arch_args.ioapic_phys = ioApic->io_apic_address;
if (gKernelArgs.arch_args.ioapic_phys == 0)
gKernelArgs.arch_args.ioapic_phys = ioApic->io_apic_address;
break;
}
}
@ -410,16 +412,11 @@ smp_init_other_cpus(void)
TRACE(("smp: ioapic_phys = %p\n",
(void *)gKernelArgs.arch_args.ioapic_phys));
// map in the apic & ioapic (if available)
// map in the apic
gKernelArgs.arch_args.apic = (uint32 *)mmu_map_physical_memory(
gKernelArgs.arch_args.apic_phys, B_PAGE_SIZE, kDefaultPageFlags);
if (gKernelArgs.arch_args.ioapic_phys != 0) {
gKernelArgs.arch_args.ioapic = (uint32 *)mmu_map_physical_memory(
gKernelArgs.arch_args.ioapic_phys, B_PAGE_SIZE, kDefaultPageFlags);
}
TRACE(("smp: apic = %p\n", gKernelArgs.arch_args.apic));
TRACE(("smp: ioapic = %p\n", gKernelArgs.arch_args.ioapic));
TRACE(("smp: apic (mapped) = %p\n", gKernelArgs.arch_args.apic));
// calculate how fast the apic timer is
calculate_apic_timer_conversion_factor();

View File

@ -825,10 +825,6 @@ arch_int_init_post_vm(struct kernel_args *args)
// don't end up using the io apic
apic_init(args);
// We need to map in the I/O APIC here, since we would lose the already
// wired mapping before arch_int_init_io() is called.
ioapic_map(args);
// create IDT area for the boot CPU
area_id area = create_area("idt", (void**)&sIDTs[0], B_EXACT_ADDRESS,
B_PAGE_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);

View File

@ -108,7 +108,7 @@ struct ioapic {
};
static ioapic sIOAPICs = { 0, 0, 0, 0, 0, 0, 0, -1, NULL, NULL };
static ioapic* sIOAPICs = NULL;
// #pragma mark - I/O APIC
@ -130,7 +130,7 @@ find_ioapic(int32 gsi)
if (gsi < 0)
return NULL;
struct ioapic* current = &sIOAPICs;
struct ioapic* current = sIOAPICs;
while (current != NULL) {
if (gsi >= current->global_interrupt_base
&& gsi <= current->global_interrupt_last) {
@ -371,7 +371,7 @@ acpi_enumerate_ioapics(acpi_module_info* acpi)
return B_ERROR;
}
struct ioapic* lastIOAPIC = &sIOAPICs;
struct ioapic* lastIOAPIC = sIOAPICs;
acpi_subtable_header* apicEntry
= (acpi_subtable_header*)((uint8*)madt + sizeof(acpi_table_madt));
@ -385,20 +385,6 @@ acpi_enumerate_ioapics(acpi_module_info* acpi)
"interrupt base %lu, apic-id %u\n", (uint32)info->Address,
(uint32)info->GlobalIrqBase, info->Id);
struct ioapic* alreadyMapped
= find_ioapic((int32)info->GlobalIrqBase);
if (alreadyMapped != NULL) {
// We've already mapped this IO-APIC (at boot), but we
// need to fill in the APIC ID. TODO: We might not
// actually get the IO-APIC with base 0 as first entry!
alreadyMapped->apic_id = info->Id;
alreadyMapped->global_interrupt_base = info->GlobalIrqBase;
alreadyMapped->global_interrupt_last = info->GlobalIrqBase
+ alreadyMapped->max_redirection_entry;
print_ioapic(*alreadyMapped);
break;
}
struct ioapic* ioapic
= (struct ioapic*)malloc(sizeof(struct ioapic));
if (ioapic == NULL) {
@ -407,7 +393,8 @@ acpi_enumerate_ioapics(acpi_module_info* acpi)
return B_NO_MEMORY;
}
ioapic->number = lastIOAPIC->number + 1;
ioapic->number
= lastIOAPIC != NULL ? lastIOAPIC->number + 1 : 0;
ioapic->apic_id = info->Id;
ioapic->global_interrupt_base = info->GlobalIrqBase;
ioapic->registers = NULL;
@ -422,7 +409,12 @@ acpi_enumerate_ioapics(acpi_module_info* acpi)
}
print_ioapic(*ioapic);
lastIOAPIC->next = ioapic;
if (lastIOAPIC == NULL)
sIOAPICs = ioapic;
else
lastIOAPIC->next = ioapic;
lastIOAPIC = ioapic;
break;
}
@ -524,26 +516,6 @@ ioapic_is_interrupt_available(int32 gsi)
}
void
ioapic_map(kernel_args* args)
{
if (args->arch_args.apic == NULL) {
dprintf("no local apic available\n");
return;
}
if (args->arch_args.ioapic == NULL) {
dprintf("no io-apic available, not using io-apics for interrupt "
"routing\n");
return;
}
// map in the first IO-APIC
sIOAPICs.registers = (ioapic_registers*)args->arch_args.ioapic;
ioapic_map_ioapic(sIOAPICs, args->arch_args.ioapic_phys);
}
void
ioapic_init(kernel_args* args)
{
@ -557,9 +529,15 @@ ioapic_init(kernel_args* args)
&ioapic_end_of_interrupt
};
if (sIOAPICs.register_area < 0 || sIOAPICs.registers == NULL)
if (args->arch_args.apic == NULL)
return;
if (args->arch_args.ioapic_phys == 0) {
dprintf("no io-apics available, not using io-apics for interrupt "
"routing\n");
return;
}
#if 0
if (get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, false)) {
dprintf("io-apics explicitly disabled, not using io-apics for "
@ -618,7 +596,7 @@ ioapic_init(kernel_args* args)
// use the boot CPU as the target for all interrupts
uint8 targetAPIC = args->arch_args.cpu_apic_id[0];
struct ioapic* current = &sIOAPICs;
struct ioapic* current = sIOAPICs;
while (current != NULL) {
status = ioapic_initialize_ioapic(*current, targetAPIC);
if (status != B_OK) {