xref: /haiku/src/add-ons/kernel/busses/pci/ecam/ECAMPCIControllerACPI.cpp (revision 8b33ac6bff6933d2477a84cdc9d01598c61ffe84)
1 /*
2  * Copyright 2022, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "ECAMPCIController.h"
8 #include <acpi.h>
9 
10 #include <AutoDeleterDrivers.h>
11 
12 #include "acpi_irq_routing_table.h"
13 
14 #include <string.h>
15 
16 
17 status_t
18 ECAMPCIControllerACPI::ReadResourceInfo()
19 {
20 	DeviceNodePutter<&gDeviceManager> parent(gDeviceManager->get_parent_node(fNode));
21 
22 	dprintf("initialize PCI controller from ACPI\n");
23 
24 	acpi_module_info* acpiModule;
25 	acpi_device_module_info* acpiDeviceModule;
26 	acpi_device acpiDevice;
27 
28 	CHECK_RET(get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule));
29 
30 	acpi_mcfg *mcfg;
31 	CHECK_RET(acpiModule->get_table(ACPI_MCFG_SIGNATURE, 0, (void**)&mcfg));
32 
33 	CHECK_RET(gDeviceManager->get_driver(parent.Get(), (driver_module_info**)&acpiDeviceModule,
34 		(void**)&acpiDevice));
35 
36 	acpi_status acpi_res = acpiDeviceModule->walk_resources(acpiDevice, (char *)"_CRS",
37 		AcpiCrsScanCallback, this);
38 
39 	if (acpi_res != 0)
40 		return B_ERROR;
41 
42 	acpi_mcfg_allocation *end = (acpi_mcfg_allocation *) ((char*)mcfg + mcfg->header.length);
43 	acpi_mcfg_allocation *alloc = (acpi_mcfg_allocation *) (mcfg + 1);
44 
45 	if (alloc + 1 != end)
46 		dprintf("PCI: multiple host bridges not supported!");
47 
48 	for (; alloc < end; alloc++) {
49 		dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: %x, end: %x\n",
50 			alloc->address, alloc->pci_segment, alloc->start_bus_number, alloc->end_bus_number);
51 
52 		if (alloc->pci_segment != 0) {
53 			dprintf("PCI: multiple segments not supported!");
54 			continue;
55 		}
56 
57 		uint8 startBusNumber = alloc->start_bus_number;
58 		uint8 endBusNumber = alloc->end_bus_number;
59 
60 		fRegsArea.SetTo(map_physical_memory("PCI Config MMIO",
61 			alloc->address, (endBusNumber - startBusNumber + 1) << 20, B_ANY_KERNEL_ADDRESS,
62 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&fRegs));
63 		CHECK_RET(fRegsArea.Get());
64 
65 		return B_OK;
66 	}
67 
68 	return B_ERROR;
69 }
70 
71 
72 acpi_status
73 ECAMPCIControllerACPI::AcpiCrsScanCallback(acpi_resource *res, void *context)
74 {
75 	return static_cast<ECAMPCIControllerACPI*>(context)->AcpiCrsScanCallbackInt(res);
76 }
77 
78 
79 acpi_status
80 ECAMPCIControllerACPI::AcpiCrsScanCallbackInt(acpi_resource *res)
81 {
82 	uint32 outType;
83 
84 	switch (res->data.address.resource_type) {
85 		case 0: // ACPI_MEMORY_RANGE
86 			outType = kPciRangeMmio;
87 			if (res->type == ACPI_RESOURCE_TYPE_ADDRESS64)
88 				outType += kPciRangeMmio64Bit;
89 			if (res->data.address.info.mem.caching == 3 /*ACPI_PREFETCHABLE_MEMORY*/)
90 				outType += kPciRangeMmioPrefetch;
91 			break;
92 		case 1: // ACPI_IO_RANGE
93 			outType = kPciRangeIoPort;
94 			break;
95 		default:
96 			return B_OK;
97 	}
98 
99 	pci_resource_range& range = fResourceRanges[outType];
100 	range.type = outType;
101 
102 	switch (res->type) {
103 		case ACPI_RESOURCE_TYPE_ADDRESS16: {
104 			const auto &address = res->data.address16.address;
105 			range.host_addr = address.minimum + address.translation_offset;
106 			range.pci_addr  = address.minimum;
107 			range.size = address.address_length;
108 			break;
109 		}
110 		case ACPI_RESOURCE_TYPE_ADDRESS32: {
111 			const auto &address = res->data.address32.address;
112 			range.host_addr = address.minimum + address.translation_offset;
113 			range.pci_addr  = address.minimum;
114 			range.size = address.address_length;
115 			break;
116 		}
117 		case ACPI_RESOURCE_TYPE_ADDRESS64: {
118 			const auto &address = res->data.address64.address;
119 			range.host_addr = address.minimum + address.translation_offset;
120 			range.pci_addr  = address.minimum;
121 			range.size = address.address_length;
122 			break;
123 		}
124 	}
125 
126 	return B_OK;
127 }
128 
129 
130 status_t
131 ECAMPCIControllerACPI::Finalize()
132 {
133 	dprintf("finalize PCI controller from ACPI\n");
134 
135 	acpi_module_info *acpiModule;
136 	CHECK_RET(get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule));
137 
138 	IRQRoutingTable table;
139 	CHECK_RET(prepare_irq_routing(acpiModule, table, [](int32 gsi) {return true;}));
140 
141 	CHECK_RET(enable_irq_routing(acpiModule, table));
142 
143 	print_irq_routing_table(table);
144 
145 	return B_OK;
146 }
147