1 /* 2 * Copyright 20010, 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/arch_int.h> 8 #include <arch/x86/msi.h> 9 10 #include <debug.h> 11 #include <lock.h> 12 13 14 static bool sMSISupported = false; 15 static const uint32 kVectorCount = 256 - ARCH_INTERRUPT_BASE; 16 static bool sAllocatedVectors[kVectorCount]; 17 static mutex sMSIAllocationLock = MUTEX_INITIALIZER("msi_allocation"); 18 19 20 void 21 msi_init() 22 { 23 if (!apic_available()) { 24 dprintf("disabling msi due to missing apic\n"); 25 return; 26 } 27 28 for (uint16 i = 0; i < kVectorCount; i++) 29 sAllocatedVectors[i] = false; 30 31 // the first 24 vectors are addressable with a single ioapic config 32 for (uint16 i = 0; i < 24; i++) 33 sAllocatedVectors[i] = true; 34 35 // performance testing and syscall interrupts 36 sAllocatedVectors[98 - ARCH_INTERRUPT_BASE] = true; 37 sAllocatedVectors[99 - ARCH_INTERRUPT_BASE] = true; 38 39 // the upper range is used by apic local (timer) and smp interrupts (ipi) 40 for (uint16 i = 251; i < 256; i++) 41 sAllocatedVectors[i - ARCH_INTERRUPT_BASE] = true; 42 43 dprintf("msi support enabled\n"); 44 sMSISupported = true; 45 } 46 47 48 bool 49 msi_supported() 50 { 51 return sMSISupported; 52 } 53 54 55 status_t 56 msi_allocate_vectors(uint8 count, uint8 *startVector, uint64 *address, 57 uint16 *data) 58 { 59 if (!sMSISupported) 60 return B_UNSUPPORTED; 61 62 mutex_lock(&sMSIAllocationLock); 63 64 uint8 vector = 0; 65 bool runFound = true; 66 for (uint16 i = 0; i < kVectorCount - (count - 1); i++) { 67 if (!sAllocatedVectors[i]) { 68 vector = i; 69 runFound = true; 70 for (uint16 j = 1; j < count; j++) { 71 if (sAllocatedVectors[i + j]) { 72 runFound = false; 73 i += j; 74 break; 75 } 76 } 77 78 if (runFound) 79 break; 80 } 81 } 82 83 if (!runFound) { 84 mutex_unlock(&sMSIAllocationLock); 85 dprintf("found no free vectors to allocate %u msi messages\n", count); 86 return B_NO_MEMORY; 87 } 88 89 for (uint16 i = 0; i < count; i++) 90 sAllocatedVectors[i + vector] = true; 91 92 mutex_unlock(&sMSIAllocationLock); 93 94 *startVector = vector; 95 *address = MSI_ADDRESS_BASE | (0 << MSI_DESTINATION_ID_SHIFT) 96 | MSI_NO_REDIRECTION | MSI_DESTINATION_MODE_PHYSICAL; 97 *data = MSI_TRIGGER_MODE_EDGE | MSI_DELIVERY_MODE_FIXED 98 | (vector + ARCH_INTERRUPT_BASE); 99 100 dprintf("msi_allocate_vectors: allocated %u vectors starting from %u\n", 101 count, vector); 102 return B_OK; 103 } 104 105 106 void 107 msi_free_vectors(uint8 count, uint8 startVector) 108 { 109 if (!sMSISupported) { 110 panic("trying to free msi vectors but msi not supported\n"); 111 return; 112 } 113 114 if ((uint32)startVector + count > kVectorCount) { 115 panic("invalid start vector %u or count %u supplied to " 116 "msi_free_vectors\n", startVector, count); 117 } 118 119 dprintf("msi_free_vectors: freeing %u vectors starting from %u\n", count, 120 startVector); 121 122 mutex_lock(&sMSIAllocationLock); 123 for (uint16 i = 0; i < count; i++) { 124 if (!sAllocatedVectors[i + startVector]) 125 panic("msi vector %u was not allocated\n", i + startVector); 126 127 sAllocatedVectors[i + startVector] = false; 128 } 129 130 mutex_unlock(&sMSIAllocationLock); 131 } 132