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
12status_t
13MsiInterruptCtrlDW::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
55status_t
56MsiInterruptCtrlDW::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
77void
78MsiInterruptCtrlDW::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
92int32
93MsiInterruptCtrlDW::InterruptReceived(void* arg)
94{
95	return static_cast<MsiInterruptCtrlDW*>(arg)->InterruptReceivedInt();
96}
97
98
99int32
100MsiInterruptCtrlDW::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