1/*
2 * Copyright 2022, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "X86PCIController.h"
8
9#include <ioapic.h>
10
11#include <AutoDeleterDrivers.h>
12#include <util/AutoLock.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
32float
33X86PCIController::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
46status_t
47X86PCIController::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
59status_t
60X86PCIController::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
106status_t
107X86PCIController::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
120status_t
121X86PCIController::InitDriverInt(device_node* node)
122{
123	fNode = node;
124	return B_OK;
125}
126
127
128void
129X86PCIController::UninitDriver()
130{
131	delete this;
132}
133
134
135//#pragma mark - PCI controller
136
137
138status_t
139X86PCIController::ReadIrq(uint8 bus, uint8 device, uint8 function,
140	uint8 pin, uint8& irq)
141{
142	return B_UNSUPPORTED;
143}
144
145
146status_t
147X86PCIController::WriteIrq(uint8 bus, uint8 device, uint8 function,
148	uint8 pin, uint8 irq)
149{
150	return B_UNSUPPORTED;
151}
152
153
154status_t
155X86PCIController::GetRange(uint32 index, pci_resource_range* range)
156{
157	return B_BAD_INDEX;
158}
159
160
161status_t
162X86PCIController::Finalize()
163{
164	ioapic_init();
165	return B_OK;
166}
167
168
169//#pragma mark - X86PCIControllerMeth1
170
171
172status_t
173X86PCIControllerMeth1::InitDriverInt(device_node* node)
174{
175	CHECK_RET(X86PCIController::InitDriverInt(node));
176
177	// check for mechanism 1
178	out32(0x80000000, PCI_MECH1_REQ_PORT);
179	if (0x80000000 == in32(PCI_MECH1_REQ_PORT)) {
180		dprintf("PCI: mechanism 1 controller found\n");
181		return B_OK;
182	}
183	return B_ERROR;
184}
185
186
187status_t
188X86PCIControllerMeth1::ReadConfig(
189	uint8 bus, uint8 device, uint8 function,
190	uint16 offset, uint8 size, uint32 &value)
191{
192	if (offset > 0xff)
193		return B_BAD_VALUE;
194
195	InterruptsSpinLocker lock(fLock);
196	out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
197	switch (size) {
198		case 1:
199			value = in8(PCI_MECH1_DATA_PORT + (offset & 3));
200			break;
201		case 2:
202			value = in16(PCI_MECH1_DATA_PORT + (offset & 3));
203			break;
204		case 4:
205			value = in32(PCI_MECH1_DATA_PORT);
206			break;
207		default:
208			return B_ERROR;
209	}
210
211	return B_OK;
212}
213
214
215status_t
216X86PCIControllerMeth1::WriteConfig(
217	uint8 bus, uint8 device, uint8 function,
218	uint16 offset, uint8 size, uint32 value)
219{
220	if (offset > 0xff)
221		return B_BAD_VALUE;
222
223	InterruptsSpinLocker lock(fLock);
224	out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
225	switch (size) {
226		case 1:
227			out8(value, PCI_MECH1_DATA_PORT + (offset & 3));
228			break;
229		case 2:
230			out16(value, PCI_MECH1_DATA_PORT + (offset & 3));
231			break;
232		case 4:
233			out32(value, PCI_MECH1_DATA_PORT);
234			break;
235		default:
236			return B_ERROR;
237	}
238
239	return B_OK;
240}
241
242
243status_t X86PCIControllerMeth1::GetMaxBusDevices(int32& count)
244{
245	count = 32;
246	return B_OK;
247}
248
249
250//#pragma mark - X86PCIControllerMeth2
251
252
253status_t
254X86PCIControllerMeth2::InitDriverInt(device_node* node)
255{
256	CHECK_RET(X86PCIController::InitDriverInt(node));
257
258	// check for mechanism 2
259	out8(0x00, 0xCFB);
260	out8(0x00, 0xCF8);
261	out8(0x00, 0xCFA);
262	if (in8(0xCF8) == 0x00 && in8(0xCFA) == 0x00) {
263		dprintf("PCI: mechanism 2 controller found\n");
264		return B_OK;
265	}
266	return B_ERROR;
267}
268
269
270status_t
271X86PCIControllerMeth2::ReadConfig(
272	uint8 bus, uint8 device, uint8 function,
273	uint16 offset, uint8 size, uint32 &value)
274{
275	if (offset > 0xff)
276		return B_BAD_VALUE;
277
278	InterruptsSpinLocker lock(fLock);
279	out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
280	out8(bus, PCI_MECH2_FORWARD_PORT);
281	switch (size) {
282		case 1:
283			value = in8(PCI_MECH2_CONFIG_PORT(device, offset));
284			break;
285		case 2:
286			value = in16(PCI_MECH2_CONFIG_PORT(device, offset));
287			break;
288		case 4:
289			value = in32(PCI_MECH2_CONFIG_PORT(device, offset));
290			break;
291		default:
292			return B_ERROR;
293	}
294	out8(0, PCI_MECH2_ENABLE_PORT);
295
296	return B_OK;
297}
298
299
300status_t
301X86PCIControllerMeth2::WriteConfig(
302	uint8 bus, uint8 device, uint8 function,
303	uint16 offset, uint8 size, uint32 value)
304{
305	if (offset > 0xff)
306		return B_BAD_VALUE;
307
308	InterruptsSpinLocker lock(fLock);
309	out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
310	out8(bus, PCI_MECH2_FORWARD_PORT);
311	switch (size) {
312		case 1:
313			out8(value, PCI_MECH2_CONFIG_PORT(device, offset));
314			break;
315		case 2:
316			out16(value, PCI_MECH2_CONFIG_PORT(device, offset));
317			break;
318		case 4:
319			out32(value, PCI_MECH2_CONFIG_PORT(device, offset));
320			break;
321		default:
322			return B_ERROR;
323	}
324	out8(0, PCI_MECH2_ENABLE_PORT);
325
326	return B_OK;
327}
328
329
330status_t X86PCIControllerMeth2::GetMaxBusDevices(int32& count)
331{
332	count = 16;
333	return B_OK;
334}
335
336
337//#pragma mark - X86PCIControllerMethPcie
338
339
340status_t
341X86PCIControllerMethPcie::InitDriverInt(device_node* node)
342{
343	status_t status = X86PCIController::InitDriverInt(node);
344	if (status != B_OK)
345		return status;
346
347	// search ACPI
348	device_node *acpiNode = NULL;
349	{
350		device_node* deviceRoot = gDeviceManager->get_root_node();
351		device_attr acpiAttrs[] = {
352			{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }},
353			{ ACPI_DEVICE_HID_ITEM, B_STRING_TYPE, { .string = "PNP0A08" }},
354			{ NULL }
355		};
356		if (gDeviceManager->find_child_node(deviceRoot, acpiAttrs, &acpiNode) != B_OK)
357			return ENODEV;
358	}
359
360	status = fECAMPCIController.ReadResourceInfo(acpiNode);
361	gDeviceManager->put_node(acpiNode);
362	return status;
363}
364
365
366status_t
367X86PCIControllerMethPcie::ReadConfig(
368	uint8 bus, uint8 device, uint8 function,
369	uint16 offset, uint8 size, uint32 &value)
370{
371	// fallback to mechanism 1 for out of range busses
372	if (bus < fECAMPCIController.fStartBusNumber || bus > fECAMPCIController.fEndBusNumber) {
373		return X86PCIControllerMeth1::ReadConfig(bus, device, function, offset,
374			size, value);
375	}
376
377	return fECAMPCIController.ReadConfig(bus, device, function, offset, size, value);
378}
379
380
381status_t
382X86PCIControllerMethPcie::WriteConfig(
383	uint8 bus, uint8 device, uint8 function,
384	uint16 offset, uint8 size, uint32 value)
385{
386	// fallback to mechanism 1 for out of range busses
387	if (bus < fECAMPCIController.fStartBusNumber || bus > fECAMPCIController.fEndBusNumber) {
388		return X86PCIControllerMeth1::WriteConfig(bus, device, function, offset,
389			size, value);
390	}
391
392	return fECAMPCIController.WriteConfig(bus, device, function, offset, size, value);
393}
394
395
396status_t
397X86PCIControllerMethPcie::GetMaxBusDevices(int32& count)
398{
399	return fECAMPCIController.GetMaxBusDevices(count);
400}
401
402
403status_t
404X86PCIControllerMethPcie::GetRange(uint32 index, pci_resource_range* range)
405{
406	return fECAMPCIController.GetRange(index, range);
407}
408