xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 /*
2  * Copyright 2006-2007, Marcus Overhagen. All rights reserved.
3  * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
4  * Copyright 2003, Marcus Overhagen. All rights reserved.
5  *
6  * Distributed under the terms of the MIT License.
7  */
8 
9 
10 #include <string.h>
11 #include <KernelExport.h>
12 #define __HAIKU_PCI_BUS_MANAGER_TESTING 1
13 #include <PCI.h>
14 
15 #include "util/kernel_cpp.h"
16 #include "pci_fixup.h"
17 #include "pci_priv.h"
18 #include "pci.h"
19 
20 #define TRACE_CAP(x...) dprintf(x)
21 #define FLOW(x...)
22 //#define FLOW(x...) dprintf(x)
23 
24 static PCI *sPCI;
25 
26 // #pragma mark bus manager exports
27 
28 
29 status_t
30 pci_controller_add(pci_controller *controller, void *cookie)
31 {
32 	return sPCI->AddController(controller, cookie);
33 }
34 
35 
36 long
37 pci_get_nth_pci_info(long index, pci_info *outInfo)
38 {
39 	return sPCI->GetNthPciInfo(index, outInfo);
40 }
41 
42 
43 uint32
44 pci_read_config(uint8 virt_bus, uint8 device, uint8 function, uint8 offset, uint8 size)
45 {
46 	uint8 bus;
47 	int domain;
48 	uint32 value;
49 
50 	if (sPCI->GetVirtBus(virt_bus, &domain, &bus) != B_OK)
51 		return 0xffffffff;
52 
53 	if (sPCI->ReadPciConfig(domain, bus, device, function, offset, size, &value) != B_OK)
54 		return 0xffffffff;
55 
56 	return value;
57 }
58 
59 
60 void
61 pci_write_config(uint8 virt_bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value)
62 {
63 	uint8 bus;
64 	int domain;
65 
66 	if (sPCI->GetVirtBus(virt_bus, &domain, &bus) != B_OK)
67 		return;
68 
69 	sPCI->WritePciConfig(domain, bus, device, function, offset, size, value);
70 }
71 
72 
73 status_t
74 pci_find_capability(uchar bus, uchar device, uchar function, uchar cap_id, uchar *offset)
75 {
76 	uint16 status;
77 	uint8 header_type;
78 	uint8 cap_ptr;
79 	int i;
80 
81 	if (!offset) {
82 		TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x offset NULL pointer\n", bus, device, function, cap_id);
83 		return B_BAD_VALUE;
84 	}
85 
86 	status = pci_read_config(bus, device, function, PCI_status, 2);
87 	if (!(status & PCI_status_capabilities)) {
88 		TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x not supported\n", bus, device, function, cap_id);
89 		return B_ERROR;
90 	}
91 
92 	header_type = pci_read_config(bus, device, function, PCI_header_type, 1);
93 	switch (header_type & PCI_header_type_mask) {
94 		case PCI_header_type_generic:
95 		case PCI_header_type_PCI_to_PCI_bridge:
96 			cap_ptr = pci_read_config(bus, device, function, PCI_capabilities_ptr, 1);
97 			break;
98 		case PCI_header_type_cardbus:
99 			cap_ptr = pci_read_config(bus, device, function, PCI_capabilities_ptr_2, 1);
100 			break;
101 		default:
102 			TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x unknown header type\n", bus, device, function, cap_id);
103 			return B_ERROR;
104 	}
105 
106 	cap_ptr &= ~3;
107 	if (!cap_ptr) {
108 		TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x empty list\n", bus, device, function, cap_id);
109 		return B_NAME_NOT_FOUND;
110 	}
111 
112 	for (i = 0; i < 48; i++) {
113 		uint8 this_cap_id = pci_read_config(bus, device, function, cap_ptr, 1);
114 		if (this_cap_id == cap_id) {
115 			*offset = cap_ptr;
116 			return B_OK;
117 		}
118 
119 		cap_ptr = pci_read_config(bus, device, function, cap_ptr + 1, 1);
120 		cap_ptr &= ~3;
121 
122 		if (!cap_ptr)
123 			return B_NAME_NOT_FOUND;
124 	}
125 
126 	TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, cap_id);
127 	return B_ERROR;
128 }
129 
130 
131 // #pragma mark kernel debugger commands
132 
133 static int
134 display_io(int argc, char **argv)
135 {
136 	int32 displayWidth;
137 	int32 itemSize;
138 	int32 num = 1;
139 	int address;
140 	int i = 1, j;
141 
142 	switch (argc) {
143 	case 3:
144 		num = atoi(argv[2]);
145 	case 2:
146 		address = strtoul(argv[1], NULL, 0);
147 		break;
148 	default:
149 		kprintf("usage: %s <address> [num]\n", argv[0]);
150 		return 0;
151 	}
152 
153 	// build the format string
154 	if (strcmp(argv[0], "inb") == 0 || strcmp(argv[0], "in8") == 0) {
155 		itemSize = 1;
156 		displayWidth = 16;
157 	} else if (strcmp(argv[0], "ins") == 0 || strcmp(argv[0], "in16") == 0) {
158 		itemSize = 2;
159 		displayWidth = 8;
160 	} else if (strcmp(argv[0], "inw") == 0 || strcmp(argv[0], "in32") == 0) {
161 		itemSize = 4;
162 		displayWidth = 4;
163 	} else {
164 		kprintf("display_io called in an invalid way!\n");
165 		return 0;
166 	}
167 
168 	for (i = 0; i < num; i++) {
169 		if ((i % displayWidth) == 0) {
170 			int32 displayed = min_c(displayWidth, (num-i)) * itemSize;
171 			if (i != 0)
172 				kprintf("\n");
173 
174 			kprintf("[0x%lx]  ", address + i * itemSize);
175 
176 			if (num > displayWidth) {
177 				// make sure the spacing in the last line is correct
178 				for (j = displayed; j < displayWidth * itemSize; j++)
179 					kprintf(" ");
180 			}
181 			kprintf("  ");
182 		}
183 
184 		switch (itemSize) {
185 			case 1:
186 				kprintf(" %02x", pci_read_io_8(address + i * itemSize));
187 				break;
188 			case 2:
189 				kprintf(" %04x", pci_read_io_16(address + i * itemSize));
190 				break;
191 			case 4:
192 				kprintf(" %08lx", pci_read_io_32(address + i * itemSize));
193 				break;
194 		}
195 	}
196 
197 	kprintf("\n");
198 	return 0;
199 }
200 
201 
202 static int
203 write_io(int argc, char **argv)
204 {
205 	int32 itemSize;
206 	uint32 value;
207 	int address;
208 	int i = 1;
209 
210 	if (argc < 3) {
211 		kprintf("usage: %s <address> <value> [value [...]]\n", argv[0]);
212 		return 0;
213 	}
214 
215 	address = strtoul(argv[1], NULL, 0);
216 
217 	if (strcmp(argv[0], "outb") == 0 || strcmp(argv[0], "out8") == 0) {
218 		itemSize = 1;
219 	} else if (strcmp(argv[0], "outs") == 0 || strcmp(argv[0], "out16") == 0) {
220 		itemSize = 2;
221 	} else if (strcmp(argv[0], "outw") == 0 || strcmp(argv[0], "out32") == 0) {
222 		itemSize = 4;
223 	} else {
224 		kprintf("write_io called in an invalid way!\n");
225 		return 0;
226 	}
227 
228 	// skip cmd name and address
229 	argv += 2;
230 	argc -= 2;
231 
232 	for (i = 0; i < argc; i++) {
233 		value = strtoul(argv[i], NULL, 0);
234 		switch (itemSize) {
235 			case 1:
236 				pci_write_io_8(address + i * itemSize, value);
237 				break;
238 			case 2:
239 				pci_write_io_16(address + i * itemSize, value);
240 				break;
241 			case 4:
242 				pci_write_io_32(address + i * itemSize, value);
243 				break;
244 		}
245 	}
246 
247 	return 0;
248 }
249 
250 
251 // #pragma mark bus manager init/uninit
252 
253 status_t
254 pci_init(void)
255 {
256 	sPCI = new PCI;
257 
258 	if (pci_io_init() != B_OK) {
259 		TRACE(("PCI: pci_io_init failed\n"));
260 		return B_ERROR;
261 	}
262 
263 	add_debugger_command("inw", &display_io, "dump io words (32-bit)");
264 	add_debugger_command("in32", &display_io, "dump io words (32-bit)");
265 	add_debugger_command("ins", &display_io, "dump io shorts (16-bit)");
266 	add_debugger_command("in16", &display_io, "dump io shorts (16-bit)");
267 	add_debugger_command("inb", &display_io, "dump io bytes (8-bit)");
268 	add_debugger_command("in8", &display_io, "dump io bytes (8-bit)");
269 
270 	add_debugger_command("outw", &write_io, "write io words (32-bit)");
271 	add_debugger_command("out32", &write_io, "write io words (32-bit)");
272 	add_debugger_command("outs", &write_io, "write io shorts (16-bit)");
273 	add_debugger_command("out16", &write_io, "write io shorts (16-bit)");
274 	add_debugger_command("outb", &write_io, "write io bytes (8-bit)");
275 	add_debugger_command("out8", &write_io, "write io bytes (8-bit)");
276 
277 	if (pci_controller_init() != B_OK) {
278 		TRACE(("PCI: pci_controller_init failed\n"));
279 		return B_ERROR;
280 	}
281 
282 	sPCI->InitDomainData();
283 	sPCI->InitBus();
284 
285 	return B_OK;
286 }
287 
288 
289 void
290 pci_uninit(void)
291 {
292 	remove_debugger_command("outw", &write_io);
293 	remove_debugger_command("out32", &write_io);
294 	remove_debugger_command("outs", &write_io);
295 	remove_debugger_command("out16", &write_io);
296 	remove_debugger_command("outb", &write_io);
297 	remove_debugger_command("out8", &write_io);
298 
299 	remove_debugger_command("inw", &display_io);
300 	remove_debugger_command("in32", &display_io);
301 	remove_debugger_command("ins", &display_io);
302 	remove_debugger_command("in16", &display_io);
303 	remove_debugger_command("inb", &display_io);
304 	remove_debugger_command("in8", &display_io);
305 
306 	delete sPCI;
307 }
308 
309 
310 // #pragma mark PCI class
311 
312 PCI::PCI()
313  :	fRootBus(0)
314  ,	fDomainCount(0)
315  ,	fBusEnumeration(false)
316 {
317 	#if defined(__POWERPC__) || defined(__M68K__)
318 		fBusEnumeration = true;
319 	#endif
320 }
321 
322 
323 void
324 PCI::InitBus()
325 {
326 	PCIBus **ppnext = &fRootBus;
327 	for (int i = 0; i < fDomainCount; i++) {
328 		PCIBus *bus = new PCIBus;
329 		bus->next = NULL;
330 		bus->parent = NULL;
331 		bus->child = NULL;
332 		bus->domain = i;
333 		bus->bus = 0;
334 		*ppnext = bus;
335 		ppnext = &bus->next;
336 	}
337 
338 	if (fBusEnumeration) {
339 		for (int i = 0; i < fDomainCount; i++) {
340 			EnumerateBus(i, 0);
341 		}
342 	}
343 
344 	if (1) {
345 		for (int i = 0; i < fDomainCount; i++) {
346 			FixupDevices(i, 0);
347 		}
348 	}
349 
350 	if (fRootBus) {
351 		DiscoverBus(fRootBus);
352 		RefreshDeviceInfo(fRootBus);
353 	}
354 }
355 
356 
357 PCI::~PCI()
358 {
359 }
360 
361 
362 status_t
363 PCI::AddVirtBus(int domain, uint8 bus, uint8 *virt_bus)
364 {
365 	if (MAX_PCI_DOMAINS != 8)
366 		panic("PCI::AddVirtBus only 8 controllers supported");
367 
368 	if (domain > 7)
369 		panic("PCI::AddVirtBus domain %d too large", domain);
370 
371 	if (bus > 31)
372 		panic("PCI::AddVirtBus bus %d too large", bus);
373 
374 	*virt_bus = (domain << 5) | bus;
375 	return B_OK;
376 }
377 
378 
379 status_t
380 PCI::GetVirtBus(uint8 virt_bus, int *domain, uint8 *bus)
381 {
382 	// XXX if you modify this, also change pci_info.cpp print_info_basic() !!
383 	*domain = virt_bus >> 5;
384 	*bus = virt_bus & 0x1f;
385 	return B_OK;
386 }
387 
388 status_t
389 PCI::AddController(pci_controller *controller, void *controller_cookie)
390 {
391 	if (fDomainCount == MAX_PCI_DOMAINS)
392 		return B_ERROR;
393 
394 	fDomainData[fDomainCount].controller = controller;
395 	fDomainData[fDomainCount].controller_cookie = controller_cookie;
396 
397 	// initialized later to avoid call back into controller at this point
398 	fDomainData[fDomainCount].max_bus_devices = -1;
399 
400 	fDomainCount++;
401 	return B_OK;
402 }
403 
404 void
405 PCI::InitDomainData()
406 {
407 	for (int i = 0; i < fDomainCount; i++) {
408 		int32 count;
409 		status_t status;
410 
411 		status = (*fDomainData[i].controller->get_max_bus_devices)(fDomainData[i].controller_cookie, &count);
412 		fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0;
413 	}
414 }
415 
416 
417 domain_data *
418 PCI::GetDomainData(int domain)
419 {
420 	if (domain < 0 || domain >= fDomainCount)
421 		return NULL;
422 
423 	return &fDomainData[domain];
424 }
425 
426 
427 status_t
428 PCI::GetNthPciInfo(long index, pci_info *outInfo)
429 {
430 	long curindex = 0;
431 	if (!fRootBus)
432 		return B_ERROR;
433 	return GetNthPciInfo(fRootBus, &curindex, index, outInfo);
434 }
435 
436 
437 status_t
438 PCI::GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo)
439 {
440 	// maps tree structure to linear indexed view
441 	PCIDev *dev = bus->child;
442 	while (dev) {
443 		if (*curindex == wantindex) {
444 			*outInfo = dev->info;
445 			return B_OK;
446 		}
447 		*curindex += 1;
448 		if (dev->child && B_OK == GetNthPciInfo(dev->child, curindex, wantindex, outInfo))
449 			return B_OK;
450 		dev = dev->next;
451 	}
452 
453 	if (bus->next)
454 		return GetNthPciInfo(bus->next, curindex, wantindex, outInfo);
455 
456 	return B_ERROR;
457 }
458 
459 void
460 PCI::EnumerateBus(int domain, uint8 bus, uint8 *subordinate_bus)
461 {
462 	TRACE(("PCI: EnumerateBus: domain %u, bus %u\n", domain, bus));
463 
464 	int max_bus_devices = GetDomainData(domain)->max_bus_devices;
465 
466 	// step 1: disable all bridges on this bus
467 	for (int dev = 0; dev < max_bus_devices; dev++) {
468 		uint16 vendor_id = ReadPciConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
469 		if (vendor_id == 0xffff)
470 			continue;
471 
472 		uint8 type = ReadPciConfig(domain, bus, dev, 0, PCI_header_type, 1);
473 		int nfunc = (type & PCI_multifunction) ? 8 : 1;
474 		for (int func = 0; func < nfunc; func++) {
475 			uint16 device_id = ReadPciConfig(domain, bus, dev, func, PCI_device_id, 2);
476 			if (device_id == 0xffff)
477 				continue;
478 
479 			uint8 base_class = ReadPciConfig(domain, bus, dev, func, PCI_class_base, 1);
480 			uint8 sub_class	 = ReadPciConfig(domain, bus, dev, func, PCI_class_sub, 1);
481 			if (base_class != PCI_bridge || sub_class != PCI_pci)
482 				continue;
483 
484 			TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n", domain, bus, dev, func));
485 			TRACE(("PCI: original settings: pcicmd %04lx, primary-bus %lu, secondary-bus %lu, subordinate-bus %lu\n",
486 				ReadPciConfig(domain, bus, dev, func, PCI_command, 2),
487 				ReadPciConfig(domain, bus, dev, func, PCI_primary_bus, 1),
488 				ReadPciConfig(domain, bus, dev, func, PCI_secondary_bus, 1),
489 				ReadPciConfig(domain, bus, dev, func, PCI_subordinate_bus, 1)));
490 
491 			// disable decoding
492 			uint16 pcicmd;
493 			pcicmd = ReadPciConfig(domain, bus, dev, func, PCI_command, 2);
494 			pcicmd &= ~(PCI_command_io | PCI_command_memory | PCI_command_master);
495 			WritePciConfig(domain, bus, dev, func, PCI_command, 2, pcicmd);
496 
497 			// disable busses
498 			WritePciConfig(domain, bus, dev, func, PCI_primary_bus, 1, 0);
499 			WritePciConfig(domain, bus, dev, func, PCI_secondary_bus, 1, 0);
500 			WritePciConfig(domain, bus, dev, func, PCI_subordinate_bus, 1, 0);
501 
502 			TRACE(("PCI: disabled settings: pcicmd %04lx, primary-bus %lu, secondary-bus %lu, subordinate-bus %lu\n",
503 				ReadPciConfig(domain, bus, dev, func, PCI_command, 2),
504 				ReadPciConfig(domain, bus, dev, func, PCI_primary_bus, 1),
505 				ReadPciConfig(domain, bus, dev, func, PCI_secondary_bus, 1),
506 				ReadPciConfig(domain, bus, dev, func, PCI_subordinate_bus, 1)));
507 		}
508 	}
509 
510 	uint8 last_used_bus_number = bus;
511 
512 	// step 2: assign busses to all bridges, and enable them again
513 	for (int dev = 0; dev < max_bus_devices; dev++) {
514 		uint16 vendor_id = ReadPciConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
515 		if (vendor_id == 0xffff)
516 			continue;
517 
518 		uint8 type = ReadPciConfig(domain, bus, dev, 0, PCI_header_type, 1);
519 		int nfunc = (type & PCI_multifunction) ? 8 : 1;
520 		for (int func = 0; func < nfunc; func++) {
521 			uint16 device_id = ReadPciConfig(domain, bus, dev, func, PCI_device_id, 2);
522 			if (device_id == 0xffff)
523 				continue;
524 
525 			uint8 base_class = ReadPciConfig(domain, bus, dev, func, PCI_class_base, 1);
526 			uint8 sub_class	 = ReadPciConfig(domain, bus, dev, func, PCI_class_sub, 1);
527 			if (base_class != PCI_bridge || sub_class != PCI_pci)
528 				continue;
529 
530 			TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
531 				domain, bus, dev, func));
532 
533 			// open Scheunentor for enumerating the bus behind the bridge
534 			WritePciConfig(domain, bus, dev, func, PCI_primary_bus, 1, bus);
535 			WritePciConfig(domain, bus, dev, func, PCI_secondary_bus, 1, last_used_bus_number + 1);
536 			WritePciConfig(domain, bus, dev, func, PCI_subordinate_bus, 1, 255);
537 
538 			// enable decoding (too early here?)
539 			uint16 pcicmd;
540 			pcicmd = ReadPciConfig(domain, bus, dev, func, PCI_command, 2);
541 			pcicmd |= PCI_command_io | PCI_command_memory | PCI_command_master;
542 			WritePciConfig(domain, bus, dev, func, PCI_command, 2, pcicmd);
543 
544 			TRACE(("PCI: probing settings: pcicmd %04lx, primary-bus %lu, secondary-bus %lu, subordinate-bus %lu\n",
545 				ReadPciConfig(domain, bus, dev, func, PCI_command, 2),
546 				ReadPciConfig(domain, bus, dev, func, PCI_primary_bus, 1),
547 				ReadPciConfig(domain, bus, dev, func, PCI_secondary_bus, 1),
548 				ReadPciConfig(domain, bus, dev, func, PCI_subordinate_bus, 1)));
549 
550 			// enumerate bus
551 			EnumerateBus(domain, last_used_bus_number + 1, &last_used_bus_number);
552 
553 			// close Scheunentor
554 			WritePciConfig(domain, bus, dev, func, PCI_subordinate_bus, 1, last_used_bus_number);
555 
556 			TRACE(("PCI: configured settings: pcicmd %04lx, primary-bus %lu, secondary-bus %lu, subordinate-bus %lu\n",
557 				ReadPciConfig(domain, bus, dev, func, PCI_command, 2),
558 				ReadPciConfig(domain, bus, dev, func, PCI_primary_bus, 1),
559 				ReadPciConfig(domain, bus, dev, func, PCI_secondary_bus, 1),
560 				ReadPciConfig(domain, bus, dev, func, PCI_subordinate_bus, 1)));
561 			}
562 	}
563 	if (subordinate_bus)
564 		*subordinate_bus = last_used_bus_number;
565 
566 	TRACE(("PCI: EnumerateBus done: domain %u, bus %u, last used bus number %u\n", domain, bus, last_used_bus_number));
567 }
568 
569 
570 void
571 PCI::FixupDevices(int domain, uint8 bus)
572 {
573 	FLOW("PCI: FixupDevices domain %u, bus %u\n", domain, bus);
574 
575 	int maxBusDevices = GetDomainData(domain)->max_bus_devices;
576 
577 	for (int dev = 0; dev < maxBusDevices; dev++) {
578 		uint16 vendorId = ReadPciConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
579 		if (vendorId == 0xffff)
580 			continue;
581 
582 		uint8 type = ReadPciConfig(domain, bus, dev, 0, PCI_header_type, 1);
583 		int nfunc = (type & PCI_multifunction) ? 8 : 1;
584 		for (int func = 0; func < nfunc; func++) {
585 			uint16 deviceId = ReadPciConfig(domain, bus, dev, func, PCI_device_id, 2);
586 			if (deviceId == 0xffff)
587 				continue;
588 
589 			pci_fixup_device(this, domain, bus, dev, func);
590 
591 			uint8 base_class = ReadPciConfig(domain, bus, dev, func, PCI_class_base, 1);
592 			if (base_class != PCI_bridge)
593 				continue;
594 			uint8 sub_class	 = ReadPciConfig(domain, bus, dev, func, PCI_class_sub, 1);
595 			if (sub_class != PCI_pci)
596 				continue;
597 
598 			int busBehindBridge = ReadPciConfig(domain, bus, dev, func, PCI_secondary_bus, 1);
599 
600 			FixupDevices(domain, busBehindBridge);
601 		}
602 	}
603 }
604 
605 
606 void
607 PCI::DiscoverBus(PCIBus *bus)
608 {
609 	FLOW("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus);
610 
611 	int max_bus_devices = GetDomainData(bus->domain)->max_bus_devices;
612 
613 	for (int dev = 0; dev < max_bus_devices; dev++) {
614 		uint16 vendor_id = ReadPciConfig(bus->domain, bus->bus, dev, 0, PCI_vendor_id, 2);
615 		if (vendor_id == 0xffff)
616 			continue;
617 
618 		uint8 type = ReadPciConfig(bus->domain, bus->bus, dev, 0, PCI_header_type, 1);
619 		int nfunc = (type & PCI_multifunction) ? 8 : 1;
620 		for (int func = 0; func < nfunc; func++)
621 			DiscoverDevice(bus, dev, func);
622 	}
623 
624 	if (bus->next)
625 		DiscoverBus(bus->next);
626 }
627 
628 
629 void
630 PCI::DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func)
631 {
632 	FLOW("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, func);
633 
634 	uint16 device_id = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_device_id, 2);
635 	if (device_id == 0xffff)
636 		return;
637 
638 	PCIDev *newdev = CreateDevice(bus, dev, func);
639 
640 	uint8 base_class = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_class_base, 1);
641 	uint8 sub_class	 = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_class_sub, 1);
642 	if (base_class == PCI_bridge && sub_class == PCI_pci) {
643 		uint8 secondary_bus = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_secondary_bus, 1);
644 		PCIBus *newbus = CreateBus(newdev, bus->domain, secondary_bus);
645 		DiscoverBus(newbus);
646 	}
647 }
648 
649 
650 PCIBus *
651 PCI::CreateBus(PCIDev *parent, int domain, uint8 bus)
652 {
653 	PCIBus *newbus = new PCIBus;
654 	newbus->next = NULL;
655 	newbus->parent = parent;
656 	newbus->child = NULL;
657 	newbus->domain = domain;
658 	newbus->bus = bus;
659 
660 	// append
661 	parent->child = newbus;
662 
663 	return newbus;
664 }
665 
666 
667 PCIDev *
668 PCI::CreateDevice(PCIBus *parent, uint8 dev, uint8 func)
669 {
670 	FLOW("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain, parent->bus, dev, func);
671 
672 	PCIDev *newdev = new PCIDev;
673 	newdev->next = NULL;
674 	newdev->parent = parent;
675 	newdev->child = NULL;
676 	newdev->domain = parent->domain;
677 	newdev->bus = parent->bus;
678 	newdev->dev = dev;
679 	newdev->func = func;
680 
681 	ReadPciBasicInfo(newdev);
682 
683 	FLOW("PCI: CreateDevice, vendor 0x%04x, device 0x%04x, class_base 0x%02x, class_sub 0x%02x\n",
684 		newdev->info.vendor_id, newdev->info.device_id, newdev->info.class_base, newdev->info.class_sub);
685 
686 	// append
687 	if (parent->child == 0) {
688 		parent->child = newdev;
689 	} else {
690 		PCIDev *sub = parent->child;
691 		while (sub->next)
692 			sub = sub->next;
693 		sub->next = newdev;
694 	}
695 
696 	return newdev;
697 }
698 
699 
700 uint32
701 PCI::BarSize(uint32 bits, uint32 mask)
702 {
703 	bits &= mask;
704 	if (!bits)
705 		return 0;
706 	uint32 size = 1;
707 	while (!(bits & size))
708 		size <<= 1;
709 	return size;
710 }
711 
712 
713 void
714 PCI::GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags)
715 {
716 	uint32 oldvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
717 	WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, 0xffffffff);
718 	uint32 newvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
719 	WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
720 
721 	*address = oldvalue & PCI_address_memory_32_mask;
722 	if (size)
723 		*size = BarSize(newvalue, PCI_address_memory_32_mask);
724 	if (flags)
725 		*flags = newvalue & 0xf;
726 }
727 
728 
729 void
730 PCI::GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags)
731 {
732 	uint32 oldvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
733 	WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, 0xfffffffe); // LSB must be 0
734 	uint32 newvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
735 	WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
736 
737 	*address = oldvalue & PCI_rom_address_mask;
738 	if (size)
739 		*size = BarSize(newvalue, PCI_rom_address_mask);
740 	if (flags)
741 		*flags = newvalue & 0xf;
742 }
743 
744 
745 void
746 PCI::ReadPciBasicInfo(PCIDev *dev)
747 {
748 	uint8 virt_bus;
749 
750 	if (AddVirtBus(dev->domain, dev->bus, &virt_bus) != B_OK) {
751 		dprintf("PCI: AddVirtBus failed, domain %u, bus %u\n", dev->domain, dev->bus);
752 		return;
753 	}
754 
755 	dev->info.vendor_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_vendor_id, 2);
756 	dev->info.device_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_device_id, 2);
757 	dev->info.bus = virt_bus;
758 	dev->info.device = dev->dev;
759 	dev->info.function = dev->func;
760 	dev->info.revision = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_revision, 1);
761 	dev->info.class_api = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_api, 1);
762 	dev->info.class_sub = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_sub, 1);
763 	dev->info.class_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_base, 1);
764 	dev->info.line_size = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_line_size, 1);
765 	dev->info.latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_latency, 1);
766 	// BeOS does not mask off the multifunction bit, developer must use (header_type & PCI_header_type_mask)
767 	dev->info.header_type = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_header_type, 1);
768 	dev->info.bist = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_bist, 1);
769 	dev->info.reserved = 0;
770 }
771 
772 
773 void
774 PCI::ReadPciHeaderInfo(PCIDev *dev)
775 {
776 	switch (dev->info.header_type & PCI_header_type_mask) {
777 		case PCI_header_type_generic:
778 		{
779 			// disable PCI device address decoding (io and memory) while BARs are modified
780 			uint16 pcicmd = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2);
781 			WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
782 
783 			// get BAR size infos
784 			GetRomBarInfo(dev, PCI_rom_base, &dev->info.u.h0.rom_base_pci, &dev->info.u.h0.rom_size);
785 			for (int i = 0; i < 6; i++) {
786 				GetBarInfo(dev, PCI_base_registers + 4*i,
787 					&dev->info.u.h0.base_registers_pci[i],
788 					&dev->info.u.h0.base_register_sizes[i],
789 					&dev->info.u.h0.base_register_flags[i]);
790 			}
791 
792 			// restore PCI device address decoding
793 			WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd);
794 
795 			dev->info.u.h0.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h0.rom_base_pci);
796 			for (int i = 0; i < 6; i++) {
797 				dev->info.u.h0.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h0.base_registers_pci[i]);
798 			}
799 
800 			dev->info.u.h0.cardbus_cis = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_cardbus_cis, 4);
801 			dev->info.u.h0.subsystem_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subsystem_id, 2);
802 			dev->info.u.h0.subsystem_vendor_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subsystem_vendor_id, 2);
803 			dev->info.u.h0.interrupt_line = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1);
804 			dev->info.u.h0.interrupt_pin = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1);
805 			dev->info.u.h0.min_grant = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_min_grant, 1);
806 			dev->info.u.h0.max_latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_max_latency, 1);
807 			break;
808 		}
809 
810 		case PCI_header_type_PCI_to_PCI_bridge:
811 		{
812 			// disable PCI device address decoding (io and memory) while BARs are modified
813 			uint16 pcicmd = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2);
814 			WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
815 
816 			GetRomBarInfo(dev, PCI_bridge_rom_base, &dev->info.u.h1.rom_base_pci);
817 			for (int i = 0; i < 2; i++) {
818 				GetBarInfo(dev, PCI_base_registers + 4*i,
819 					&dev->info.u.h1.base_registers_pci[i],
820 					&dev->info.u.h1.base_register_sizes[i],
821 					&dev->info.u.h1.base_register_flags[i]);
822 			}
823 
824 			// restore PCI device address decoding
825 			WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd);
826 
827 			dev->info.u.h1.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h1.rom_base_pci);
828 			for (int i = 0; i < 2; i++) {
829 				dev->info.u.h1.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h1.base_registers_pci[i]);
830 			}
831 
832 			dev->info.u.h1.primary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_primary_bus, 1);
833 			dev->info.u.h1.secondary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_bus, 1);
834 			dev->info.u.h1.subordinate_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subordinate_bus, 1);
835 			dev->info.u.h1.secondary_latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_latency, 1);
836 			dev->info.u.h1.io_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base, 1);
837 			dev->info.u.h1.io_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit, 1);
838 			dev->info.u.h1.secondary_status = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_status, 2);
839 			dev->info.u.h1.memory_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_base, 2);
840 			dev->info.u.h1.memory_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit, 2);
841 			dev->info.u.h1.prefetchable_memory_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base, 2);
842 			dev->info.u.h1.prefetchable_memory_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit, 2);
843 			dev->info.u.h1.prefetchable_memory_base_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base_upper32, 4);
844 			dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit_upper32, 4);
845 			dev->info.u.h1.io_base_upper16 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base_upper16, 2);
846 			dev->info.u.h1.io_limit_upper16 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit_upper16, 2);
847 			dev->info.u.h1.interrupt_line = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1);
848 			dev->info.u.h1.interrupt_pin = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1);
849 			dev->info.u.h1.bridge_control = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_bridge_control, 2);
850 			dev->info.u.h1.subsystem_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_device_id_1, 2);
851 			dev->info.u.h1.subsystem_vendor_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_vendor_id_1, 2);
852 			break;
853 		}
854 
855 		case PCI_header_type_cardbus:
856 		{
857 			// for testing only, not final:
858 			dev->info.u.h2.subsystem_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_device_id_2, 2);
859 			dev->info.u.h2.subsystem_vendor_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_vendor_id_2, 2);
860 			dev->info.u.h2.primary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_primary_bus_2, 1);
861 			dev->info.u.h2.secondary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_bus_2, 1);
862 			dev->info.u.h2.subordinate_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subordinate_bus_2, 1);
863 			dev->info.u.h2.secondary_latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_latency_2, 1);
864 			dev->info.u.h2.reserved = 0;
865 			dev->info.u.h2.memory_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_base0_2, 4);
866 			dev->info.u.h2.memory_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit0_2, 4);
867 			dev->info.u.h2.memory_base_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_base1_2, 4);
868 			dev->info.u.h2.memory_limit_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit1_2, 4);
869 			dev->info.u.h2.io_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base0_2, 4);
870 			dev->info.u.h2.io_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit0_2, 4);
871 			dev->info.u.h2.io_base_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base1_2, 4);
872 			dev->info.u.h2.io_limit_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit1_2, 4);
873 			dev->info.u.h2.secondary_status = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_status_2, 2);
874 			dev->info.u.h2.bridge_control = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_bridge_control_2, 1);
875 			break;
876 		}
877 
878 		default:
879 			TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type));
880 			break;
881 	}
882 }
883 
884 
885 void
886 PCI::RefreshDeviceInfo(PCIBus *bus)
887 {
888 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
889 		ReadPciBasicInfo(dev);
890 		ReadPciHeaderInfo(dev);
891 		if (dev->child)
892 			RefreshDeviceInfo(dev->child);
893 	}
894 
895 	if (bus->next)
896 		RefreshDeviceInfo(bus->next);
897 }
898 
899 
900 status_t
901 PCI::ReadPciConfig(int domain, uint8 bus, uint8 device, uint8 function,
902 				   uint8 offset, uint8 size, uint32 *value)
903 {
904 	domain_data *info;
905 	info = GetDomainData(domain);
906 	if (!info)
907 		return B_ERROR;
908 
909 	if (device > (info->max_bus_devices - 1)
910 		|| function > 7
911 		|| (size != 1 && size != 2 && size != 4)
912 		|| (size == 2 && (offset & 3) == 3)
913 		|| (size == 4 && (offset & 3) != 0)) {
914 		dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
915 			 domain, bus, device, function, offset, size);
916 		return B_ERROR;
917 	}
918 
919 	status_t status;
920 	status = (*info->controller->read_pci_config)(info->controller_cookie,
921 												  bus, device, function,
922 												  offset, size, value);
923 	return status;
924 }
925 
926 
927 uint32
928 PCI::ReadPciConfig(int domain, uint8 bus, uint8 device, uint8 function,
929 				   uint8 offset, uint8 size)
930 {
931 	uint32 value;
932 
933 	if (ReadPciConfig(domain, bus, device, function, offset, size, &value) != B_OK)
934 		return 0xffffffff;
935 
936 	return value;
937 }
938 
939 
940 status_t
941 PCI::WritePciConfig(int domain, uint8 bus, uint8 device, uint8 function,
942 					uint8 offset, uint8 size, uint32 value)
943 {
944 	domain_data *info;
945 	info = GetDomainData(domain);
946 	if (!info)
947 		return B_ERROR;
948 
949 	if (device > (info->max_bus_devices - 1)
950 		|| function > 7
951 		|| (size != 1 && size != 2 && size != 4)
952 		|| (size == 2 && (offset & 3) == 3)
953 		|| (size == 4 && (offset & 3) != 0)) {
954 		dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
955 			 domain, bus, device, function, offset, size);
956 		return B_ERROR;
957 	}
958 
959 	status_t status;
960 	status = (*info->controller->write_pci_config)(info->controller_cookie,
961 												   bus, device, function,
962 												   offset, size, value);
963 	return status;
964 }
965 
966