xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci.cpp (revision d29f332ad4210e2e2b5ef42231531dd937ebc52e)
1 /*
2  * Copyright 2005, 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 <KernelExport.h>
10 #include <PCI.h>
11 
12 #include "util/kernel_cpp.h"
13 #include "pci_priv.h"
14 #include "pci.h"
15 
16 
17 bool gIrqRouterAvailable = false;
18 spinlock gConfigLock = 0;
19 
20 static PCI *sPCI;
21 
22 
23 status_t
24 pci_init(void)
25 {
26 	if (pci_io_init() != B_OK) {
27 		TRACE(("PCI: pci_io_init failed\n"));
28 		return B_ERROR;
29 	}
30 
31 	if (pci_config_init() != B_OK) {
32 		TRACE(("PCI: pci_config_init failed\n"));
33 		return B_ERROR;
34 	}
35 
36 	if (pci_irq_init() != B_OK)
37 		TRACE(("PCI: IRQ router not available\n"));
38 	else
39 		gIrqRouterAvailable = true;
40 
41 	sPCI = new PCI;
42 
43 	return B_OK;
44 }
45 
46 
47 void
48 pci_uninit(void)
49 {
50 	delete sPCI;
51 }
52 
53 
54 long
55 pci_get_nth_pci_info(long index, pci_info *outInfo)
56 {
57 	return sPCI->GetNthPciInfo(index, outInfo);
58 }
59 
60 
61 PCI::PCI()
62 {
63 	fRootBus.parent = 0;
64 	fRootBus.bus = 0;
65 	fRootBus.child = 0;
66 
67 	DiscoverBus(&fRootBus);
68 
69 	RefreshDeviceInfo(&fRootBus);
70 }
71 
72 
73 PCI::~PCI()
74 {
75 }
76 
77 
78 status_t
79 PCI::GetNthPciInfo(long index, pci_info *outInfo)
80 {
81 	long curindex = 0;
82 	return GetNthPciInfo(&fRootBus, &curindex, index, outInfo);
83 }
84 
85 
86 status_t
87 PCI::GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo)
88 {
89 	// maps tree structure to linear indexed view
90 	PCIDev *dev = bus->child;
91 	while (dev) {
92 		if (*curindex == wantindex) {
93 			*outInfo = dev->info;
94 			return B_OK;
95 		}
96 		*curindex += 1;
97 		if (dev->child && B_OK == GetNthPciInfo(dev->child, curindex, wantindex, outInfo))
98 			return B_OK;
99 		dev = dev->next;
100 	}
101 	return B_ERROR;
102 }
103 
104 
105 void
106 PCI::DiscoverBus(PCIBus *bus)
107 {
108 	TRACE(("PCI: DiscoverBus, bus %u\n", bus->bus));
109 
110 	for (int dev = 0; dev < gMaxBusDevices; dev++) {
111 		uint16 vendor_id = pci_read_config(bus->bus, dev, 0, PCI_vendor_id, 2);
112 		if (vendor_id == 0xffff)
113 			continue;
114 
115 		uint8 type = pci_read_config(bus->bus, dev, 0, PCI_header_type, 1);
116 		int nfunc = (type & PCI_multifunction) ? 8 : 1;
117 		for (int func = 0; func < nfunc; func++)
118 			DiscoverDevice(bus, dev, func);
119 	}
120 }
121 
122 
123 void
124 PCI::DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func)
125 {
126 	TRACE(("PCI: DiscoverDevice, bus %u, dev %u, func %u\n", bus->bus, dev, func));
127 
128 	uint16 device_id = pci_read_config(bus->bus, dev, func, PCI_device_id, 2);
129 	if (device_id == 0xffff)
130 		return;
131 
132 	PCIDev *newdev = CreateDevice(bus, dev, func);
133 
134 	uint8 base_class = pci_read_config(bus->bus, dev, func, PCI_class_base, 1);
135 	uint8 sub_class	 = pci_read_config(bus->bus, dev, func, PCI_class_sub, 1);
136 	if (base_class == PCI_bridge && sub_class == PCI_pci) {
137 		uint8 secondary_bus = pci_read_config(bus->bus, dev, func, PCI_secondary_bus, 1);
138 		PCIBus *newbus = CreateBus(newdev, secondary_bus);
139 		DiscoverBus(newbus);
140 	}
141 }
142 
143 
144 PCIBus *
145 PCI::CreateBus(PCIDev *parent, uint8 bus)
146 {
147 	PCIBus *newbus = new PCIBus;
148 	newbus->parent = parent;
149 	newbus->bus = bus;
150 	newbus->child = 0;
151 
152 	// append
153 	parent->child = newbus;
154 
155 	return newbus;
156 }
157 
158 
159 PCIDev *
160 PCI::CreateDevice(PCIBus *parent, uint8 dev, uint8 func)
161 {
162 	TRACE(("PCI: CreateDevice, bus %u, dev %u, func %u:\n", parent->bus, dev, func));
163 
164 	PCIDev *newdev = new PCIDev;
165 	newdev->next = 0;
166 	newdev->parent = parent;
167 	newdev->child = 0;
168 	newdev->bus = parent->bus;
169 	newdev->dev = dev;
170 	newdev->func = func;
171 
172 	ReadPciBasicInfo(newdev);
173 
174 	TRACE(("PCI: vendor 0x%04x, device 0x%04x, class_base 0x%02x, class_sub 0x%02x\n",
175 		newdev->info.vendor_id, newdev->info.device_id, newdev->info.class_base, newdev->info.class_sub));
176 
177 	// append
178 	if (parent->child == 0) {
179 		parent->child = newdev;
180 	} else {
181 		PCIDev *sub = parent->child;
182 		while (sub->next)
183 			sub = sub->next;
184 		sub->next = newdev;
185 	}
186 
187 	return newdev;
188 }
189 
190 
191 uint32
192 PCI::BarSize(uint32 bits, uint32 mask)
193 {
194 	bits &= mask;
195 	if (!bits)
196 		return 0;
197 	uint32 size = 1;
198 	while (!(bits & size))
199 		size <<= 1;
200 	return size;
201 }
202 
203 
204 void
205 PCI::GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags)
206 {
207 	uint32 oldvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4);
208 	pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, 0xffffffff);
209 	uint32 newvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4);
210 	pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
211 
212 	*address = oldvalue & PCI_address_memory_32_mask;
213 	if (size)
214 		*size = BarSize(newvalue, PCI_address_memory_32_mask);
215 	if (flags)
216 		*flags = newvalue & 0xf;
217 }
218 
219 
220 void
221 PCI::GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags)
222 {
223 	uint32 oldvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4);
224 	pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, 0xfffffffe); // LSB must be 0
225 	uint32 newvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4);
226 	pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
227 
228 	*address = oldvalue & PCI_rom_address_mask;
229 	if (size)
230 		*size = BarSize(newvalue, PCI_rom_address_mask);
231 	if (flags)
232 		*flags = newvalue & 0xf;
233 }
234 
235 
236 void
237 PCI::ReadPciBasicInfo(PCIDev *dev)
238 {
239 	dev->info.vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_vendor_id, 2);
240 	dev->info.device_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_device_id, 2);
241 	dev->info.bus = dev->bus;
242 	dev->info.device = dev->dev;
243 	dev->info.function = dev->func;
244 	dev->info.revision = pci_read_config(dev->bus, dev->dev, dev->func, PCI_revision, 1);
245 	dev->info.class_api = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_api, 1);
246 	dev->info.class_sub = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_sub, 1);
247 	dev->info.class_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_base, 1);
248 	dev->info.line_size = pci_read_config(dev->bus, dev->dev, dev->func, PCI_line_size, 1);
249 	dev->info.latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_latency, 1);
250 	// BeOS does not mask off the multifunction bit, developer must use (header_type & PCI_header_type_mask)
251 	dev->info.header_type = pci_read_config(dev->bus, dev->dev, dev->func, PCI_header_type, 1);
252 	dev->info.bist = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bist, 1);
253 	dev->info.reserved = 0;
254 }
255 
256 
257 void
258 PCI::ReadPciHeaderInfo(PCIDev *dev)
259 {
260 	switch (dev->info.header_type & PCI_header_type_mask) {
261 		case 0:
262 		{
263 			// disable PCI device address decoding (io and memory) while BARs are modified
264 			uint16 pcicmd = pci_read_config(dev->bus, dev->dev, dev->func, PCI_command, 2);
265 			pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
266 
267 			// get BAR size infos
268 			GetRomBarInfo(dev, PCI_rom_base, &dev->info.u.h0.rom_base_pci, &dev->info.u.h0.rom_size);
269 			for (int i = 0; i < 6; i++) {
270 				GetBarInfo(dev, PCI_base_registers + 4*i,
271 					&dev->info.u.h0.base_registers_pci[i],
272 					&dev->info.u.h0.base_register_sizes[i],
273 					&dev->info.u.h0.base_register_flags[i]);
274 			}
275 
276 			// restore PCI device address decoding
277 			pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd);
278 
279 			dev->info.u.h0.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h0.rom_base_pci);
280 			for (int i = 0; i < 6; i++) {
281 				dev->info.u.h0.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h0.base_registers_pci[i]);
282 			}
283 
284 			dev->info.u.h0.cardbus_cis = pci_read_config(dev->bus, dev->dev, dev->func, PCI_cardbus_cis, 4);
285 			dev->info.u.h0.subsystem_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subsystem_id, 2);
286 			dev->info.u.h0.subsystem_vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subsystem_vendor_id, 2);
287 			dev->info.u.h0.interrupt_line = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1);
288 			dev->info.u.h0.interrupt_pin = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1);
289 			dev->info.u.h0.min_grant = pci_read_config(dev->bus, dev->dev, dev->func, PCI_min_grant, 1);
290 			dev->info.u.h0.max_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_max_latency, 1);
291 			break;
292 		}
293 
294 		case 1:
295 		{
296 			// disable PCI device address decoding (io and memory) while BARs are modified
297 			uint16 pcicmd = pci_read_config(dev->bus, dev->dev, dev->func, PCI_command, 2);
298 			pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
299 
300 			GetRomBarInfo(dev, PCI_bridge_rom_base, &dev->info.u.h1.rom_base_pci);
301 			for (int i = 0; i < 2; i++) {
302 				GetBarInfo(dev, PCI_base_registers + 4*i,
303 					&dev->info.u.h1.base_registers_pci[i],
304 					&dev->info.u.h1.base_register_sizes[i],
305 					&dev->info.u.h1.base_register_flags[i]);
306 			}
307 
308 			// restore PCI device address decoding
309 			pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd);
310 
311 			dev->info.u.h1.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h1.rom_base_pci);
312 			for (int i = 0; i < 2; i++) {
313 				dev->info.u.h1.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h1.base_registers_pci[i]);
314 			}
315 
316 			dev->info.u.h1.primary_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_primary_bus, 1);
317 			dev->info.u.h1.secondary_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_bus, 1);
318 			dev->info.u.h1.subordinate_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subordinate_bus, 1);
319 			dev->info.u.h1.secondary_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_latency, 1);
320 			dev->info.u.h1.io_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_base, 1);
321 			dev->info.u.h1.io_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_limit, 1);
322 			dev->info.u.h1.secondary_status = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_status, 2);
323 			dev->info.u.h1.memory_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_base, 2);
324 			dev->info.u.h1.memory_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_limit, 2);
325 			dev->info.u.h1.prefetchable_memory_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base, 2);
326 			dev->info.u.h1.prefetchable_memory_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit, 2);
327 			dev->info.u.h1.prefetchable_memory_base_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base_upper32, 4);
328 			dev->info.u.h1.prefetchable_memory_limit_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit_upper32, 4);
329 			dev->info.u.h1.io_base_upper16 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_base_upper16, 2);
330 			dev->info.u.h1.io_limit_upper16 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_limit_upper16, 2);
331 			dev->info.u.h1.interrupt_line = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1);
332 			dev->info.u.h1.interrupt_pin = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1);
333 			dev->info.u.h1.bridge_control = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bridge_control, 2);
334 			break;
335 		}
336 
337 		default:
338 			TRACE(("PCI: Header type unknown (%d)\n", dev->info.header_type));
339 			break;
340 	}
341 }
342 
343 
344 void
345 PCI::RefreshDeviceInfo(PCIBus *bus)
346 {
347 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
348 		ReadPciBasicInfo(dev);
349 		ReadPciHeaderInfo(dev);
350 		if (dev->child)
351 			RefreshDeviceInfo(dev->child);
352 	}
353 }
354