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