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