xref: /haiku/src/add-ons/kernel/busses/pci/ecam/ECAMPCIControllerFDT.cpp (revision 958b83c3ed45e0e599e7dc0bc7f5841d4d9c03e5)
1 /*
2  * Copyright 2022, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "ECAMPCIController.h"
8 
9 #include <AutoDeleterDrivers.h>
10 
11 #include <string.h>
12 
13 
14 status_t
15 ECAMPCIControllerFDT::ReadResourceInfo()
16 {
17 	DeviceNodePutter<&gDeviceManager> fdtNode(gDeviceManager->get_parent_node(fNode));
18 
19 	fdt_device_module_info *fdtModule;
20 	fdt_device* fdtDev;
21 	CHECK_RET(gDeviceManager->get_driver(fdtNode.Get(),
22 		(driver_module_info**)&fdtModule, (void**)&fdtDev));
23 
24 	const void* prop;
25 	int propLen;
26 
27 	prop = fdtModule->get_prop(fdtDev, "bus-range", &propLen);
28 	if (prop != NULL && propLen == 8) {
29 		uint32 busBeg = B_BENDIAN_TO_HOST_INT32(*((uint32*)prop + 0));
30 		uint32 busEnd = B_BENDIAN_TO_HOST_INT32(*((uint32*)prop + 1));
31 		dprintf("  bus-range: %" B_PRIu32 " - %" B_PRIu32 "\n", busBeg, busEnd);
32 	}
33 
34 	prop = fdtModule->get_prop(fdtDev, "ranges", &propLen);
35 	if (prop == NULL) {
36 		dprintf("  \"ranges\" property not found");
37 		return B_ERROR;
38 	}
39 	dprintf("  ranges:\n");
40 	for (uint32_t *it = (uint32_t*)prop; (uint8_t*)it - (uint8_t*)prop < propLen; it += 7) {
41 		dprintf("    ");
42 		uint32_t type      = B_BENDIAN_TO_HOST_INT32(*(it + 0));
43 		uint64_t childAdr  = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 1));
44 		uint64_t parentAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3));
45 		uint64_t len       = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5));
46 
47 		uint32 outType = kPciRangeInvalid;
48 		switch (type & fdtPciRangeTypeMask) {
49 		case fdtPciRangeIoPort:
50 			outType = kPciRangeIoPort;
51 			break;
52 		case fdtPciRangeMmio32Bit:
53 			outType = kPciRangeMmio;
54 			break;
55 		case fdtPciRangeMmio64Bit:
56 			outType = kPciRangeMmio + kPciRangeMmio64Bit;
57 			break;
58 		}
59 		if (outType >= kPciRangeMmio && outType < kPciRangeMmioEnd
60 			&& (fdtPciRangePrefechable & type) != 0)
61 			outType += kPciRangeMmioPrefetch;
62 
63 		if (outType != kPciRangeInvalid) {
64 			fResourceRanges[outType].type = outType;
65 			fResourceRanges[outType].host_addr = parentAdr;
66 			fResourceRanges[outType].pci_addr = childAdr;
67 			fResourceRanges[outType].size = len;
68 		}
69 
70 		switch (type & fdtPciRangeTypeMask) {
71 		case fdtPciRangeConfig:    dprintf("CONFIG"); break;
72 		case fdtPciRangeIoPort:    dprintf("IOPORT"); break;
73 		case fdtPciRangeMmio32Bit: dprintf("MMIO32"); break;
74 		case fdtPciRangeMmio64Bit: dprintf("MMIO64"); break;
75 		}
76 
77 		dprintf(" (0x%08" B_PRIx32 "): ", type);
78 		dprintf("child: %08" B_PRIx64, childAdr);
79 		dprintf(", parent: %08" B_PRIx64, parentAdr);
80 		dprintf(", len: %" B_PRIx64 "\n", len);
81 	}
82 
83 	uint64 regs = 0;
84 	if (!fdtModule->get_reg(fdtDev, 0, &regs, &fRegsLen))
85 		return B_ERROR;
86 
87 	fRegsArea.SetTo(map_physical_memory("PCI Config MMIO", regs, fRegsLen, B_ANY_KERNEL_ADDRESS,
88 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&fRegs));
89 	CHECK_RET(fRegsArea.Get());
90 
91 	return B_OK;
92 }
93 
94 
95 status_t
96 ECAMPCIControllerFDT::Finalize()
97 {
98 	dprintf("finalize PCI controller from FDT\n");
99 
100 	DeviceNodePutter<&gDeviceManager> parent(gDeviceManager->get_parent_node(fNode));
101 
102 	fdt_device_module_info* parentModule;
103 	fdt_device* parentDev;
104 
105 	CHECK_RET(gDeviceManager->get_driver(parent.Get(), (driver_module_info**)&parentModule,
106 		(void**)&parentDev));
107 
108 	struct fdt_interrupt_map* interruptMap = parentModule->get_interrupt_map(parentDev);
109 	parentModule->print_interrupt_map(interruptMap);
110 
111 	for (int bus = 0; bus < 8; bus++) {
112 		// TODO: Proper multiple domain handling. (domain, bus) pair should be converted to virtual
113 		// bus before calling PCI module interface.
114 		for (int device = 0; device < 32; device++) {
115 			uint32 vendorID = gPCI->read_pci_config(bus, device, 0, PCI_vendor_id, 2);
116 			if ((vendorID != 0xffffffff) && (vendorID != 0xffff)) {
117 				uint32 headerType = gPCI->read_pci_config(bus, device, 0, PCI_header_type, 1);
118 				if ((headerType & 0x80) != 0) {
119 					for (int function = 0; function < 8; function++) {
120 						FinalizeInterrupts(parentModule, interruptMap, bus, device, function);
121 					}
122 				} else {
123 					FinalizeInterrupts(parentModule, interruptMap, bus, device, 0);
124 				}
125 			}
126 		}
127 	}
128 
129 	return B_OK;
130 }
131 
132 
133 void
134 ECAMPCIControllerFDT::FinalizeInterrupts(fdt_device_module_info* fdtModule,
135 	struct fdt_interrupt_map* interruptMap, int bus, int device, int function)
136 {
137 	uint32 childAddr = ((bus & 0xff) << 16) | ((device & 0x1f) << 11) | ((function & 0x07) << 8);
138 	uint32 interruptPin = gPCI->read_pci_config(bus, device, function, PCI_interrupt_pin, 1);
139 
140 	if (interruptPin == 0xffffffff) {
141 		dprintf("Error: Unable to read interrupt pin!\n");
142 		return;
143 	}
144 
145 	uint32 irq = fdtModule->lookup_interrupt_map(interruptMap, childAddr, interruptPin);
146 	if (irq == 0xffffffff) {
147 		dprintf("no interrupt mapping for childAddr: (%d:%d:%d), childIrq: %d)\n",
148 			bus, device, function, interruptPin);
149 	} else {
150 		dprintf("configure interrupt (%d,%d,%d) --> %d\n",
151 			bus, device, function, irq);
152 		gPCI->update_interrupt_line(bus, device, function, irq);
153 	}
154 }
155