xref: /haiku/src/add-ons/kernel/busses/pci/designware/MsiInterruptCtrlDW.cpp (revision dd2a1e350b303b855a50fd64e6cb55618be1ae6a)
1 /*
2  * Copyright 2022, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "DWPCIController.h"
8 
9 #include <int.h>
10 
11 
12 status_t
13 MsiInterruptCtrlDW::Init(PciDbiRegs volatile* dbiRegs, int32 msiIrq)
14 {
15 	dprintf("MsiInterruptCtrlDW::Init()\n");
16 	dprintf("  msiIrq: %" B_PRId32 "\n", msiIrq);
17 
18 	fDbiRegs = dbiRegs;
19 
20 	physical_entry pe;
21 	status_t result = get_memory_map(&fMsiData, sizeof(fMsiData), &pe, 1);
22 	if (result != B_OK) {
23 		dprintf("  unable to get MSI Memory map!\n");
24 		return result;
25 	}
26 
27 	fMsiPhysAddr = pe.address;
28 	dprintf("  fMsiPhysAddr: %#" B_PRIxADDR "\n", fMsiPhysAddr);
29 	fDbiRegs->msiAddrLo = (uint32)fMsiPhysAddr;
30 	fDbiRegs->msiAddrHi = (uint32)(fMsiPhysAddr >> 32);
31 
32 	fDbiRegs->msiIntr[0].enable = 0xffffffff;
33 	fDbiRegs->msiIntr[0].mask = 0xffffffff;
34 
35 	result = install_io_interrupt_handler(msiIrq, InterruptReceived, this, 0);
36 	if (result != B_OK) {
37 		dprintf("  unable to attach MSI irq handler!\n");
38 		return result;
39 	}
40 	result = allocate_io_interrupt_vectors(32, &fMsiStartIrq, INTERRUPT_TYPE_IRQ);
41 
42 	if (result != B_OK) {
43 		dprintf("  unable to attach MSI irq handler!\n");
44 		return result;
45 	}
46 
47 	msi_set_interface(static_cast<MSIInterface*>(this));
48 
49 	dprintf("  fMsiStartIrq: %" B_PRId32 "\n", fMsiStartIrq);
50 
51 	return B_OK;
52 }
53 
54 
55 status_t
56 MsiInterruptCtrlDW::AllocateVectors(uint32 count, uint32& startVector, uint64& address,
57 	uint32& data)
58 {
59 	if (count != 1)
60 		return B_ERROR;
61 
62 	for (int i = 0; i < 32; i++) {
63 		if (((1 << i) & fAllocatedMsiIrqs[0]) == 0) {
64 			fAllocatedMsiIrqs[0] |= (1 << i);
65 			fDbiRegs->msiIntr[0].mask &= ~(1 << i);
66 
67 			startVector = fMsiStartIrq + i;
68 			address = fMsiPhysAddr;
69 			data = i;
70 			return B_OK;
71 		}
72 	}
73 	return B_ERROR;
74 }
75 
76 
77 void
78 MsiInterruptCtrlDW::FreeVectors(uint32 count, uint32 startVector)
79 {
80 	int32 irq = (int32)startVector - fMsiStartIrq;
81 	while (count > 0) {
82 		if (irq >= 0 && irq < 32 && ((1 << irq) & fAllocatedMsiIrqs[0]) != 0) {
83 			fDbiRegs->msiIntr[0].mask |= (1 << (uint32)irq);
84 			fAllocatedMsiIrqs[0] &= ~(1 << (uint32)irq);
85 		}
86 		irq++;
87 		count--;
88 	}
89 }
90 
91 
92 int32
93 MsiInterruptCtrlDW::InterruptReceived(void* arg)
94 {
95 	return static_cast<MsiInterruptCtrlDW*>(arg)->InterruptReceivedInt();
96 }
97 
98 
99 int32
100 MsiInterruptCtrlDW::InterruptReceivedInt()
101 {
102 //	dprintf("MsiInterruptCtrlDW::InterruptReceivedInt()\n");
103 	uint32 status = fDbiRegs->msiIntr[0].status;
104 	for (int i = 0; i < 32; i++) {
105 		if (((1 << i) & status) != 0) {
106 //			dprintf("MSI IRQ: %d (%ld)\n", i, fStartMsiIrq + i);
107 			int_io_interrupt_handler(fMsiStartIrq + i, false);
108 			fDbiRegs->msiIntr[0].status = (1 << i);
109 		}
110 	}
111 	return B_HANDLED_INTERRUPT;
112 }
113