xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci_root.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
1 /*
2  * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Copyright 2003, Marcus Overhagen. All rights reserved.
4  *
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include <device_manager.h>
10 #include <PCI.h>
11 #include <drivers/ACPI.h>
12 #include <drivers/bus/FDT.h>
13 
14 #include <string.h>
15 
16 #include "pci_private.h"
17 #include "pci.h"
18 
19 
20 // name of PCI root module
21 #define PCI_ROOT_MODULE_NAME "bus_managers/pci/root/driver_v1"
22 
23 
24 device_node* gPCIRootNode = NULL;
25 
26 
27 static float
28 pci_root_supports_device(device_node* parent)
29 {
30 	const char* bus;
31 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) < B_OK)
32 		return -1.0f;
33 
34 #if defined(__riscv)
35 	if (strcmp(bus, "fdt") == 0) {
36 		const char* compatible;
37 		if (gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, false) < B_OK)
38 			return -1.0f;
39 
40 		if (strcmp(compatible, "pci-host-ecam-generic") == 0
41 			|| strcmp(compatible, "sifive,fu740-pcie") == 0) {
42 			return 1.0f;
43 		}
44 	}
45 #elif defined(__arm__) || defined(__aarch64__)
46 	if (strcmp(bus, "fdt") == 0) {
47 		const char* compatible;
48 		if (gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, false) < B_OK)
49 			return -1.0f;
50 
51 		if (strcmp(compatible, "pci-host-ecam-generic") == 0)
52 			return 1.0f;
53 	}
54 
55 	if (strcmp(bus, "acpi") == 0) {
56 		const char* hid;
57 		if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid, false) < B_OK)
58 			return -1.0f;
59 
60 		if (strcmp(hid, "PNP0A03") == 0 || strcmp(hid, "PNP0A08") == 0)
61 			return 1.0f;
62 	}
63 #else
64 	if (strcmp(bus, "root") == 0)
65 		return 1.0f;
66 #endif
67 
68 	return 0.0;
69 }
70 
71 
72 static status_t
73 pci_root_register_device(device_node* parent)
74 {
75 // XXX how do we handle this for PPC?
76 // I/O port for PCI config space address
77 #define PCI_CONFIG_ADDRESS 0xcf8
78 
79 	io_resource resources[2] = {
80 		{B_IO_PORT, PCI_CONFIG_ADDRESS, 8},
81 		{}
82 	};
83 	device_attr attrs[] = {
84 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "PCI"}},
85 		{B_DEVICE_FLAGS, B_UINT32_TYPE, {.ui32 = B_KEEP_DRIVER_LOADED}},
86 		{}
87 	};
88 
89 	return gDeviceManager->register_node(parent, PCI_ROOT_MODULE_NAME, attrs,
90 		resources, NULL);
91 }
92 
93 
94 static status_t
95 pci_root_register_child_devices(void* cookie)
96 {
97 	device_node* node = (device_node*)cookie;
98 
99 	pci_info info;
100 	for (int32 i = 0; pci_get_nth_pci_info(i, &info) == B_OK; i++) {
101 		uint8 domain;
102 		uint8 bus;
103 		if (gPCI->ResolveVirtualBus(info.bus, &domain, &bus) != B_OK) {
104 			dprintf("ResolveVirtualBus(%u) failed\n", info.bus);
105 			continue;
106 		}
107 
108 		device_attr attrs[] = {
109 			// info about device
110 			{B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}},
111 
112 			// location on PCI bus
113 			{B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {.ui8 = domain}},
114 			{B_PCI_DEVICE_BUS, B_UINT8_TYPE, {.ui8 = bus}},
115 			{B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {.ui8 = info.device}},
116 			{B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {.ui8 = info.function}},
117 
118 			// info about the device
119 			{B_DEVICE_VENDOR_ID, B_UINT16_TYPE, {.ui16 = info.vendor_id}},
120 			{B_DEVICE_ID, B_UINT16_TYPE, {.ui16 = info.device_id}},
121 
122 			{B_DEVICE_TYPE, B_UINT16_TYPE, {.ui16 = info.class_base}},
123 			{B_DEVICE_SUB_TYPE, B_UINT16_TYPE, {.ui16 = info.class_sub}},
124 			{B_DEVICE_INTERFACE, B_UINT16_TYPE, {.ui16 = info.class_api}},
125 
126 			{B_DEVICE_FLAGS, B_UINT32_TYPE, {.ui32 = B_FIND_CHILD_ON_DEMAND}},
127 			{}
128 		};
129 
130 		gDeviceManager->register_node(node, PCI_DEVICE_MODULE_NAME, attrs,
131 			NULL, NULL);
132 	}
133 
134 	return B_OK;
135 }
136 
137 
138 static status_t
139 pci_root_init(device_node* node, void** _cookie)
140 {
141 	*_cookie = node;
142 
143 	gPCIRootNode = node;
144 
145 	module_info *module;
146 	status_t res = get_module(B_PCI_MODULE_NAME, &module);
147 	if (res < B_OK)
148 		return res;
149 
150 	return pci_init_deferred();
151 }
152 
153 
154 static int32
155 pci_root_std_ops(int32 op, ...)
156 {
157 	switch (op) {
158 		case B_MODULE_INIT:
159 			return B_OK;
160 
161 		case B_MODULE_UNINIT:
162 			return B_OK;
163 	}
164 
165 	return B_BAD_VALUE;
166 }
167 
168 
169 struct pci_root_module_info gPCIRootModule = {
170 	{
171 		{
172 			PCI_ROOT_MODULE_NAME,
173 			0,
174 			pci_root_std_ops
175 		},
176 
177 		pci_root_supports_device,
178 		pci_root_register_device,
179 		pci_root_init,
180 		NULL,	// uninit
181 		pci_root_register_child_devices,
182 		NULL,	// rescan devices
183 		NULL,	// device removed
184 	},
185 
186 	&pci_read_config,
187 	&pci_write_config
188 };
189