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