1/*
2 * Copyright 2003-2008, Marcus Overhagen. All rights reserved.
3 * Copyright 2005-2008, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7#ifndef __PCI_H__
8#define __PCI_H__
9
10#include <bus/PCI.h>
11
12#include <VectorMap.h>
13
14#include "pci_msi.h"
15
16
17#define TRACE_PCI
18#ifndef TRACE_PCI
19#	define TRACE(x)
20#else
21#	define TRACE(x) dprintf x
22#endif
23
24struct PCIDev;
25
26struct PCIBus {
27	PCIDev *			parent;
28	PCIDev *			child;
29	uint8				domain;
30	uint8				bus;
31};
32
33struct PCIDev {
34	PCIDev *			next;
35	PCIBus *			parent;
36	PCIBus *			child;
37	uint8				domain;
38	uint8				bus;
39	uint8				device;
40	uint8				function;
41	pci_info			info;
42
43	msi_info			msi;
44	msix_info			msix;
45	ht_mapping_info		ht_mapping;
46};
47
48
49struct domain_data {
50	~domain_data()
51	{
52#if !(defined(__i386__) || defined(__x86_64__))
53		if (io_port_area >= 0)
54			delete_area(io_port_area);
55#endif
56	}
57
58	// These two are set in PCI::AddController:
59	pci_controller_module_info *controller;
60	void *				controller_cookie;
61	device_node *		root_node;
62	PCIBus *			bus;
63
64	// All the rest is set in PCI::InitDomainData
65	int					max_bus_devices;
66	Vector<pci_resource_range> ranges;
67
68#if !(defined(__i386__) || defined(__x86_64__))
69	area_id				io_port_area = -1;
70	uint8 *				io_port_adr = NULL;
71#endif
72};
73
74
75class PCI {
76public:
77							PCI();
78							~PCI();
79
80			void			InitDomainData(domain_data &data);
81			void			InitBus(PCIBus *bus);
82
83			status_t		AddController(pci_controller_module_info *controller,
84								void *controllerCookie, device_node *rootNode,
85								domain_data **domainData);
86
87			status_t		LookupRange(uint32 type, phys_addr_t pciAddr,
88								uint8 &domain, pci_resource_range &range, uint8 **mappedAdr = NULL);
89
90			status_t		GetNthInfo(long index, pci_info *outInfo);
91
92			status_t		ReadConfig(uint8 domain, uint8 bus, uint8 device,
93								uint8 function, uint16 offset, uint8 size,
94								uint32 *value);
95			uint32			ReadConfig(uint8 domain, uint8 bus, uint8 device,
96								uint8 function, uint16 offset, uint8 size);
97			uint32			ReadConfig(PCIDev *device, uint16 offset,
98								uint8 size);
99
100			status_t		WriteConfig(uint8 domain, uint8 bus, uint8 device,
101								uint8 function, uint16 offset, uint8 size,
102								uint32 value);
103			status_t		WriteConfig(PCIDev *device, uint16 offset,
104								uint8 size, uint32 value);
105
106			status_t		FindCapability(uint8 domain, uint8 bus,
107								uint8 device, uint8 function, uint8 capID,
108								uint8 *offset = NULL);
109			status_t		FindCapability(PCIDev *device, uint8 capID,
110								uint8 *offset = NULL);
111			status_t		FindExtendedCapability(uint8 domain, uint8 bus,
112								uint8 device, uint8 function, uint16 capID,
113								uint16 *offset = NULL);
114			status_t		FindExtendedCapability(PCIDev *device,
115								uint16 capID, uint16 *offset = NULL);
116			status_t		FindHTCapability(uint8 domain, uint8 bus,
117								uint8 device, uint8 function, uint16 capID,
118								uint8 *offset);
119			status_t		FindHTCapability(PCIDev *device,
120								uint16 capID, uint8 *offset = NULL);
121
122			status_t		ResolveVirtualBus(uint8 virtualBus, uint8 *domain,
123								uint8 *bus);
124
125			PCIDev *		FindDevice(uint8 domain, uint8 bus, uint8 device,
126								uint8 function);
127
128			void			ClearDeviceStatus(PCIBus *bus, bool dumpStatus);
129
130			uint8			GetPowerstate(PCIDev *device);
131			status_t		GetPowerstate(uint8 domain, uint8 bus, uint8 device,
132								uint8 function, uint8* state);
133			void			SetPowerstate(PCIDev *device, uint8 state);
134			status_t		SetPowerstate(uint8 domain, uint8 bus, uint8 device,
135								uint8 function, uint8 newState);
136
137			void			RefreshDeviceInfo();
138
139			status_t		UpdateInterruptLine(uint8 domain, uint8 bus,
140								uint8 device, uint8 function,
141								uint8 newInterruptLineValue);
142
143			uint32			GetMSICount(PCIDev *device);
144			status_t		ConfigureMSI(PCIDev *device, uint32 count, uint32 *startVector);
145			status_t		UnconfigureMSI(PCIDev *device);
146			status_t		EnableMSI(PCIDev *device);
147			status_t		DisableMSI(PCIDev *device);
148			uint32			GetMSIXCount(PCIDev *device);
149			status_t		ConfigureMSIX(PCIDev *device, uint32 count, uint32 *startVector);
150			status_t		EnableMSIX(PCIDev *device);
151
152private:
153			void			_EnumerateBus(uint8 domain, uint8 bus,
154								uint8 *subordinateBus = NULL);
155
156			void			_FixupDevices(uint8 domain, uint8 bus);
157
158			void			_DiscoverBus(PCIBus *bus);
159			void			_DiscoverDevice(PCIBus *bus, uint8 dev,
160								uint8 function);
161
162			PCIDev *		_CreateDevice(PCIBus *parent, uint8 dev,
163								uint8 function);
164			PCIBus *		_CreateBus(PCIDev *parent, uint8 domain,
165								uint8 bus);
166
167			status_t		_GetNthInfo(PCIBus *bus, long *currentIndex,
168								long wantIndex, pci_info *outInfo);
169			void			_ReadBasicInfo(PCIDev *dev);
170			void			_ReadHeaderInfo(PCIDev *dev);
171
172			void			_ConfigureBridges(PCIBus *bus);
173			void			_RefreshDeviceInfo(PCIBus *bus);
174
175			uint64			_BarSize(uint64 bits);
176			size_t			_GetBarInfo(PCIDev *dev, uint8 offset,
177								uint32 &ramAddress, uint32 &pciAddress,
178								uint32 &size, uint8 &flags,
179								uint32 *highRAMAddress = NULL,
180								uint32 *highPCIAddress = NULL,
181								uint32 *highSize = NULL);
182			void			_GetRomBarInfo(PCIDev *dev, uint8 offset,
183								uint32 &address, uint32 *size = NULL,
184								uint8 *flags = NULL);
185
186public:
187			domain_data *	_GetDomainData(uint8 domain);
188
189private:
190			status_t		_CreateVirtualBus(uint8 domain, uint8 bus,
191								uint8 *virtualBus);
192
193			int				_NumFunctions(uint8 domain, uint8 bus,
194								uint8 device);
195			PCIDev *		_FindDevice(PCIBus *current, uint8 domain,
196								uint8 bus, uint8 device, uint8 function);
197
198			void			_HtMSIMap(PCIDev *device, uint64 address);
199			void			_ReadMSIInfo(PCIDev *device);
200			void			_ReadMSIXInfo(PCIDev *device);
201			void			_ReadHtMappingInfo(PCIDev *device);
202			status_t		_UnconfigureMSIX(PCIDev *device);
203			status_t		_DisableMSIX(PCIDev *device);
204
205private:
206	enum { MAX_PCI_DOMAINS = 8 };
207
208	domain_data				fDomainData[MAX_PCI_DOMAINS];
209	uint8					fDomainCount;
210	bool					fBusEnumeration;
211
212	typedef VectorMap<uint8, uint16> VirtualBusMap;
213
214	VirtualBusMap			fVirtualBusMap;
215	int						fNextVirtualBus;
216};
217
218extern PCI *gPCI;
219
220
221extern "C" {
222
223status_t	pci_init(void);
224status_t	pci_init_deferred(void);
225void		pci_uninit(void);
226
227long		pci_get_nth_pci_info(long index, pci_info *outInfo);
228
229uint32		pci_read_config(uint8 virtualBus, uint8 device, uint8 function,
230				uint16 offset, uint8 size);
231void		pci_write_config(uint8 virtualBus, uint8 device, uint8 function,
232				uint16 offset, uint8 size, uint32 value);
233
234void		__pci_resolve_virtual_bus(uint8 virtualBus, uint8 *domain, uint8 *bus);
235
236}
237
238#endif	/* __PCI_H__ */
239