1 /* 2 * Copyright 2010-2011, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 */ 5 6 #include <arch/x86/apic.h> 7 #include <arch/x86/msi.h> 8 9 #include <debug.h> 10 #include <int.h> 11 #include <lock.h> 12 13 14 static bool sMSISupported = false; 15 static uint32 sBootCPUAPICId = 0; 16 17 18 void 19 msi_init(kernel_args* args) 20 { 21 if (!apic_available()) { 22 dprintf("disabling msi due to missing apic\n"); 23 return; 24 } 25 26 dprintf("msi support enabled\n"); 27 sMSISupported = true; 28 sBootCPUAPICId = args->arch_args.cpu_apic_id[0]; 29 } 30 31 32 bool 33 msi_supported() 34 { 35 return sMSISupported; 36 } 37 38 39 status_t 40 msi_allocate_vectors(uint8 count, uint8 *startVector, uint64 *address, 41 uint16 *data) 42 { 43 if (!sMSISupported) 44 return B_UNSUPPORTED; 45 46 long vector; 47 status_t result = allocate_io_interrupt_vectors(count, &vector); 48 if (result != B_OK) 49 return result; 50 51 if (vector >= 256) { 52 free_io_interrupt_vectors(count, vector); 53 return B_NO_MEMORY; 54 } 55 56 *startVector = (uint8)vector; 57 *address = MSI_ADDRESS_BASE | (sBootCPUAPICId << MSI_DESTINATION_ID_SHIFT) 58 | MSI_NO_REDIRECTION | MSI_DESTINATION_MODE_PHYSICAL; 59 *data = MSI_TRIGGER_MODE_EDGE | MSI_DELIVERY_MODE_FIXED 60 | ((uint16)vector + ARCH_INTERRUPT_BASE); 61 62 dprintf("msi_allocate_vectors: allocated %u vectors starting from %u\n", 63 count, *startVector); 64 return B_OK; 65 } 66 67 68 void 69 msi_free_vectors(uint8 count, uint8 startVector) 70 { 71 if (!sMSISupported) { 72 panic("trying to free msi vectors but msi not supported\n"); 73 return; 74 } 75 76 dprintf("msi_free_vectors: freeing %u vectors starting from %u\n", count, 77 startVector); 78 79 free_io_interrupt_vectors(count, startVector); 80 } 81