]> pd.if.org Git - zos/blob - pci/pci.c
add a readme with a public domain note
[zos] / pci / pci.c
1 #include "kernel.h"
2
3 #include "mem.h"
4 #include "ioport.h"
5
6 #include "pci.h"
7 #include <string.h>
8
9 /* TODO figure this out better */
10
11 struct pci_class_code_desc {
12         uint8_t code;
13         char description[63];
14 } pci_class_code_description[256] = {
15 /* Class Code   Description */
16         {0x00, "Unclassified Device" },
17         {0x01, "Mass Storage Controller" },
18         {0x02, "Network Controller" },
19         {0x03, "Display Controller" },
20         {0x04, "Multimedia Controller" },
21         {0x05, "Memory Controller" },
22         {0x06, "Bridge" },
23         {0x07, "Communication Controller" },
24         {0x08, "Generic System Peripheral" },
25         {0x09, "Input Device Controller" },
26         {0x0A, "Docking Station" },
27         {0x0B, "Processor" },
28         {0x0C, "Serial Bus Controller" },
29         {0x0D, "Wireless Controller" },
30         {0x0E, "Intelligent Controller" },
31         {0x0F, "Satellite Communications Controller" },
32         {0x10, "Encryption Controller" },
33         {0x11, "Signal Processing Controller" },
34         {0x12, "Processing accelerators"},
35         {0x13, "Non-Essential Instrumentation"},
36         {0x14, "Reserved"},
37         {0x15, "Reserved"},
38         {0x16, "Reserved"},
39         {0x17, "Reserved"},
40         {0x18, "Reserved"},
41         {0x19, "Reserved"},
42         {0x1A, "Reserved"},
43         {0x1B, "Reserved"},
44         {0x1C, "Reserved"},
45         {0x1D, "Reserved"},
46         {0x1E, "Reserved"},
47         {0x1F, "Reserved"},
48         {0x20, "Reserved"},
49         {0x21, "Reserved"},
50         {0x22, "Reserved"},
51         {0x23, "Reserved"},
52         {0x24, "Reserved"},
53         {0x25, "Reserved"},
54         {0x26, "Reserved"},
55         {0x27, "Reserved"},
56         {0x28, "Reserved"},
57         {0x29, "Reserved"},
58         {0x2A, "Reserved"},
59         {0x2B, "Reserved"},
60         {0x2C, "Reserved"},
61         {0x2D, "Reserved"},
62         {0x2E, "Reserved"},
63         {0x2F, "Reserved"},
64         {0x30, "Reserved"},
65         {0x31, "Reserved"},
66         {0x32, "Reserved"},
67         {0x33, "Reserved"},
68         {0x34, "Reserved"},
69         {0x35, "Reserved"},
70         {0x36, "Reserved"},
71         {0x37, "Reserved"},
72         {0x38, "Reserved"},
73         {0x39, "Reserved"},
74         {0x3A, "Reserved"},
75         {0x3B, "Reserved"},
76         {0x3C, "Reserved"},
77         {0x3D, "Reserved"},
78         {0x3E, "Reserved"},
79         {0x3F, "Reserved"},
80         {0x40, "Reserved"},
81         {0x41, "Reserved"},
82         {0x42, "Reserved"},
83         {0x43, "Reserved"},
84         {0x44, "Reserved"},
85         {0x45, "Reserved"},
86         {0x46, "Reserved"},
87         {0x47, "Reserved"},
88         {0x48, "Reserved"},
89         {0x49, "Reserved"},
90         {0x4A, "Reserved"},
91         {0x4B, "Reserved"},
92         {0x4C, "Reserved"},
93         {0x4D, "Reserved"},
94         {0x4E, "Reserved"},
95         {0x4F, "Reserved"},
96         {0x50, "Reserved"},
97         {0x51, "Reserved"},
98         {0x52, "Reserved"},
99         {0x53, "Reserved"},
100         {0x54, "Reserved"},
101         {0x55, "Reserved"},
102         {0x56, "Reserved"},
103         {0x57, "Reserved"},
104         {0x58, "Reserved"},
105         {0x59, "Reserved"},
106         {0x5A, "Reserved"},
107         {0x5B, "Reserved"},
108         {0x5C, "Reserved"},
109         {0x5D, "Reserved"},
110         {0x5E, "Reserved"},
111         {0x5F, "Reserved"},
112         {0x60, "Reserved"},
113         {0x61, "Reserved"},
114         {0x62, "Reserved"},
115         {0x63, "Reserved"},
116         {0x64, "Reserved"},
117         {0x65, "Reserved"},
118         {0x66, "Reserved"},
119         {0x67, "Reserved"},
120         {0x68, "Reserved"},
121         {0x69, "Reserved"},
122         {0x6A, "Reserved"},
123         {0x6B, "Reserved"},
124         {0x6C, "Reserved"},
125         {0x6D, "Reserved"},
126         {0x6E, "Reserved"},
127         {0x6F, "Reserved"},
128         {0x70, "Reserved"},
129         {0x71, "Reserved"},
130         {0x72, "Reserved"},
131         {0x73, "Reserved"},
132         {0x74, "Reserved"},
133         {0x75, "Reserved"},
134         {0x76, "Reserved"},
135         {0x77, "Reserved"},
136         {0x78, "Reserved"},
137         {0x79, "Reserved"},
138         {0x7A, "Reserved"},
139         {0x7B, "Reserved"},
140         {0x7C, "Reserved"},
141         {0x7D, "Reserved"},
142         {0x7E, "Reserved"},
143         {0x7F, "Reserved"},
144         {0x80, "Reserved"},
145         {0x81, "Reserved"},
146         {0x82, "Reserved"},
147         {0x83, "Reserved"},
148         {0x84, "Reserved"},
149         {0x85, "Reserved"},
150         {0x86, "Reserved"},
151         {0x87, "Reserved"},
152         {0x88, "Reserved"},
153         {0x89, "Reserved"},
154         {0x8A, "Reserved"},
155         {0x8B, "Reserved"},
156         {0x8C, "Reserved"},
157         {0x8D, "Reserved"},
158         {0x8E, "Reserved"},
159         {0x8F, "Reserved"},
160         {0x90, "Reserved"},
161         {0x91, "Reserved"},
162         {0x92, "Reserved"},
163         {0x93, "Reserved"},
164         {0x94, "Reserved"},
165         {0x95, "Reserved"},
166         {0x96, "Reserved"},
167         {0x97, "Reserved"},
168         {0x98, "Reserved"},
169         {0x99, "Reserved"},
170         {0x9A, "Reserved"},
171         {0x9B, "Reserved"},
172         {0x9C, "Reserved"},
173         {0x9D, "Reserved"},
174         {0x9E, "Reserved"},
175         {0x9F, "Reserved"},
176         {0xA0, "Reserved"},
177         {0xA1, "Reserved"},
178         {0xA2, "Reserved"},
179         {0xA3, "Reserved"},
180         {0xA4, "Reserved"},
181         {0xA5, "Reserved"},
182         {0xA6, "Reserved"},
183         {0xA7, "Reserved"},
184         {0xA8, "Reserved"},
185         {0xA9, "Reserved"},
186         {0xAA, "Reserved"},
187         {0xAB, "Reserved"},
188         {0xAC, "Reserved"},
189         {0xAD, "Reserved"},
190         {0xAE, "Reserved"},
191         {0xAF, "Reserved"},
192         {0xB0, "Reserved"},
193         {0xB1, "Reserved"},
194         {0xB2, "Reserved"},
195         {0xB3, "Reserved"},
196         {0xB4, "Reserved"},
197         {0xB5, "Reserved"},
198         {0xB6, "Reserved"},
199         {0xB7, "Reserved"},
200         {0xB8, "Reserved"},
201         {0xB9, "Reserved"},
202         {0xBA, "Reserved"},
203         {0xBB, "Reserved"},
204         {0xBC, "Reserved"},
205         {0xBD, "Reserved"},
206         {0xBE, "Reserved"},
207         {0xBF, "Reserved"},
208         {0xC0, "Reserved"},
209         {0xC1, "Reserved"},
210         {0xC2, "Reserved"},
211         {0xC3, "Reserved"},
212         {0xC4, "Reserved"},
213         {0xC5, "Reserved"},
214         {0xC6, "Reserved"},
215         {0xC7, "Reserved"},
216         {0xC8, "Reserved"},
217         {0xC9, "Reserved"},
218         {0xCA, "Reserved"},
219         {0xCB, "Reserved"},
220         {0xCC, "Reserved"},
221         {0xCD, "Reserved"},
222         {0xCE, "Reserved"},
223         {0xCF, "Reserved"},
224         {0xD0, "Reserved"},
225         {0xD1, "Reserved"},
226         {0xD2, "Reserved"},
227         {0xD3, "Reserved"},
228         {0xD4, "Reserved"},
229         {0xD5, "Reserved"},
230         {0xD6, "Reserved"},
231         {0xD7, "Reserved"},
232         {0xD8, "Reserved"},
233         {0xD9, "Reserved"},
234         {0xDA, "Reserved"},
235         {0xDB, "Reserved"},
236         {0xDC, "Reserved"},
237         {0xDD, "Reserved"},
238         {0xDE, "Reserved"},
239         {0xDF, "Reserved"},
240         {0xE0, "Reserved"},
241         {0xE1, "Reserved"},
242         {0xE2, "Reserved"},
243         {0xE3, "Reserved"},
244         {0xE4, "Reserved"},
245         {0xE5, "Reserved"},
246         {0xE6, "Reserved"},
247         {0xE7, "Reserved"},
248         {0xE8, "Reserved"},
249         {0xE9, "Reserved"},
250         {0xEA, "Reserved"},
251         {0xEB, "Reserved"},
252         {0xEC, "Reserved"},
253         {0xED, "Reserved"},
254         {0xEE, "Reserved"},
255         {0xEF, "Reserved"},
256         {0xF0, "Reserved"},
257         {0xF1, "Reserved"},
258         {0xF2, "Reserved"},
259         {0xF3, "Reserved"},
260         {0xF4, "Reserved"},
261         {0xF5, "Reserved"},
262         {0xF6, "Reserved"},
263         {0xF7, "Reserved"},
264         {0xF8, "Reserved"},
265         {0xF9, "Reserved"},
266         {0xFA, "Reserved"},
267         {0xFB, "Reserved"},
268         {0xFC, "Reserved"},
269         {0xFD, "Reserved"},
270         {0xFE, "Reserved"},
271         {0xFF, "Device does not fit any defined class." }
272 };
273
274 #define PCI_ADDR(bus, dev, func, offset) ( (uint32_t) ( \
275                           ((uint32_t)bus << 16) \
276                         | ((uint32_t)device << 11) \
277                         | ((uint32_t)function << 8) \
278                         | ((uint32_t)0x80000000U) \
279                         | (offset & 0xfc) ) )
280
281 uint32_t pci_read_config(uint32_t base, uint8_t offset) {
282         uint32_t data;
283         base = base | (offset & 0xfc);
284         outport32(0xcf8, base);
285         data = inport32(0xcfc);
286         return data;
287 }
288
289 void pci_write_config(uint32_t base, uint8_t offset, uint32_t val) {
290         base = base | (offset & 0xfc);
291         outport32(0xcf8, base);
292         outport32(0xcfc, val);
293         return;
294 }
295
296 int pci_read_header(struct pci_header *h, uint8_t bus, uint8_t device, uint8_t function) {
297         uint32_t addr, data;
298         int offset;
299         uint32_t *hb;
300         int size = 0;
301
302         hb = (uint32_t *)h;
303
304         addr = 0;
305         addr =  PCI_ADDR(bus,device,function,0); /* offset 0 for device and vendor id */
306         outport32(0xcf8, addr);
307         data = inport32(0xcfc);
308         h->vendorid = data & 0xffff;
309         h->deviceid = data >> 16;
310         if (h->vendorid == 0xffff) return 0;
311
312         hb++;
313         /* might as well read in the rest */
314
315         //printk("read in vendor id %x\n", h->vendorid);
316         switch (h->headertype & 0x7F) {
317                 case 0x00: size = 0x40; break; /* general device */
318                 case 0x01: size = 0x40; break; /* PCI to PCI bridge */
319                 case 0x02: size = 0x48; break; /* PCI to CardBus bridge */
320                 default: size = 0x10; break;
321         }
322
323         for (offset = 4; offset < size ; offset += 4) {
324                 addr =  PCI_ADDR(bus,device,function,offset);
325                 outport32(0xcf8, addr);
326                 data = inport32(0xcfc);
327                 *hb++ = data;
328         }
329         return 1;
330 }
331
332 void pci_debug_info(struct pci_header *h) {
333         printk("pci: id %0x:%0x, type %0x, class %0x:%0x, %s / %s\n",
334                         h->vendorid, h->deviceid, h->headertype, h->classcode, h->subclass,
335                         pci_class_code_description[h->classcode].description,
336                         pci_func_desc(h->classcode, h->subclass, h->progif)
337               );
338 }
339
340 void pci_scan_bus(uint8_t bus);
341
342 void pci_scan_device(uint8_t bus, uint8_t device) {
343         union pci_device h;
344         uint8_t function = 0;
345         struct pci_info *pci;
346
347         pci_read_header((struct pci_header *)&h, 0, device, function);
348
349         if (h.header.vendorid == 0xffff) return;
350
351         //printk("read pci header\n");
352         //pci_debug_info((struct pci_header *)&h);
353         
354         if (h.header.classcode == 0x06 && h.header.subclass == 0x04) {
355                 /* this is a bridge */
356                 uint8_t secbus = h.bridge.secondary_bus_number;
357                 pci_scan_bus(secbus);
358         }
359
360         if (h.header.headertype & 0x80 != 0) {
361                 for (function = 1; function < 8; function++) {
362                         pci_read_header((struct pci_header *)&h, 0, device, function);
363                         if (h.header.vendorid == 0xffff) continue;
364 //                      pci_debug_info((struct pci_header *)&h);
365                         if (h.header.classcode == 0x06 && h.header.subclass == 0x04) {
366                                 /* this is a bridge */
367                                 uint8_t secbus = h.bridge.secondary_bus_number;
368                                 pci_scan_bus(secbus);
369                         }
370                 }
371         }
372         pci = koalloc(sizeof *pci);
373         memcpy(&pci->device, &h, sizeof h);
374         pci->base = PCI_ADDR(bus,device,function,0);
375         if (pci_devices == NULL) {
376 //              printk("setting up list\n");
377                 pci_devices = pci;
378                 pci->next = pci;
379                 pci->prev = pci;
380         } else {
381 //              printk("adding to list\n");
382
383                 pci->prev = pci_devices->prev;
384                 pci->next = pci_devices;
385
386                 pci_devices->prev->next = pci;
387                 pci_devices->prev = pci;
388         }
389 }
390
391 void pci_scan_bus(uint8_t bus) {
392         uint8_t device;
393
394         for (device = 0; device < 32; device++) {
395                 pci_scan_device(bus, device);
396         }
397 }
398
399 struct pci_info *pci_devices;
400 paddr_t pci_start; /* the start of pci space */
401
402 void pci_init() {
403         struct pci_info *dev;
404
405         /* align the start of PCI memory to 1 MB */
406         /* TODO we could probably free any remaining physical pages
407          * between the _kernel_phys_end and the new alignment
408          */
409         pci_start = mem_align(_kernel_phys_end, MB(1));
410
411         //printk("sizeof pci_header = %x\n", sizeof h);
412         //
413         /* TODO free the list if it's not null? */
414
415         pci_devices = 0;
416         pci_scan_bus(0);
417
418         for (dev = pci_devices; dev; dev = dev->next) {
419                 pci_debug_info(&dev->device.header);
420                 if (dev->next == pci_devices) break;
421         }
422 }