1/*
2 * Copyright 2003-2006, Marcus Overhagen. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <KernelExport.h>
8#define __HAIKU_PCI_BUS_MANAGER_TESTING 1
9#include <PCI.h>
10#include <string.h>
11#include "pci_info.h"
12#include "pci_private.h"
13#include "pci.h"
14
15#define PCI_VERBOSE	1
16#if defined(__i386__) || defined(__x86_64__)
17// enabling it makes the pci bus_manager binary about 1MB
18// some other platforms have issues with floppy image size...
19// TODO: Move this define to BuildSetup?
20#define USE_PCI_HEADER 1
21#endif
22
23#if USE_PCI_HEADER
24#	include "pcihdr.h"
25#	include "pci-utils.h"
26#endif
27
28const char *get_capability_name(uint8 cap_id);
29const char *get_extended_capability_name(uint16 cap_id);
30
31
32static void
33print_pci2pci_bridge_info(const pci_info *info, bool verbose)
34{
35	TRACE(("PCI:   subsystem_id %04x, subsystem_vendor_id %04x\n",
36		info->u.h1.subsystem_id, info->u.h1.subsystem_vendor_id));
37	TRACE(("PCI:   primary_bus %02x, secondary_bus %02x, subordinate_bus %02x,"
38		" secondary_latency %02x\n", info->u.h1.primary_bus,
39		info->u.h1.secondary_bus, info->u.h1.subordinate_bus, info->u.h1.secondary_latency));
40	uint32 io_base = ((uint32)info->u.h1.io_base & 0xf0) << 8;
41	if (info->u.h1.io_base & 1)
42		 io_base += ((uint32)info->u.h1.io_base_upper16 << 16);
43	uint32 io_limit = (((uint32)info->u.h1.io_limit & 0xf0) << 8) + 0xfff;
44	if (info->u.h1.io_limit & 1)
45		 io_limit += info->u.h1.io_limit_upper16 << 16;
46	TRACE(("PCI:   I/O window %04" B_PRIx32 "-%04" B_PRIx32 "\n", io_base,
47		io_limit));
48	uint32 memory_base = ((uint32)info->u.h1.memory_base & 0xfff0) << 16;
49	uint32 memory_limit = (((uint32)info->u.h1.memory_limit & 0xfff0) << 16)
50		+ 0xfffff;
51	TRACE(("PCI:   memory window %08" B_PRIx32 "-%08" B_PRIx32 "\n",
52		memory_base, memory_limit));
53	uint64 prefetchable_memory_base =
54		((uint32)info->u.h1.prefetchable_memory_base & 0xfff0) << 16;
55	if (info->u.h1.prefetchable_memory_base & 1) {
56		prefetchable_memory_base +=
57			(uint64)info->u.h1.prefetchable_memory_base_upper32 << 32;
58	}
59	uint64 prefetchable_memory_limit =
60		(((uint32)info->u.h1.prefetchable_memory_limit & 0xfff0) << 16)
61		+ 0xfffff;
62	if (info->u.h1.prefetchable_memory_limit & 1) {
63		prefetchable_memory_limit +=
64			(uint64)info->u.h1.prefetchable_memory_limit_upper32 << 32;
65	}
66	TRACE(("PCI:   prefetchable memory window %016" B_PRIx64 "-%016" B_PRIx64 "\n",
67		prefetchable_memory_base, prefetchable_memory_limit));
68	TRACE(("PCI:   bridge_control %04x, secondary_status %04x\n",
69			info->u.h1.bridge_control, info->u.h1.secondary_status));
70	TRACE(("PCI:   interrupt_line %02x, interrupt_pin %02x\n",
71			info->u.h1.interrupt_line, info->u.h1.interrupt_pin));
72	TRACE(("PCI:   ROM base host %08" B_PRIx32 ", pci %08" B_PRIx32 ", size ??\n",
73			info->u.h1.rom_base, info->u.h1.rom_base_pci));
74	for (int i = 0; i < 2; i++)
75		TRACE(("PCI:   base reg %d: host %08" B_PRIx32 ", pci %08" B_PRIx32 ", "
76			"size %08" B_PRIx32 ", flags %02x\n", i, info->u.h1.base_registers[i],
77			info->u.h1.base_registers_pci[i], info->u.h1.base_register_sizes[i],
78			info->u.h1.base_register_flags[i]));
79}
80
81
82static void
83print_pci2cardbus_bridge_info(const pci_info *info, bool verbose)
84{
85	TRACE(("PCI:   subsystem_id %04x, subsystem_vendor_id %04x\n",
86		info->u.h2.subsystem_id, info->u.h2.subsystem_vendor_id));
87	TRACE(("PCI:   primary_bus %02x, secondary_bus %02x, subordinate_bus %02x, "
88		"secondary_latency %02x\n", info->u.h2.primary_bus,
89		info->u.h2.secondary_bus, info->u.h2.subordinate_bus,
90		info->u.h2.secondary_latency));
91	TRACE(("PCI:   bridge_control %04x, secondary_status %04x\n",
92		info->u.h2.bridge_control, info->u.h2.secondary_status));
93	TRACE(("PCI:   memory_base_upper32  %08" B_PRIx32 ", memory_base  %08"
94		B_PRIx32 "\n", info->u.h2.memory_base_upper32, info->u.h2.memory_base));
95	TRACE(("PCI:   memory_limit_upper32 %08" B_PRIx32 ", memory_limit %08"
96		B_PRIx32 "\n", info->u.h2.memory_limit_upper32, info->u.h2.memory_limit));
97	TRACE(("PCI:   io_base_upper32  %08" B_PRIx32 ", io_base  %08" B_PRIx32 "\n",
98		info->u.h2.io_base_upper32, info->u.h2.io_base));
99	TRACE(("PCI:   io_limit_upper32 %08" B_PRIx32 ", io_limit %08" B_PRIx32 "\n",
100		info->u.h2.io_limit_upper32, info->u.h2.io_limit));
101}
102
103
104static void
105print_generic_info(const pci_info *info, bool verbose)
106{
107	TRACE(("PCI:   ROM base host %08" B_PRIx32 ", pci %08" B_PRIx32 ", size "
108		"%08" B_PRIx32 "\n", info->u.h0.rom_base, info->u.h0.rom_base_pci,
109		info->u.h0.rom_size));
110	TRACE(("PCI:   cardbus_CIS %08" B_PRIx32 ", subsystem_id %04x, "
111		"subsystem_vendor_id %04x\n", info->u.h0.cardbus_cis,
112		info->u.h0.subsystem_id, info->u.h0.subsystem_vendor_id));
113	TRACE(("PCI:   interrupt_line %02x, interrupt_pin %02x, min_grant %02x, "
114		"max_latency %02x\n", info->u.h0.interrupt_line, info->u.h0.interrupt_pin,
115		info->u.h0.min_grant, info->u.h0.max_latency));
116	for (int i = 0; i < 6; i++) {
117		if ((info->u.h0.base_register_flags[i] & PCI_address_type) == PCI_address_type_64) {
118			TRACE(("PCI:   base reg %d: host %016" B_PRIx64 ", pci %016" B_PRIx64 ", "
119				"size %08" B_PRIx64 ", flags %02x %02x\n", i,
120				info->u.h0.base_registers[i] | ((uint64)info->u.h0.base_registers[i + 1] << 32),
121				info->u.h0.base_registers_pci[i] | ((uint64)info->u.h0.base_registers_pci[i + 1] << 32),
122				info->u.h0.base_register_sizes[i] | ((uint64)info->u.h0.base_register_sizes[i + 1] << 32),
123				info->u.h0.base_register_flags[i], info->u.h0.base_register_flags[i + 1]));
124			i++;
125		} else {
126			TRACE(("PCI:   base reg %d: host %08" B_PRIx32 ", pci %08" B_PRIx32 ", "
127				"size %08" B_PRIx32 ", flags %02x\n", i, info->u.h0.base_registers[i],
128				info->u.h0.base_registers_pci[i], info->u.h0.base_register_sizes[i],
129				info->u.h0.base_register_flags[i]));
130		}
131	}
132}
133
134
135static void
136print_capabilities(const pci_info *info)
137{
138	uint16	status;
139	uint8	cap_ptr;
140	uint8	cap_id;
141	int		i;
142
143	TRACE(("PCI:   Capabilities: "));
144
145	status = pci_read_config(info->bus, info->device, info->function, PCI_status, 2);
146	if (!(status & PCI_status_capabilities)) {
147		TRACE(("(not supported)\n"));
148		return;
149	}
150
151	switch (info->header_type & PCI_header_type_mask) {
152		case PCI_header_type_generic:
153		case PCI_header_type_PCI_to_PCI_bridge:
154			cap_ptr = pci_read_config(info->bus, info->device, info->function, PCI_capabilities_ptr, 1);
155			break;
156		case PCI_header_type_cardbus:
157			cap_ptr = pci_read_config(info->bus, info->device, info->function, PCI_capabilities_ptr_2, 1);
158			break;
159		default:
160			TRACE(("(unknown header type)\n"));
161			return;
162	}
163
164	cap_ptr &= ~3;
165	if (!cap_ptr) {
166		TRACE(("(empty list)\n"));
167		return;
168	}
169
170	for (i = 0; i < 48; i++) {
171		const char *name;
172		cap_id  = pci_read_config(info->bus, info->device, info->function, cap_ptr, 1);
173		cap_ptr = pci_read_config(info->bus, info->device, info->function, cap_ptr + 1, 1);
174		cap_ptr &= ~3;
175		if (i) {
176			TRACE((", "));
177		}
178		name = get_capability_name(cap_id);
179		if (name) {
180			TRACE(("%s", name));
181		} else {
182			TRACE(("0x%02x", cap_id));
183		}
184		if (!cap_ptr)
185			break;
186	}
187	TRACE(("\n"));
188}
189
190
191static void
192print_extended_capabilities(const pci_info *info)
193{
194	if (pci_find_capability(info->bus, info->device, info->function,
195			PCI_cap_id_pcie, NULL) != B_OK)
196		return;
197
198	uint16 capPointer = PCI_extended_capability;
199	uint32 capability = pci_read_config(info->bus, info->device,
200		info->function, capPointer, 4);
201	TRACE(("PCI:   Extended capabilities: "));
202	if (capability == 0 || capability == 0xffffffff) {
203		TRACE(("(empty list)\n"));
204		return;
205	}
206
207	for (int i = 0; i < 48; i++) {
208		if (i) {
209			TRACE((", "));
210		}
211		const char *name = get_extended_capability_name(
212			PCI_extcap_id(capability));
213		if (name) {
214			TRACE(("%s", name));
215		} else {
216			TRACE(("0x%04" B_PRIx32, PCI_extcap_id(capability)));
217		}
218
219		capPointer = PCI_extcap_next_ptr(capability) & ~3;
220		if (capPointer < PCI_extended_capability)
221			break;
222		capability = pci_read_config(info->bus, info->device, info->function,
223			capPointer, 4);
224	}
225
226	TRACE(("\n"));
227}
228
229
230static void
231print_info_basic(const pci_info *info, bool verbose)
232{
233	uint8 domain;
234	uint8 bus;
235
236	__pci_resolve_virtual_bus(info->bus, &domain, &bus);
237
238	TRACE(("PCI: [dom %d, bus %2d] bus %3d, device %2d, function %2d: vendor %04x, device %04x, revision %02x\n",
239			domain, bus, info->bus /* virtual bus*/,
240			info->device, info->function, info->vendor_id, info->device_id, info->revision));
241	TRACE(("PCI:   class_base %02x, class_function %02x, class_api %02x\n",
242			info->class_base, info->class_sub, info->class_api));
243
244	if (verbose) {
245#if USE_PCI_HEADER
246		const char *venShort;
247		const char *venFull;
248		get_vendor_info(info->vendor_id, &venShort, &venFull);
249		if (!venShort && !venFull) {
250			TRACE(("PCI:   vendor %04x: Unknown\n", info->vendor_id));
251		} else if (venShort && venFull) {
252			TRACE(("PCI:   vendor %04x: %s - %s\n", info->vendor_id, venShort, venFull));
253		} else {
254			TRACE(("PCI:   vendor %04x: %s\n", info->vendor_id, venShort ? venShort : venFull));
255		}
256		const char *devShort;
257		const char *devFull;
258		get_device_info(info->vendor_id, info->device_id, info->u.h0.subsystem_vendor_id, info->u.h0.subsystem_id,
259			&devShort, &devFull);
260		if (!devShort && !devFull) {
261			TRACE(("PCI:   device %04x: Unknown\n", info->device_id));
262		} else if (devShort && devFull) {
263			TRACE(("PCI:   device %04x: %s (%s)\n", info->device_id, devShort, devFull));
264		} else {
265			TRACE(("PCI:   device %04x: %s\n", info->device_id, devShort ? devShort : devFull));
266		}
267		char classInfo[128];
268		get_class_info(info->class_base, info->class_sub, info->class_api, classInfo, sizeof(classInfo));
269		TRACE(("PCI:   info: %s\n", classInfo));
270#endif
271	}
272	TRACE(("PCI:   line_size %02x, latency %02x, header_type %02x, BIST %02x\n",
273			info->line_size, info->latency, info->header_type, info->bist));
274
275	switch (info->header_type & PCI_header_type_mask) {
276		case PCI_header_type_generic:
277			print_generic_info(info, verbose);
278			break;
279		case PCI_header_type_PCI_to_PCI_bridge:
280			print_pci2pci_bridge_info(info, verbose);
281			break;
282		case PCI_header_type_cardbus:
283			print_pci2cardbus_bridge_info(info, verbose);
284			break;
285		default:
286			TRACE(("PCI:   unknown header type\n"));
287	}
288
289	print_capabilities(info);
290	print_extended_capabilities(info);
291}
292
293
294void
295pci_print_info()
296{
297	pci_info info;
298	for (long index = 0; B_OK == pci_get_nth_pci_info(index, &info); index++) {
299		print_info_basic(&info, PCI_VERBOSE);
300	}
301}
302
303
304const char *
305get_capability_name(uint8 cap_id)
306{
307	switch (cap_id) {
308		case PCI_cap_id_reserved:
309			return "reserved";
310		case PCI_cap_id_pm:
311			return "PM";
312		case PCI_cap_id_agp:
313			return "AGP";
314		case PCI_cap_id_vpd:
315			return "VPD";
316		case PCI_cap_id_slotid:
317			return "SlotID";
318		case PCI_cap_id_msi:
319			return "MSI";
320		case PCI_cap_id_chswp:
321			return "CompactPCIHotSwap";
322		case PCI_cap_id_pcix:
323			return "PCI-X";
324		case PCI_cap_id_ht:
325			return "HyperTransport";
326		case PCI_cap_id_vendspec:
327			return "vendspec";
328		case PCI_cap_id_debugport:
329			return "DebugPort";
330		case PCI_cap_id_cpci_rsrcctl:
331			return "cpci_rsrcctl";
332		case PCI_cap_id_hotplug:
333			return "HotPlug";
334		case PCI_cap_id_subvendor:
335			return "subvendor";
336		case PCI_cap_id_agp8x:
337			return "AGP8x";
338		case PCI_cap_id_secure_dev:
339			return "Secure Device";
340		case PCI_cap_id_pcie:
341			return "PCIe";
342		case PCI_cap_id_msix:
343			return "MSI-X";
344		case PCI_cap_id_sata:
345			return "SATA";
346		case PCI_cap_id_pciaf:
347			return "AdvancedFeatures";
348		default:
349			return NULL;
350	}
351}
352
353
354const char *
355get_extended_capability_name(uint16 cap_id)
356{
357	switch (cap_id) {
358		case PCI_extcap_id_aer:
359			return "Advanced Error Reporting";
360		case PCI_extcap_id_vc:
361			return "Virtual Channel";
362		case PCI_extcap_id_serial:
363			return "Serial Number";
364		case PCI_extcap_id_power_budget:
365			return "Power Budgeting";
366		case PCI_extcap_id_rcl_decl:
367			return "Root Complex Link Declaration";
368		case PCI_extcap_id_rcil_ctl:
369			return "Root Complex Internal Link Control";
370		case PCI_extcap_id_rcec_assoc:
371			return "Root Complex Event Collector Association";
372		case PCI_extcap_id_mfvc:
373			return "MultiFunction Virtual Channel";
374		case PCI_extcap_id_vc2:
375			return "Virtual Channel 2";
376		case PCI_extcap_id_rcrb_header:
377			return "RCRB Header";
378		case PCI_extcap_id_vendor:
379			return "Vendor Unique";
380		case PCI_extcap_id_acs:
381			return "Access Control Services";
382		case PCI_extcap_id_ari:
383			return "Alternative Routing Id Interpretation";
384		case PCI_extcap_id_ats:
385			return "Address Translation Services";
386		case PCI_extcap_id_srio_virtual:
387			return "Single Root I/O Virtualization";
388		case PCI_extcap_id_mrio_virtual:
389			return "Multiple Root I/O Virtual";
390		case PCI_extcap_id_multicast:
391			return "Multicast";
392		case PCI_extcap_id_page_request:
393			return "Page Request";
394		case PCI_extcap_id_amd:
395			return "AMD Reserved";
396		case PCI_extcap_id_resizable_bar:
397			return "Resizable Bar";
398		case PCI_extcap_id_dyn_power_alloc:
399			return "Dynamic Power Allocation";
400		case PCI_extcap_id_tph_requester:
401			return "TPH Requester";
402		case PCI_extcap_id_latency_tolerance:
403			return "Latency Tolerance Reporting";
404		case PCI_extcap_id_2ndpcie:
405			return "Secondary PCIe";
406		case PCI_extcap_id_pmux:
407			return "Protocol Multiplexing";
408		case PCI_extcap_id_pasid:
409			return "Process Address Space Id";
410		case PCI_extcap_id_ln_requester:
411			return "LN Requester";
412		case PCI_extcap_id_dpc:
413			return "Downstream Porto Containment";
414		case PCI_extcap_id_l1pm:
415			return "L1 Power Management Substates";
416		case PCI_extcap_id_ptm:
417			return "Precision Time Measurement";
418		case PCI_extcap_id_m_pcie:
419			return "PCIe over M-PHY";
420		case PCI_extcap_id_frs:
421			return "FRS Queuing";
422		case PCI_extcap_id_rtr:
423			return "Readiness Time Reporting";
424		case PCI_extcap_id_dvsec:
425			return "Designated Vendor-Specific";
426		case PCI_extcap_id_vf_resizable_bar:
427			return "VF Resizable BAR";
428		case PCI_extcap_id_datalink:
429			return "Data Link Feature";
430		case PCI_extcap_id_16gt:
431			return "Physical Layer 16.0 GT/s";
432		case PCI_extcap_id_lmr:
433			return "Lane Marging at the Receiver";
434		case PCI_extcap_id_hierarchy_id:
435			return "Hierarchy ID";
436		case PCI_extcap_id_npem:
437			return "Native PCIe Enclosure Management";
438		case PCI_extcap_id_pl32:
439			return "Physical Layer 32.0 GT/s";
440		case PCI_extcap_id_ap:
441			return "Alternate Protocol";
442		case PCI_extcap_id_sfi:
443			return "System Firmware Intermediary";
444		case PCI_extcap_id_sf:
445			return "Shadow Functions";
446		case PCI_extcap_id_doe:
447			return "Data Object Exchange";
448
449		default:
450			return NULL;
451	}
452}
453
454