1*dc14d97bSMichael Lotz /* 2*dc14d97bSMichael Lotz * Copyright 2008-2011, Michael Lotz, mmlr@mlotz.ch. 3*dc14d97bSMichael Lotz * Distributed under the terms of the MIT License. 4*dc14d97bSMichael Lotz */ 5*dc14d97bSMichael Lotz 6*dc14d97bSMichael Lotz #include <arch/x86/ioapic.h> 7*dc14d97bSMichael Lotz 8*dc14d97bSMichael Lotz #include <int.h> 9*dc14d97bSMichael Lotz #include <vm/vm.h> 10*dc14d97bSMichael Lotz 11*dc14d97bSMichael Lotz #include "irq_routing_table.h" 12*dc14d97bSMichael Lotz 13*dc14d97bSMichael Lotz #include <ACPI.h> 14*dc14d97bSMichael Lotz #include <AutoDeleter.h> 15*dc14d97bSMichael Lotz #include <safemode.h> 16*dc14d97bSMichael Lotz #include <string.h> 17*dc14d97bSMichael Lotz #include <stdio.h> 18*dc14d97bSMichael Lotz 19*dc14d97bSMichael Lotz #include <arch/x86/apic.h> 20*dc14d97bSMichael Lotz #include <arch/x86/arch_int.h> 21*dc14d97bSMichael Lotz #include <arch/x86/pic.h> 22*dc14d97bSMichael Lotz 23*dc14d97bSMichael Lotz 24*dc14d97bSMichael Lotz //#define TRACE_IOAPIC 25*dc14d97bSMichael Lotz #ifdef TRACE_IOAPIC 26*dc14d97bSMichael Lotz # define TRACE(x) dprintf x 27*dc14d97bSMichael Lotz #else 28*dc14d97bSMichael Lotz # define TRACE(x) ; 29*dc14d97bSMichael Lotz #endif 30*dc14d97bSMichael Lotz 31*dc14d97bSMichael Lotz 32*dc14d97bSMichael Lotz // ACPI interrupt models 33*dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_PIC 0 34*dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_APIC 1 35*dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_SAPIC 2 36*dc14d97bSMichael Lotz 37*dc14d97bSMichael Lotz 38*dc14d97bSMichael Lotz // Definitions for a 82093AA IO APIC controller 39*dc14d97bSMichael Lotz #define IO_APIC_IDENTIFICATION 0x00 40*dc14d97bSMichael Lotz #define IO_APIC_VERSION 0x01 41*dc14d97bSMichael Lotz #define IO_APIC_ARBITRATION 0x02 42*dc14d97bSMichael Lotz #define IO_APIC_REDIRECTION_TABLE 0x10 // entry = base + 2 * index 43*dc14d97bSMichael Lotz 44*dc14d97bSMichael Lotz // Fields for the version register 45*dc14d97bSMichael Lotz #define IO_APIC_VERSION_SHIFT 0 46*dc14d97bSMichael Lotz #define IO_APIC_VERSION_MASK 0xff 47*dc14d97bSMichael Lotz #define IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT 16 48*dc14d97bSMichael Lotz #define IO_APIC_MAX_REDIRECTION_ENTRY_MASK 0xff 49*dc14d97bSMichael Lotz 50*dc14d97bSMichael Lotz // Fields of each redirection table entry 51*dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_FIELD_SHIFT 56 52*dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_FIELD_MASK 0x0f 53*dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_MASK_SHIFT 16 54*dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_MASKED 1 55*dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_UNMASKED 0 56*dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_SHIFT 15 57*dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_EDGE 0 58*dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_LEVEL 1 59*dc14d97bSMichael Lotz #define IO_APIC_REMOTE_IRR_SHIFT 14 60*dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_SHIFT 13 61*dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_HIGH_ACTIVE 0 62*dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_LOW_ACTIVE 1 63*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_SHIFT 12 64*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_IDLE 0 65*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_PENDING 1 66*dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_SHIFT 11 67*dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_PHYSICAL 0 68*dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_LOGICAL 1 69*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_SHIFT 8 70*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_MASK 0x07 71*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_FIXED 0 72*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_LOWEST_PRIO 1 73*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_SMI 2 74*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_NMI 4 75*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_INIT 5 76*dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_EXT_INT 7 77*dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_VECTOR_SHIFT 0 78*dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_VECTOR_MASK 0xff 79*dc14d97bSMichael Lotz 80*dc14d97bSMichael Lotz 81*dc14d97bSMichael Lotz typedef struct ioapic_s { 82*dc14d97bSMichael Lotz volatile uint32 io_register_select; 83*dc14d97bSMichael Lotz uint32 reserved[3]; 84*dc14d97bSMichael Lotz volatile uint32 io_window_register; 85*dc14d97bSMichael Lotz } ioapic; 86*dc14d97bSMichael Lotz 87*dc14d97bSMichael Lotz static ioapic *sIOAPIC = NULL; 88*dc14d97bSMichael Lotz static uint32 sIOAPICMaxRedirectionEntry = 23; 89*dc14d97bSMichael Lotz 90*dc14d97bSMichael Lotz static uint64 sLevelTriggeredInterrupts = 0; 91*dc14d97bSMichael Lotz // binary mask: 1 level, 0 edge 92*dc14d97bSMichael Lotz 93*dc14d97bSMichael Lotz 94*dc14d97bSMichael Lotz // #pragma mark - I/O APIC 95*dc14d97bSMichael Lotz 96*dc14d97bSMichael Lotz 97*dc14d97bSMichael Lotz static inline uint32 98*dc14d97bSMichael Lotz ioapic_read_32(uint8 registerSelect) 99*dc14d97bSMichael Lotz { 100*dc14d97bSMichael Lotz sIOAPIC->io_register_select = registerSelect; 101*dc14d97bSMichael Lotz return sIOAPIC->io_window_register; 102*dc14d97bSMichael Lotz } 103*dc14d97bSMichael Lotz 104*dc14d97bSMichael Lotz 105*dc14d97bSMichael Lotz static inline void 106*dc14d97bSMichael Lotz ioapic_write_32(uint8 registerSelect, uint32 value) 107*dc14d97bSMichael Lotz { 108*dc14d97bSMichael Lotz sIOAPIC->io_register_select = registerSelect; 109*dc14d97bSMichael Lotz sIOAPIC->io_window_register = value; 110*dc14d97bSMichael Lotz } 111*dc14d97bSMichael Lotz 112*dc14d97bSMichael Lotz 113*dc14d97bSMichael Lotz static inline uint64 114*dc14d97bSMichael Lotz ioapic_read_64(uint8 registerSelect) 115*dc14d97bSMichael Lotz { 116*dc14d97bSMichael Lotz sIOAPIC->io_register_select = registerSelect + 1; 117*dc14d97bSMichael Lotz uint64 result = sIOAPIC->io_window_register; 118*dc14d97bSMichael Lotz result <<= 32; 119*dc14d97bSMichael Lotz sIOAPIC->io_register_select = registerSelect; 120*dc14d97bSMichael Lotz result |= sIOAPIC->io_window_register; 121*dc14d97bSMichael Lotz return result; 122*dc14d97bSMichael Lotz } 123*dc14d97bSMichael Lotz 124*dc14d97bSMichael Lotz 125*dc14d97bSMichael Lotz static inline void 126*dc14d97bSMichael Lotz ioapic_write_64(uint8 registerSelect, uint64 value) 127*dc14d97bSMichael Lotz { 128*dc14d97bSMichael Lotz sIOAPIC->io_register_select = registerSelect; 129*dc14d97bSMichael Lotz sIOAPIC->io_window_register = (uint32)value; 130*dc14d97bSMichael Lotz sIOAPIC->io_register_select = registerSelect + 1; 131*dc14d97bSMichael Lotz sIOAPIC->io_window_register = (uint32)(value >> 32); 132*dc14d97bSMichael Lotz } 133*dc14d97bSMichael Lotz 134*dc14d97bSMichael Lotz 135*dc14d97bSMichael Lotz static bool 136*dc14d97bSMichael Lotz ioapic_is_spurious_interrupt(int32 num) 137*dc14d97bSMichael Lotz { 138*dc14d97bSMichael Lotz // the spurious interrupt vector is initialized to the max value in smp 139*dc14d97bSMichael Lotz return num == 0xff - ARCH_INTERRUPT_BASE; 140*dc14d97bSMichael Lotz } 141*dc14d97bSMichael Lotz 142*dc14d97bSMichael Lotz 143*dc14d97bSMichael Lotz static bool 144*dc14d97bSMichael Lotz ioapic_is_level_triggered_interrupt(int32 pin) 145*dc14d97bSMichael Lotz { 146*dc14d97bSMichael Lotz if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) 147*dc14d97bSMichael Lotz return false; 148*dc14d97bSMichael Lotz 149*dc14d97bSMichael Lotz return (sLevelTriggeredInterrupts & (1 << pin)) != 0; 150*dc14d97bSMichael Lotz } 151*dc14d97bSMichael Lotz 152*dc14d97bSMichael Lotz 153*dc14d97bSMichael Lotz static bool 154*dc14d97bSMichael Lotz ioapic_end_of_interrupt(int32 num) 155*dc14d97bSMichael Lotz { 156*dc14d97bSMichael Lotz apic_end_of_interrupt(); 157*dc14d97bSMichael Lotz return true; 158*dc14d97bSMichael Lotz } 159*dc14d97bSMichael Lotz 160*dc14d97bSMichael Lotz 161*dc14d97bSMichael Lotz static void 162*dc14d97bSMichael Lotz ioapic_enable_io_interrupt(int32 pin) 163*dc14d97bSMichael Lotz { 164*dc14d97bSMichael Lotz if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) 165*dc14d97bSMichael Lotz return; 166*dc14d97bSMichael Lotz 167*dc14d97bSMichael Lotz TRACE(("ioapic_enable_io_interrupt: pin %ld\n", pin)); 168*dc14d97bSMichael Lotz 169*dc14d97bSMichael Lotz uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); 170*dc14d97bSMichael Lotz entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT); 171*dc14d97bSMichael Lotz entry |= IO_APIC_INTERRUPT_UNMASKED << IO_APIC_INTERRUPT_MASK_SHIFT; 172*dc14d97bSMichael Lotz ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); 173*dc14d97bSMichael Lotz } 174*dc14d97bSMichael Lotz 175*dc14d97bSMichael Lotz 176*dc14d97bSMichael Lotz static void 177*dc14d97bSMichael Lotz ioapic_disable_io_interrupt(int32 pin) 178*dc14d97bSMichael Lotz { 179*dc14d97bSMichael Lotz if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) 180*dc14d97bSMichael Lotz return; 181*dc14d97bSMichael Lotz 182*dc14d97bSMichael Lotz TRACE(("ioapic_disable_io_interrupt: pin %ld\n", pin)); 183*dc14d97bSMichael Lotz 184*dc14d97bSMichael Lotz uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); 185*dc14d97bSMichael Lotz entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT); 186*dc14d97bSMichael Lotz entry |= IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT; 187*dc14d97bSMichael Lotz ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); 188*dc14d97bSMichael Lotz } 189*dc14d97bSMichael Lotz 190*dc14d97bSMichael Lotz 191*dc14d97bSMichael Lotz static void 192*dc14d97bSMichael Lotz ioapic_configure_io_interrupt(int32 pin, uint32 config) 193*dc14d97bSMichael Lotz { 194*dc14d97bSMichael Lotz if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) 195*dc14d97bSMichael Lotz return; 196*dc14d97bSMichael Lotz 197*dc14d97bSMichael Lotz TRACE(("ioapic_configure_io_interrupt: pin %ld; config 0x%08lx\n", pin, 198*dc14d97bSMichael Lotz config)); 199*dc14d97bSMichael Lotz 200*dc14d97bSMichael Lotz uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); 201*dc14d97bSMichael Lotz entry &= ~((1 << IO_APIC_TRIGGER_MODE_SHIFT) 202*dc14d97bSMichael Lotz | (1 << IO_APIC_PIN_POLARITY_SHIFT) 203*dc14d97bSMichael Lotz | (IO_APIC_INTERRUPT_VECTOR_MASK << IO_APIC_INTERRUPT_VECTOR_SHIFT)); 204*dc14d97bSMichael Lotz 205*dc14d97bSMichael Lotz if (config & B_LEVEL_TRIGGERED) { 206*dc14d97bSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT); 207*dc14d97bSMichael Lotz sLevelTriggeredInterrupts |= (1 << pin); 208*dc14d97bSMichael Lotz } else { 209*dc14d97bSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT); 210*dc14d97bSMichael Lotz sLevelTriggeredInterrupts &= ~(1 << pin); 211*dc14d97bSMichael Lotz } 212*dc14d97bSMichael Lotz 213*dc14d97bSMichael Lotz if (config & B_LOW_ACTIVE_POLARITY) 214*dc14d97bSMichael Lotz entry |= (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT); 215*dc14d97bSMichael Lotz else 216*dc14d97bSMichael Lotz entry |= (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT); 217*dc14d97bSMichael Lotz 218*dc14d97bSMichael Lotz entry |= (pin + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT; 219*dc14d97bSMichael Lotz ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); 220*dc14d97bSMichael Lotz } 221*dc14d97bSMichael Lotz 222*dc14d97bSMichael Lotz 223*dc14d97bSMichael Lotz static status_t 224*dc14d97bSMichael Lotz acpi_set_interrupt_model(acpi_module_info* acpiModule, uint32 interruptModel) 225*dc14d97bSMichael Lotz { 226*dc14d97bSMichael Lotz acpi_object_type model; 227*dc14d97bSMichael Lotz model.object_type = ACPI_TYPE_INTEGER; 228*dc14d97bSMichael Lotz model.data.integer = interruptModel; 229*dc14d97bSMichael Lotz 230*dc14d97bSMichael Lotz acpi_objects parameter; 231*dc14d97bSMichael Lotz parameter.count = 1; 232*dc14d97bSMichael Lotz parameter.pointer = &model; 233*dc14d97bSMichael Lotz 234*dc14d97bSMichael Lotz dprintf("setting ACPI interrupt model to %s\n", 235*dc14d97bSMichael Lotz interruptModel == 0 ? "PIC" 236*dc14d97bSMichael Lotz : (interruptModel == 1 ? "APIC" 237*dc14d97bSMichael Lotz : (interruptModel == 2 ? "SAPIC" 238*dc14d97bSMichael Lotz : "unknown"))); 239*dc14d97bSMichael Lotz 240*dc14d97bSMichael Lotz return acpiModule->evaluate_method(NULL, "\\_PIC", ¶meter, NULL); 241*dc14d97bSMichael Lotz } 242*dc14d97bSMichael Lotz 243*dc14d97bSMichael Lotz 244*dc14d97bSMichael Lotz void 245*dc14d97bSMichael Lotz ioapic_map(kernel_args* args) 246*dc14d97bSMichael Lotz { 247*dc14d97bSMichael Lotz if (args->arch_args.apic == NULL) { 248*dc14d97bSMichael Lotz dprintf("no local apic available\n"); 249*dc14d97bSMichael Lotz return; 250*dc14d97bSMichael Lotz } 251*dc14d97bSMichael Lotz 252*dc14d97bSMichael Lotz if (args->arch_args.ioapic == NULL) { 253*dc14d97bSMichael Lotz dprintf("no ioapic available, not using ioapics for interrupt routing\n"); 254*dc14d97bSMichael Lotz return; 255*dc14d97bSMichael Lotz } 256*dc14d97bSMichael Lotz 257*dc14d97bSMichael Lotz // map in the (first) IO-APIC 258*dc14d97bSMichael Lotz sIOAPIC = (ioapic *)args->arch_args.ioapic; 259*dc14d97bSMichael Lotz if (vm_map_physical_memory(B_SYSTEM_TEAM, "ioapic", (void**)&sIOAPIC, 260*dc14d97bSMichael Lotz B_EXACT_ADDRESS, B_PAGE_SIZE, 261*dc14d97bSMichael Lotz B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 262*dc14d97bSMichael Lotz args->arch_args.ioapic_phys, true) < 0) { 263*dc14d97bSMichael Lotz panic("mapping the ioapic failed"); 264*dc14d97bSMichael Lotz return; 265*dc14d97bSMichael Lotz } 266*dc14d97bSMichael Lotz } 267*dc14d97bSMichael Lotz 268*dc14d97bSMichael Lotz 269*dc14d97bSMichael Lotz void 270*dc14d97bSMichael Lotz ioapic_init(kernel_args* args) 271*dc14d97bSMichael Lotz { 272*dc14d97bSMichael Lotz static const interrupt_controller ioapicController = { 273*dc14d97bSMichael Lotz "82093AA IOAPIC", 274*dc14d97bSMichael Lotz &ioapic_enable_io_interrupt, 275*dc14d97bSMichael Lotz &ioapic_disable_io_interrupt, 276*dc14d97bSMichael Lotz &ioapic_configure_io_interrupt, 277*dc14d97bSMichael Lotz &ioapic_is_spurious_interrupt, 278*dc14d97bSMichael Lotz &ioapic_is_level_triggered_interrupt, 279*dc14d97bSMichael Lotz &ioapic_end_of_interrupt 280*dc14d97bSMichael Lotz }; 281*dc14d97bSMichael Lotz 282*dc14d97bSMichael Lotz if (sIOAPIC == NULL) 283*dc14d97bSMichael Lotz return; 284*dc14d97bSMichael Lotz 285*dc14d97bSMichael Lotz #if 0 286*dc14d97bSMichael Lotz if (get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, false)) { 287*dc14d97bSMichael Lotz dprintf("ioapic explicitly disabled, not using ioapics for interrupt " 288*dc14d97bSMichael Lotz "routing\n"); 289*dc14d97bSMichael Lotz return; 290*dc14d97bSMichael Lotz } 291*dc14d97bSMichael Lotz #else 292*dc14d97bSMichael Lotz // TODO: This can be removed once IO-APIC code is broadly tested 293*dc14d97bSMichael Lotz if (!get_safemode_boolean(B_SAFEMODE_ENABLE_IOAPIC, false)) { 294*dc14d97bSMichael Lotz dprintf("ioapic not enabled, not using ioapics for interrupt " 295*dc14d97bSMichael Lotz "routing\n"); 296*dc14d97bSMichael Lotz return; 297*dc14d97bSMichael Lotz } 298*dc14d97bSMichael Lotz #endif 299*dc14d97bSMichael Lotz 300*dc14d97bSMichael Lotz uint32 version = ioapic_read_32(IO_APIC_VERSION); 301*dc14d97bSMichael Lotz if (version == 0xffffffff) { 302*dc14d97bSMichael Lotz dprintf("ioapic seems inaccessible, not using it\n"); 303*dc14d97bSMichael Lotz return; 304*dc14d97bSMichael Lotz } 305*dc14d97bSMichael Lotz 306*dc14d97bSMichael Lotz // load acpi module 307*dc14d97bSMichael Lotz status_t status; 308*dc14d97bSMichael Lotz acpi_module_info* acpiModule; 309*dc14d97bSMichael Lotz status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule); 310*dc14d97bSMichael Lotz if (status != B_OK) { 311*dc14d97bSMichael Lotz dprintf("acpi module not available, not configuring ioapic\n"); 312*dc14d97bSMichael Lotz return; 313*dc14d97bSMichael Lotz } 314*dc14d97bSMichael Lotz BPrivate::CObjectDeleter<const char, status_t> 315*dc14d97bSMichael Lotz acpiModulePutter(B_ACPI_MODULE_NAME, put_module); 316*dc14d97bSMichael Lotz 317*dc14d97bSMichael Lotz // switch to the APIC interrupt model before retrieving the irq routing 318*dc14d97bSMichael Lotz // table as it will return different settings depending on the model 319*dc14d97bSMichael Lotz status = acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_APIC); 320*dc14d97bSMichael Lotz if (status != B_OK) { 321*dc14d97bSMichael Lotz dprintf("failed to put ACPI into APIC interrupt model, ignoring\n"); 322*dc14d97bSMichael Lotz // don't abort, as the _PIC method is optional and as long as there 323*dc14d97bSMichael Lotz // aren't different routings based on it this is non-fatal 324*dc14d97bSMichael Lotz } 325*dc14d97bSMichael Lotz 326*dc14d97bSMichael Lotz sLevelTriggeredInterrupts = 0; 327*dc14d97bSMichael Lotz sIOAPICMaxRedirectionEntry 328*dc14d97bSMichael Lotz = ((version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT) 329*dc14d97bSMichael Lotz & IO_APIC_MAX_REDIRECTION_ENTRY_MASK); 330*dc14d97bSMichael Lotz 331*dc14d97bSMichael Lotz TRACE(("ioapic has %lu entries\n", sIOAPICMaxRedirectionEntry + 1)); 332*dc14d97bSMichael Lotz 333*dc14d97bSMichael Lotz IRQRoutingTable table; 334*dc14d97bSMichael Lotz status = prepare_irq_routing(acpiModule, table, 335*dc14d97bSMichael Lotz sIOAPICMaxRedirectionEntry + 1); 336*dc14d97bSMichael Lotz if (status != B_OK) { 337*dc14d97bSMichael Lotz dprintf("IRQ routing preparation failed, not configuring ioapic.\n"); 338*dc14d97bSMichael Lotz acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); 339*dc14d97bSMichael Lotz // revert to PIC interrupt model just in case 340*dc14d97bSMichael Lotz return; 341*dc14d97bSMichael Lotz } 342*dc14d97bSMichael Lotz 343*dc14d97bSMichael Lotz print_irq_routing_table(table); 344*dc14d97bSMichael Lotz 345*dc14d97bSMichael Lotz status = enable_irq_routing(acpiModule, table); 346*dc14d97bSMichael Lotz if (status != B_OK) { 347*dc14d97bSMichael Lotz panic("failed to enable IRQ routing"); 348*dc14d97bSMichael Lotz // if it failed early on it might still work in PIC mode 349*dc14d97bSMichael Lotz acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); 350*dc14d97bSMichael Lotz return; 351*dc14d97bSMichael Lotz } 352*dc14d97bSMichael Lotz 353*dc14d97bSMichael Lotz // use the boot CPU as the target for all interrupts 354*dc14d97bSMichael Lotz uint64 targetAPIC = args->arch_args.cpu_apic_id[0]; 355*dc14d97bSMichael Lotz 356*dc14d97bSMichael Lotz // program the interrupt vectors of the ioapic 357*dc14d97bSMichael Lotz for (uint32 i = 0; i <= sIOAPICMaxRedirectionEntry; i++) { 358*dc14d97bSMichael Lotz // initialize everything to deliver to the boot CPU in physical mode 359*dc14d97bSMichael Lotz // and masked until explicitly enabled through enable_io_interrupt() 360*dc14d97bSMichael Lotz uint64 entry = (targetAPIC << IO_APIC_DESTINATION_FIELD_SHIFT) 361*dc14d97bSMichael Lotz | (IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT) 362*dc14d97bSMichael Lotz | (IO_APIC_DESTINATION_MODE_PHYSICAL << IO_APIC_DESTINATION_MODE_SHIFT) 363*dc14d97bSMichael Lotz | ((i + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT); 364*dc14d97bSMichael Lotz 365*dc14d97bSMichael Lotz if (i == 0) { 366*dc14d97bSMichael Lotz // make redirection entry 0 into an external interrupt 367*dc14d97bSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT) 368*dc14d97bSMichael Lotz | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) 369*dc14d97bSMichael Lotz | (IO_APIC_DELIVERY_MODE_EXT_INT << IO_APIC_DELIVERY_MODE_SHIFT); 370*dc14d97bSMichael Lotz } else if (i < 16) { 371*dc14d97bSMichael Lotz // make 1-15 ISA interrupts 372*dc14d97bSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT) 373*dc14d97bSMichael Lotz | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) 374*dc14d97bSMichael Lotz | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT); 375*dc14d97bSMichael Lotz } else { 376*dc14d97bSMichael Lotz // and the rest are PCI interrupts 377*dc14d97bSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT) 378*dc14d97bSMichael Lotz | (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) 379*dc14d97bSMichael Lotz | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT); 380*dc14d97bSMichael Lotz sLevelTriggeredInterrupts |= (1 << i); 381*dc14d97bSMichael Lotz } 382*dc14d97bSMichael Lotz 383*dc14d97bSMichael Lotz ioapic_write_64(IO_APIC_REDIRECTION_TABLE + 2 * i, entry); 384*dc14d97bSMichael Lotz } 385*dc14d97bSMichael Lotz 386*dc14d97bSMichael Lotz // configure io apic interrupts from PCI routing table 387*dc14d97bSMichael Lotz for (int i = 0; i < table.Count(); i++) { 388*dc14d97bSMichael Lotz irq_routing_entry& entry = table.ElementAt(i); 389*dc14d97bSMichael Lotz ioapic_configure_io_interrupt(entry.irq, 390*dc14d97bSMichael Lotz entry.polarity | entry.trigger_mode); 391*dc14d97bSMichael Lotz } 392*dc14d97bSMichael Lotz 393*dc14d97bSMichael Lotz // disable the legacy PIC 394*dc14d97bSMichael Lotz pic_disable(); 395*dc14d97bSMichael Lotz 396*dc14d97bSMichael Lotz // prefer the ioapic over the normal pic 397*dc14d97bSMichael Lotz dprintf("using ioapic for interrupt routing\n"); 398*dc14d97bSMichael Lotz arch_int_set_interrupt_controller(ioapicController); 399*dc14d97bSMichael Lotz } 400