1 
2 #include <stdbool.h>
3 #include <stdint.h>
4 
5 #include <sys/kassert.h>
6 #include <sys/kdebug.h>
7 #include <sys/pci.h>
8 
9 static void PCIScan();
10 
11 // Platform functions
12 uint8_t PCICfgRead8(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg);
13 uint16_t PCICfgRead16(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg);
14 uint32_t PCICfgRead32(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg);
15 void PCICfgWrite8(uint32_t bus, uint32_t slot, uint32_t func,
16                   uint32_t reg, uint8_t data);
17 void PCICfgWrite16(uint32_t bus, uint32_t slot, uint32_t func,
18                   uint32_t reg, uint16_t data);
19 void PCICfgWrite32(uint32_t bus, uint32_t slot, uint32_t func,
20                   uint32_t reg, uint32_t data);
21 
22 // Supported Devices
23 void AHCI_Init(uint32_t bus, uint32_t device, uint32_t func);
24 void E1000_Init(uint32_t bus, uint32_t device, uint32_t func);
25 
26 void
PCI_Init()27 PCI_Init()
28 {
29     kprintf("PCI: Initializing ...\n");
30     PCIScan();
31     kprintf("PCI: Initialization Done!\n");
32 }
33 
34 uint16_t
PCIGetDeviceID(uint32_t bus,uint32_t device,uint32_t func)35 PCIGetDeviceID(uint32_t bus, uint32_t device, uint32_t func)
36 {
37     return PCICfgRead16(bus, device, func, PCI_OFFSET_DEVICEID);
38 }
39 
40 uint16_t
PCIGetVendorID(uint32_t bus,uint32_t device,uint32_t func)41 PCIGetVendorID(uint32_t bus, uint32_t device, uint32_t func)
42 {
43     return PCICfgRead16(bus, device, func, PCI_OFFSET_VENDORID);
44 }
45 
46 uint8_t
PCIGetBaseClass(uint32_t bus,uint32_t device,uint32_t func)47 PCIGetBaseClass(uint32_t bus, uint32_t device, uint32_t func)
48 {
49     return PCICfgRead8(bus, device, func, PCI_OFFSET_CLASS);
50 }
51 
52 uint8_t
PCIGetSubClass(uint32_t bus,uint32_t device,uint32_t func)53 PCIGetSubClass(uint32_t bus, uint32_t device, uint32_t func)
54 {
55     return PCICfgRead8(bus, device, func, PCI_OFFSET_SUBCLASS);
56 }
57 
58 uint8_t
PCIGetHeaderType(uint32_t bus,uint32_t device,uint32_t func)59 PCIGetHeaderType(uint32_t bus, uint32_t device, uint32_t func)
60 {
61     return PCICfgRead8(bus, device, func, PCI_OFFSET_HEADERTYPE);
62 }
63 
64 uint8_t
PCI_CfgRead8(PCIDevice * dev,uint32_t reg)65 PCI_CfgRead8(PCIDevice *dev, uint32_t reg)
66 {
67     return PCICfgRead8(dev->bus, dev->slot, dev->func, reg);
68 }
69 
70 uint16_t
PCI_CfgRead16(PCIDevice * dev,uint32_t reg)71 PCI_CfgRead16(PCIDevice *dev, uint32_t reg)
72 {
73     return PCICfgRead16(dev->bus, dev->slot, dev->func, reg);
74 }
75 
76 uint32_t
PCI_CfgRead32(PCIDevice * dev,uint32_t reg)77 PCI_CfgRead32(PCIDevice *dev, uint32_t reg)
78 {
79     return PCICfgRead32(dev->bus, dev->slot, dev->func, reg);
80 }
81 
82 void
PCI_CfgWrite8(PCIDevice * dev,uint32_t reg,uint8_t data)83 PCI_CfgWrite8(PCIDevice *dev, uint32_t reg, uint8_t data)
84 {
85     return PCICfgWrite8(dev->bus, dev->slot, dev->func, reg, data);
86 }
87 
88 void
PCI_CfgWrite16(PCIDevice * dev,uint32_t reg,uint16_t data)89 PCI_CfgWrite16(PCIDevice *dev, uint32_t reg, uint16_t data)
90 {
91     return PCICfgWrite16(dev->bus, dev->slot, dev->func, reg, data);
92 }
93 
94 void
PCI_CfgWrite32(PCIDevice * dev,uint32_t reg,uint32_t data)95 PCI_CfgWrite32(PCIDevice *dev, uint32_t reg, uint32_t data)
96 {
97     return PCICfgWrite32(dev->bus, dev->slot, dev->func, reg, data);
98 }
99 
100 uint16_t
PCI_GetDeviceID(PCIDevice * dev)101 PCI_GetDeviceID(PCIDevice *dev)
102 {
103     return PCI_CfgRead16(dev, PCI_OFFSET_DEVICEID);
104 }
105 
106 uint16_t
PCI_GetVendorID(PCIDevice * dev)107 PCI_GetVendorID(PCIDevice *dev)
108 {
109     return PCI_CfgRead16(dev, PCI_OFFSET_VENDORID);
110 }
111 
112 uint8_t
PCI_GetBaseClass(PCIDevice * dev)113 PCI_GetBaseClass(PCIDevice *dev)
114 {
115     return PCI_CfgRead8(dev, PCI_OFFSET_CLASS);
116 }
117 
118 uint8_t
PCI_GetSubClass(PCIDevice * dev)119 PCI_GetSubClass(PCIDevice *dev)
120 {
121     return PCI_CfgRead8(dev, PCI_OFFSET_SUBCLASS);
122 }
123 
124 uint8_t
PCI_GetHeaderType(PCIDevice * dev)125 PCI_GetHeaderType(PCIDevice *dev)
126 {
127     return PCI_CfgRead8(dev, PCI_OFFSET_HEADERTYPE);
128 }
129 
130 /*
131  * PCICheckFunction --
132  *
133  * 	Identify device type and initialize known devices.
134  */
135 static void
PCICheckFunction(uint32_t bus,uint32_t device,uint32_t func)136 PCICheckFunction(uint32_t bus, uint32_t device, uint32_t func)
137 {
138     uint8_t baseClass, subClass;
139     uint16_t vendorId, deviceId;
140 
141     baseClass = PCIGetBaseClass(bus, device, func);
142     subClass = PCIGetSubClass(bus, device, func);
143     vendorId = PCIGetVendorID(bus, device, func);
144     deviceId = PCIGetDeviceID(bus, device, func);
145 
146     if (baseClass == PCI_CLASS_BRIDGE) {
147         if (subClass == PCI_SCLASS_BRIDGE_HOST) {
148             kprintf("PCI: (%d,%d,%d) Host Bridge (%04x:%04x)\n",
149                     bus, device, func, vendorId, deviceId);
150         } else if (subClass == PCI_SCLASS_BRIDGE_ISA) {
151             kprintf("PCI: (%d,%d,%d) ISA Bridge (%04x:%04x)\n",
152                     bus, device, func, vendorId, deviceId);
153         } else if (subClass == PCI_SCLASS_BRIDGE_PCI) {
154             kprintf("PCI: (%d,%d,%d) PCI-PCI Bridge (%04x:%04x)\n",
155                     bus, device, func, vendorId, deviceId);
156             // Scan sub-bus
157         } else if (subClass == PCI_SCLASS_BRIDGE_MISC) {
158             kprintf("PCI: (%d,%d,%d) Other Bridge (%04x:%04x)\n",
159                     bus, device, func, vendorId, deviceId);
160         }
161     } else if (baseClass == PCI_CLASS_STORAGE) {
162         if (subClass == PCI_SCLASS_STORAGE_SATA) {
163             kprintf("PCI: (%d,%d,%d) SATA Controller (%04x:%04x)\n",
164                     bus, device, func, vendorId, deviceId);
165 
166             AHCI_Init(bus, device, func);
167         } else if (subClass == PCI_SCLASS_STORAGE_IDE) {
168             kprintf("PCI: (%d,%d,%d) IDE Controller (%04x:%04x)\n",
169                     bus, device, func, vendorId, deviceId);
170         }
171     } else if ((baseClass == PCI_CLASS_NETWORK) && (subClass == 0x00)) {
172         kprintf("PCI: (%d,%d,%d) Ethernet (%04x:%04x)\n",
173                 bus, device, func, vendorId, deviceId);
174         E1000_Init(bus, device, func);
175     } else if ((baseClass == PCI_CLASS_GRAPHICS) && (subClass == 0x00)) {
176         kprintf("PCI: (%d,%d,%d) VGA (%04x:%04x)\n",
177                 bus, device, func, vendorId, deviceId);
178     } else if ((baseClass == PCI_CLASS_BUS) && (subClass == PCI_SCLASS_BUS_SMBUS)) {
179         kprintf("PCI: (%d,%d,%d) SMBUS (%04x:%04x)\n",
180                 bus, device, func, vendorId, deviceId);
181     } else {
182         kprintf("PCI: (%d,%d,%d) Unsupported (%04x:%04x %02x:%02x)\n",
183                 bus, device, func, vendorId, deviceId, baseClass, subClass);
184     }
185 }
186 
187 static void
PCIScanDevice(uint32_t bus,uint32_t device)188 PCIScanDevice(uint32_t bus, uint32_t device)
189 {
190     uint8_t headerType;
191     uint16_t vendorId;
192 
193     vendorId = PCIGetVendorID(bus, device, 0);
194     if (vendorId == 0xFFFF)
195         return;
196 
197     PCICheckFunction(bus, device, 0);
198 
199     headerType = PCIGetHeaderType(bus, device, 0);
200     if ((headerType & 0x80) != 0) {
201         uint8_t func;
202         for (func = 0; func < 8; func++) {
203             if (PCIGetVendorID(bus, device, func) != 0xFFFF) {
204                 PCICheckFunction(bus, device, func);
205             }
206         }
207     }
208 }
209 
210 static void
PCIScanBus(uint8_t bus)211 PCIScanBus(uint8_t bus)
212 {
213     uint8_t device;
214 
215     for (device = 0; device < 32; device++) {
216         PCIScanDevice(bus, device);
217     }
218 }
219 
220 /*
221  * PCIScan --
222  *
223  * 	Scan all busses and devices.
224  */
225 static void
PCIScan()226 PCIScan()
227 {
228     uint8_t headerType = PCIGetHeaderType(0, 0, 0);
229 
230     if ((headerType & 0x80) == 0) {
231         PCIScanBus(0);
232     } else {
233         uint8_t busNo;
234 
235         for (busNo = 0; busNo < 8; busNo++) {
236             if (PCIGetVendorID(0, 0, busNo) != 0xFFFF)
237                 break;
238             PCIScanBus(busNo);
239         }
240     }
241 }
242 
243 /*
244  * PCI_Configure --
245  *
246  * 	Configure a PCI device BAR registers.
247  */
248 void
PCI_Configure(PCIDevice * dev)249 PCI_Configure(PCIDevice *dev)
250 {
251     int bar;
252 
253     dev->irq = PCI_CfgRead8(dev, PCI_OFFSET_IRQLINE);
254 
255     PCI_CfgWrite16(dev, PCI_OFFSET_COMMAND,
256                    PCI_COMMAND_IOENABLE | PCI_COMMAND_MEMENABLE | PCI_COMMAND_BUSMASTER);
257 
258     for (bar = 0; bar < PCI_MAX_BARS; bar++)
259     {
260         dev->bars[bar].base = 0;
261         dev->bars[bar].size = 0;
262         dev->bars[bar].type = PCIBAR_TYPE_NULL;
263     }
264 
265     for (bar = 0; bar < PCI_MAX_BARS; bar++)
266     {
267         uint32_t barReg = PCI_OFFSET_BARFIRST + 4 * bar;
268         uint32_t base, size;
269         uint32_t origValue = PCI_CfgRead32(dev, barReg);
270 
271         PCI_CfgWrite32(dev, barReg, 0xFFFFFFFF);
272         size = PCI_CfgRead32(dev, barReg);
273         if (size == 0)
274             continue;
275 
276         PCI_CfgWrite32(dev, barReg, origValue);
277 
278         if (origValue & 0x1)
279         {
280             dev->bars[bar].type = PCIBAR_TYPE_IO;
281             base = origValue & 0xFFFFFFFC;
282             size = size & 0xFFFFFFFC;
283             size = ~size + 1;
284         } else {
285             dev->bars[bar].type = PCIBAR_TYPE_MEM;
286             base = origValue & 0xFFFFFFF0;
287             size = size & 0xFFFFFFF0;
288             size = ~size + 1;
289             // XXX: Support 64-bit
290             ASSERT((origValue & 0x06) == 0x00);
291         }
292 
293         dev->bars[bar].base = base;
294         dev->bars[bar].size = size;
295     }
296 }
297 
298 static void
DebugPCICheckFunction(uint32_t bus,uint32_t device,uint32_t func)299 DebugPCICheckFunction(uint32_t bus, uint32_t device, uint32_t func)
300 {
301     uint8_t baseClass, subClass;
302     uint16_t vendorId, deviceId;
303 
304     baseClass = PCIGetBaseClass(bus, device, func);
305     subClass = PCIGetSubClass(bus, device, func);
306     vendorId = PCIGetVendorID(bus, device, func);
307     deviceId = PCIGetDeviceID(bus, device, func);
308 
309     if (baseClass == PCI_CLASS_BRIDGE) {
310         if (subClass == PCI_SCLASS_BRIDGE_HOST) {
311             kprintf("PCI: (%d,%d,%d) Host Bridge (%04x:%04x)\n",
312                     bus, device, func, vendorId, deviceId);
313         } else if (subClass == PCI_SCLASS_BRIDGE_ISA) {
314             kprintf("PCI: (%d,%d,%d) ISA Bridge (%04x:%04x)\n",
315                     bus, device, func, vendorId, deviceId);
316         } else if (subClass == PCI_SCLASS_BRIDGE_PCI) {
317             kprintf("PCI: (%d,%d,%d) PCI-PCI Bridge (%04x:%04x)\n",
318                     bus, device, func, vendorId, deviceId);
319             // XXX: Scan sub-bus
320         } else if (subClass == PCI_SCLASS_BRIDGE_MISC) {
321             kprintf("PCI: (%d,%d,%d) Other Bridge (%04x:%04x)\n",
322                     bus, device, func, vendorId, deviceId);
323         }
324     } else if (baseClass == PCI_CLASS_STORAGE) {
325         if (subClass == PCI_SCLASS_STORAGE_SATA) {
326             kprintf("PCI: (%d,%d,%d) SATA Controller (%04x:%04x)\n",
327                     bus, device, func, vendorId, deviceId);
328         } else if (subClass == PCI_SCLASS_STORAGE_IDE) {
329             kprintf("PCI: (%d,%d,%d) IDE Controller (%04x:%04x)\n",
330                     bus, device, func, vendorId, deviceId);
331         }
332     } else if ((baseClass == PCI_CLASS_NETWORK) && (subClass == 0x00)) {
333         kprintf("PCI: (%d,%d,%d) Ethernet (%04x:%04x)\n",
334                 bus, device, func, vendorId, deviceId);
335     } else if ((baseClass == PCI_CLASS_GRAPHICS) && (subClass == 0x00)) {
336         kprintf("PCI: (%d,%d,%d) VGA (%04x:%04x)\n",
337                 bus, device, func, vendorId, deviceId);
338     } else if ((baseClass == PCI_CLASS_BUS) && (subClass == PCI_SCLASS_BUS_SMBUS)) {
339         kprintf("PCI: (%d,%d,%d) SMBUS (%04x:%04x)\n",
340                 bus, device, func, vendorId, deviceId);
341     } else {
342         kprintf("PCI: (%d,%d,%d) Unsupported (%04x:%04x %02x:%02x)\n",
343                 bus, device, func, vendorId, deviceId, baseClass, subClass);
344     }
345 }
346 
347 static void
DebugPCIScanBus(uint8_t bus)348 DebugPCIScanBus(uint8_t bus)
349 {
350     uint8_t device;
351     uint8_t headerType;
352     uint16_t vendorId;
353 
354     for (device = 0; device < 32; device++) {
355         vendorId = PCIGetVendorID(bus, device, 0);
356         if (vendorId == 0xFFFF)
357                 return;
358 
359         DebugPCICheckFunction(bus, device, 0);
360 
361         headerType = PCIGetHeaderType(bus, device, 0);
362         if ((headerType & 0x80) != 0) {
363             uint8_t func;
364             for (func = 0; func < 8; func++) {
365                 if (PCIGetVendorID(bus, device, func) != 0xFFFF) {
366                         DebugPCICheckFunction(bus, device, func);
367                 }
368             }
369         }
370     }
371 }
372 
373 void
Debug_PCIList(int argc,const char * argv[])374 Debug_PCIList(int argc, const char *argv[])
375 {
376     uint8_t headerType = PCIGetHeaderType(0, 0, 0);
377 
378     if ((headerType & 0x80) == 0) {
379         DebugPCIScanBus(0);
380     } else {
381         uint8_t busNo;
382 
383         for (busNo = 0; busNo < 8; busNo++) {
384             if (PCIGetVendorID(0, 0, busNo) != 0xFFFF)
385                 break;
386             DebugPCIScanBus(busNo);
387         }
388     }
389 }
390 
391 REGISTER_DBGCMD(pcilist, "PCI Device List", Debug_PCIList);
392 
393 void
Debug_PCIDump(int argc,const char * argv[])394 Debug_PCIDump(int argc, const char *argv[])
395 {
396     uint32_t bus, device, func;
397     uint32_t bar;
398 
399     if (argc != 4) {
400         kprintf("Requires 3 arguments!\n");
401         return;
402     }
403 
404     bus = Debug_StrToInt(argv[1]);
405     device = Debug_StrToInt(argv[2]);
406     func = Debug_StrToInt(argv[3]);
407 
408     kprintf("Vendor ID: %04x\n", PCIGetVendorID(bus, device, func));
409     kprintf("Device ID: %04x\n", PCIGetDeviceID(bus, device, func));
410     kprintf("Class: %d\n", PCIGetBaseClass(bus, device, func));
411     kprintf("Subclass: %d\n", PCIGetSubClass(bus, device, func));
412     kprintf("Header Type: %d\n", PCIGetHeaderType(bus, device, func));
413 
414     for (bar = 0; bar < PCI_MAX_BARS; bar++)
415     {
416         uint32_t barReg = PCI_OFFSET_BARFIRST + 4 * bar;
417 
418         kprintf("BAR%d: %016llx\n", bar, PCICfgRead32(bus, device, func, barReg));
419     }
420 }
421 
422 REGISTER_DBGCMD(pcidump, "PCI Device Dump", Debug_PCIDump);
423 
424