xref: /haiku/src/system/kernel/arch/x86/msi.cpp (revision 37c7d5d83a2372a6971e383411d5bacbeef0ebdc)
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