xref: /haiku/src/add-ons/kernel/busses/pci/x86/X86PCIController.cpp (revision b289c1e4066d31da5ac6c5e587d9b98b76493af9)
1 /*
2  * Copyright 2022, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "X86PCIController.h"
8 #include "pci_acpi.h"
9 
10 #include <AutoDeleterDrivers.h>
11 #include <util/AutoLock.h>
12 #include "acpi.h"
13 
14 #include <string.h>
15 #include <new>
16 
17 
18 #define PCI_MECH1_REQ_PORT				0xCF8
19 #define PCI_MECH1_DATA_PORT 			0xCFC
20 #define PCI_MECH1_REQ_DATA(bus, device, func, offset) \
21 	(0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3))
22 
23 #define PCI_MECH2_ENABLE_PORT			0x0cf8
24 #define PCI_MECH2_FORWARD_PORT			0x0cfa
25 #define PCI_MECH2_CONFIG_PORT(dev, offset) \
26 	(uint16)(0xC00 | (dev << 8) | offset)
27 
28 
29 //#pragma mark - driver
30 
31 
32 float
33 X86PCIController::SupportsDevice(device_node* parent)
34 {
35 	const char* bus;
36 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) < B_OK)
37 		return -1.0f;
38 
39 	if (strcmp(bus, "root") == 0)
40 		return 1.0f;
41 
42 	return 0.0;
43 }
44 
45 
46 status_t
47 X86PCIController::RegisterDevice(device_node* parent)
48 {
49 	device_attr attrs[] = {
50 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "X86 PCI Host Controller"} },
51 		{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {.string = "bus_managers/pci/root/driver_v1"} },
52 		{}
53 	};
54 
55 	return gDeviceManager->register_node(parent, PCI_X86_DRIVER_MODULE_NAME, attrs, NULL, NULL);
56 }
57 
58 
59 status_t
60 X86PCIController::InitDriver(device_node* node, X86PCIController*& outDriver)
61 {
62 	bool search_mech1 = true;
63 	bool search_mech2 = true;
64 	bool search_mechpcie = true;
65 	void *config = NULL;
66 
67 	config = load_driver_settings("pci");
68 	if (config) {
69 		const char *mech = get_driver_parameter(config, "mechanism", NULL, NULL);
70 		if (mech) {
71 			search_mech1 = search_mech2 = search_mechpcie = false;
72 			if (strcmp(mech, "1") == 0)
73 				search_mech1 = true;
74 			else if (strcmp(mech, "2") == 0)
75 				search_mech2 = true;
76 			else if (strcmp(mech, "pcie") == 0)
77 				search_mechpcie = true;
78 			else
79 				panic("Unknown pci config mechanism setting %s\n", mech);
80 		}
81 		unload_driver_settings(config);
82 	}
83 
84 	// PCI configuration mechanism PCIe is the preferred one.
85 	// If it doesn't work, try mechanism 1.
86 	// If it doesn't work, try mechanism 2.
87 
88 	if (search_mechpcie) {
89 		if (CreateDriver(node, new(std::nothrow) X86PCIControllerMethPcie(), outDriver) >= B_OK)
90 			return B_OK;
91 	}
92 	if (search_mech1) {
93 		if (CreateDriver(node, new(std::nothrow) X86PCIControllerMeth1(), outDriver) >= B_OK)
94 			return B_OK;
95 	}
96 	if (search_mech2) {
97 		if (CreateDriver(node, new(std::nothrow) X86PCIControllerMeth2(), outDriver) >= B_OK)
98 			return B_OK;
99 	}
100 
101 	dprintf("PCI: no configuration mechanism found\n");
102 	return B_ERROR;
103 }
104 
105 
106 status_t
107 X86PCIController::CreateDriver(device_node* node, X86PCIController* driverIn,
108 	X86PCIController*& driverOut)
109 {
110 	ObjectDeleter<X86PCIController> driver(driverIn);
111 	if (!driver.IsSet())
112 		return B_NO_MEMORY;
113 
114 	CHECK_RET(driver->InitDriverInt(node));
115 	driverOut = driver.Detach();
116 	return B_OK;
117 }
118 
119 
120 status_t
121 X86PCIController::InitDriverInt(device_node* node)
122 {
123 	fNode = node;
124 	return B_OK;
125 }
126 
127 
128 void
129 X86PCIController::UninitDriver()
130 {
131 	delete this;
132 }
133 
134 
135 //#pragma mark - PCI controller
136 
137 
138 status_t
139 X86PCIController::ReadIrq(uint8 bus, uint8 device, uint8 function,
140 	uint8 pin, uint8& irq)
141 {
142 	return B_UNSUPPORTED;
143 }
144 
145 
146 status_t
147 X86PCIController::WriteIrq(uint8 bus, uint8 device, uint8 function,
148 	uint8 pin, uint8 irq)
149 {
150 	return B_UNSUPPORTED;
151 }
152 
153 
154 status_t
155 X86PCIController::GetRange(uint32 index, pci_resource_range* range)
156 {
157 
158 	return B_BAD_INDEX;
159 }
160 
161 
162 //#pragma mark - X86PCIControllerMeth1
163 
164 
165 status_t
166 X86PCIControllerMeth1::InitDriverInt(device_node* node)
167 {
168 	CHECK_RET(X86PCIController::InitDriverInt(node));
169 
170 	// check for mechanism 1
171 	out32(0x80000000, PCI_MECH1_REQ_PORT);
172 	if (0x80000000 == in32(PCI_MECH1_REQ_PORT)) {
173 		dprintf("PCI: mechanism 1 controller found\n");
174 		return B_OK;
175 	}
176 	return B_ERROR;
177 }
178 
179 
180 status_t
181 X86PCIControllerMeth1::ReadConfig(
182 	uint8 bus, uint8 device, uint8 function,
183 	uint16 offset, uint8 size, uint32 &value)
184 {
185 	if (offset > 0xff)
186 		return B_BAD_VALUE;
187 
188 	InterruptsSpinLocker lock(fLock);
189 	out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
190 	switch (size) {
191 		case 1:
192 			value = in8(PCI_MECH1_DATA_PORT + (offset & 3));
193 			break;
194 		case 2:
195 			value = in16(PCI_MECH1_DATA_PORT + (offset & 3));
196 			break;
197 		case 4:
198 			value = in32(PCI_MECH1_DATA_PORT);
199 			break;
200 		default:
201 			return B_ERROR;
202 	}
203 
204 	return B_OK;
205 }
206 
207 
208 status_t
209 X86PCIControllerMeth1::WriteConfig(
210 	uint8 bus, uint8 device, uint8 function,
211 	uint16 offset, uint8 size, uint32 value)
212 {
213 	if (offset > 0xff)
214 		return B_BAD_VALUE;
215 
216 	InterruptsSpinLocker lock(fLock);
217 	out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
218 	switch (size) {
219 		case 1:
220 			out8(value, PCI_MECH1_DATA_PORT + (offset & 3));
221 			break;
222 		case 2:
223 			out16(value, PCI_MECH1_DATA_PORT + (offset & 3));
224 			break;
225 		case 4:
226 			out32(value, PCI_MECH1_DATA_PORT);
227 			break;
228 		default:
229 			return B_ERROR;
230 	}
231 
232 	return B_OK;
233 }
234 
235 
236 status_t X86PCIControllerMeth1::GetMaxBusDevices(int32& count)
237 {
238 	count = 32;
239 	return B_OK;
240 }
241 
242 
243 //#pragma mark - X86PCIControllerMeth2
244 
245 
246 status_t
247 X86PCIControllerMeth2::InitDriverInt(device_node* node)
248 {
249 	CHECK_RET(X86PCIController::InitDriverInt(node));
250 
251 	// check for mechanism 2
252 	out8(0x00, 0xCFB);
253 	out8(0x00, 0xCF8);
254 	out8(0x00, 0xCFA);
255 	if (in8(0xCF8) == 0x00 && in8(0xCFA) == 0x00) {
256 		dprintf("PCI: mechanism 2 controller found\n");
257 		return B_OK;
258 	}
259 	return B_ERROR;
260 }
261 
262 
263 status_t
264 X86PCIControllerMeth2::ReadConfig(
265 	uint8 bus, uint8 device, uint8 function,
266 	uint16 offset, uint8 size, uint32 &value)
267 {
268 	if (offset > 0xff)
269 		return B_BAD_VALUE;
270 
271 	InterruptsSpinLocker lock(fLock);
272 	out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
273 	out8(bus, PCI_MECH2_FORWARD_PORT);
274 	switch (size) {
275 		case 1:
276 			value = in8(PCI_MECH2_CONFIG_PORT(device, offset));
277 			break;
278 		case 2:
279 			value = in16(PCI_MECH2_CONFIG_PORT(device, offset));
280 			break;
281 		case 4:
282 			value = in32(PCI_MECH2_CONFIG_PORT(device, offset));
283 			break;
284 		default:
285 			return B_ERROR;
286 	}
287 	out8(0, PCI_MECH2_ENABLE_PORT);
288 
289 	return B_OK;
290 }
291 
292 
293 status_t
294 X86PCIControllerMeth2::WriteConfig(
295 	uint8 bus, uint8 device, uint8 function,
296 	uint16 offset, uint8 size, uint32 value)
297 {
298 	if (offset > 0xff)
299 		return B_BAD_VALUE;
300 
301 	InterruptsSpinLocker lock(fLock);
302 	out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
303 	out8(bus, PCI_MECH2_FORWARD_PORT);
304 	switch (size) {
305 		case 1:
306 			out8(value, PCI_MECH2_CONFIG_PORT(device, offset));
307 			break;
308 		case 2:
309 			out16(value, PCI_MECH2_CONFIG_PORT(device, offset));
310 			break;
311 		case 4:
312 			out32(value, PCI_MECH2_CONFIG_PORT(device, offset));
313 			break;
314 		default:
315 			return B_ERROR;
316 	}
317 	out8(0, PCI_MECH2_ENABLE_PORT);
318 
319 	return B_OK;
320 }
321 
322 
323 status_t X86PCIControllerMeth2::GetMaxBusDevices(int32& count)
324 {
325 	count = 16;
326 	return B_OK;
327 }
328 
329 
330 //#pragma mark - X86PCIControllerMethPcie
331 
332 
333 #define PCIE_VADDR(base, bus, slot, func, reg)  ((base) + \
334 	((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) |   \
335     (((func) & 0x7) << 12) | ((reg) & 0xfff)))
336 
337 
338 status_t
339 X86PCIControllerMethPcie::InitDriverInt(device_node* node)
340 {
341 	CHECK_RET(X86PCIController::InitDriverInt(node));
342 
343 	acpi_init();
344 	struct acpi_table_mcfg* mcfg =
345 		(struct acpi_table_mcfg*)acpi_find_table("MCFG");
346 	if (mcfg != NULL) {
347 		struct acpi_mcfg_allocation* end = (struct acpi_mcfg_allocation*)
348 			((char*)mcfg + mcfg->Header.Length);
349 		struct acpi_mcfg_allocation* alloc = (struct acpi_mcfg_allocation*)
350 			(mcfg + 1);
351 		for (; alloc < end; alloc++) {
352 			dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: "
353 				"%x, end: %x\n", alloc->Address, alloc->PciSegment,
354 				alloc->StartBusNumber, alloc->EndBusNumber);
355 			if (alloc->PciSegment == 0) {
356 				area_id mcfgArea = map_physical_memory("acpi mcfg",
357 					alloc->Address, (alloc->EndBusNumber + 1) << 20,
358 					B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA
359 						| B_KERNEL_WRITE_AREA, (void **)&fPCIeBase);
360 				if (mcfgArea < 0)
361 					break;
362 				fStartBusNumber = alloc->StartBusNumber;
363 				fEndBusNumber = alloc->EndBusNumber;
364 				dprintf("PCI: mechanism pcie controller found\n");
365 				return B_OK;
366 			}
367 		}
368 	}
369 	return B_ERROR;
370 }
371 
372 
373 status_t
374 X86PCIControllerMethPcie::ReadConfig(
375 	uint8 bus, uint8 device, uint8 function,
376 	uint16 offset, uint8 size, uint32 &value)
377 {
378 	// fallback to mechanism 1 for out of range busses
379 	if (bus < fStartBusNumber || bus > fEndBusNumber) {
380 		return X86PCIControllerMeth1::ReadConfig(bus, device, function, offset,
381 			size, value);
382 	}
383 
384 	addr_t address = PCIE_VADDR(fPCIeBase, bus, device, function, offset);
385 
386 	switch (size) {
387 		case 1:
388 			value = *(uint8*)address;
389 			break;
390 		case 2:
391 			value = *(uint16*)address;
392 			break;
393 		case 4:
394 			value = *(uint32*)address;
395 			break;
396 		default:
397 			return B_ERROR;
398 	}
399 	return B_OK;
400 }
401 
402 
403 status_t
404 X86PCIControllerMethPcie::WriteConfig(
405 	uint8 bus, uint8 device, uint8 function,
406 	uint16 offset, uint8 size, uint32 value)
407 {
408 	// fallback to mechanism 1 for out of range busses
409 	if (bus < fStartBusNumber || bus > fEndBusNumber) {
410 		return X86PCIControllerMeth1::WriteConfig(bus, device, function, offset,
411 			size, value);
412 	}
413 
414 	addr_t address = PCIE_VADDR(fPCIeBase, bus, device, function, offset);
415 	switch (size) {
416 		case 1:
417 			*(uint8*)address = value;
418 			break;
419 		case 2:
420 			*(uint16*)address = value;
421 			break;
422 		case 4:
423 			*(uint32*)address = value;
424 			break;
425 		default:
426 			return B_ERROR;
427 	}
428 
429 	return B_OK;
430 }
431 
432 
433 status_t X86PCIControllerMethPcie::GetMaxBusDevices(int32& count)
434 {
435 	count = 32;
436 	return B_OK;
437 }
438