xref: /haiku/src/system/kernel/arch/x86/msi.cpp (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
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 #include <arch/x86/arch_smp.h>
9 
10 #include <debug.h>
11 #include <int.h>
12 #include <lock.h>
13 
14 
15 struct MSIConfiguration {
16 	uint64*	fAddress;
17 	uint32* fData;
18 };
19 
20 static MSIConfiguration sMSIConfigurations[NUM_IO_VECTORS];
21 
22 static bool sMSISupported = false;
23 static uint32 sBootCPUAPICId = 0;
24 
25 
26 void
27 msi_init(kernel_args* args)
28 {
29 	if (!apic_available()) {
30 		dprintf("disabling msi due to missing apic\n");
31 		return;
32 	}
33 
34 	dprintf("msi support enabled\n");
35 	sMSISupported = true;
36 	sBootCPUAPICId = args->arch_args.cpu_apic_id[0];
37 }
38 
39 
40 bool
41 msi_supported()
42 {
43 	return sMSISupported;
44 }
45 
46 
47 status_t
48 msi_allocate_vectors(uint32 count, uint32 *startVector, uint64 *address,
49 	uint32 *data)
50 {
51 	if (!sMSISupported)
52 		return B_UNSUPPORTED;
53 
54 	int32 vector;
55 	status_t result = allocate_io_interrupt_vectors(count, &vector,
56 		INTERRUPT_TYPE_IRQ);
57 	if (result != B_OK)
58 		return result;
59 
60 	if (vector >= NUM_IO_VECTORS) {
61 		free_io_interrupt_vectors(count, vector);
62 		return B_NO_MEMORY;
63 	}
64 
65 	sMSIConfigurations[vector].fAddress = address;
66 	sMSIConfigurations[vector].fData = data;
67 	x86_set_irq_source(vector, IRQ_SOURCE_MSI);
68 
69 	*startVector = (uint32)vector;
70 	*address = MSI_ADDRESS_BASE | (sBootCPUAPICId << MSI_DESTINATION_ID_SHIFT)
71 		| MSI_NO_REDIRECTION | MSI_DESTINATION_MODE_PHYSICAL;
72 	*data = MSI_TRIGGER_MODE_EDGE | MSI_DELIVERY_MODE_FIXED
73 		| ((uint16)vector + ARCH_INTERRUPT_BASE);
74 
75 	dprintf("msi_allocate_vectors: allocated %" B_PRIu32 " vectors starting from %" B_PRIu32 "\n",
76 		count, *startVector);
77 	return B_OK;
78 }
79 
80 
81 void
82 msi_free_vectors(uint32 count, uint32 startVector)
83 {
84 	if (!sMSISupported) {
85 		panic("trying to free msi vectors but msi not supported\n");
86 		return;
87 	}
88 
89 	dprintf("msi_free_vectors: freeing %" B_PRIu32 " vectors starting from %" B_PRIu32 "\n", count,
90 		startVector);
91 
92 	free_io_interrupt_vectors(count, startVector);
93 }
94 
95 
96 void
97 msi_assign_interrupt_to_cpu(uint32 irq, int32 cpu)
98 {
99 	uint32 apic_id = x86_get_cpu_apic_id(cpu);
100 
101 	uint64* address = sMSIConfigurations[irq].fAddress;
102 	*address = MSI_ADDRESS_BASE | (apic_id << MSI_DESTINATION_ID_SHIFT)
103 		| MSI_NO_REDIRECTION | MSI_DESTINATION_MODE_PHYSICAL;
104 }
105 
106