xref: /haiku/src/add-ons/kernel/busses/pci/designware/MsiInterruptCtrlDW.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
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: %ld\n", fMsiStartIrq);
50 
51 	return B_OK;
52 }
53 
54 
55 status_t
56 MsiInterruptCtrlDW::AllocateVectors(uint8 count, uint8& startVector, uint64& address, uint16& data)
57 {
58 	if (count != 1)
59 		return B_ERROR;
60 
61 	for (int i = 0; i < 32; i++) {
62 		if (((1 << i) & fAllocatedMsiIrqs[0]) == 0) {
63 			fAllocatedMsiIrqs[0] |= (1 << i);
64 			fDbiRegs->msiIntr[0].mask &= ~(1 << i);
65 
66 			startVector = fMsiStartIrq + i;
67 			address = fMsiPhysAddr;
68 			data = i;
69 			return B_OK;
70 		}
71 	}
72 	return B_ERROR;
73 }
74 
75 
76 void
77 MsiInterruptCtrlDW::FreeVectors(uint8 count, uint8 startVector)
78 {
79 	int32 irq = (int32)startVector - fMsiStartIrq;
80 	while (count > 0) {
81 		if (irq >= 0 && irq < 32 && ((1 << irq) & fAllocatedMsiIrqs[0]) != 0) {
82 			fDbiRegs->msiIntr[0].mask |= (1 << (uint32)irq);
83 			fAllocatedMsiIrqs[0] &= ~(1 << (uint32)irq);
84 		}
85 		irq++;
86 		count--;
87 	}
88 }
89 
90 
91 int32
92 MsiInterruptCtrlDW::InterruptReceived(void* arg)
93 {
94 	return static_cast<MsiInterruptCtrlDW*>(arg)->InterruptReceivedInt();
95 }
96 
97 
98 int32
99 MsiInterruptCtrlDW::InterruptReceivedInt()
100 {
101 //	dprintf("MsiInterruptCtrlDW::InterruptReceivedInt()\n");
102 	uint32 status = fDbiRegs->msiIntr[0].status;
103 	for (int i = 0; i < 32; i++) {
104 		if (((1 << i) & status) != 0) {
105 //			dprintf("MSI IRQ: %d (%ld)\n", i, fStartMsiIrq + i);
106 			int_io_interrupt_handler(fMsiStartIrq + i, false);
107 			fDbiRegs->msiIntr[0].status = (1 << i);
108 		}
109 	}
110 	return B_HANDLED_INTERRUPT;
111 }
112