1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <inttypes.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <console.h>
39#include <sys/pci.h>
40#include <com32.h>
41#include <stdbool.h>
42#include <ctype.h>
43#include <syslinux/zio.h>
44#include <dprintf.h>
45
46#define MAX_LINE 512
47
48
49static void remove_eol(char *string)
50{
51 int j = strlen(string);
52 int i = 0;
53 for (i = 0; i < j; i++)
54 if (string[i] == '\n')
55 string[i] = 0;
56}
57
58
59static int hex_to_int(char *hexa)
60{
61 return strtoul(hexa, NULL, 16);
62}
63
64
65
66int get_module_name_from_pcimap(struct pci_domain *domain,
67 char *modules_pcimap_path)
68{
69 char line[MAX_LINE];
70 char module_name[21];
71 char delims[]=" ";
72 char vendor_id[16];
73 char product_id[16];
74 char sub_vendor_id[16];
75 char sub_product_id[16];
76 FILE *f;
77 struct pci_device *dev=NULL;
78
79
80
81 for_each_pci_func(dev, domain) {
82
83 if (! dev->dev_info) {
84 dev->dev_info = zalloc(sizeof *dev->dev_info);
85 if (!dev->dev_info)
86 return -1;
87 }
88 for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) {
89 if (strlen(dev->dev_info->linux_kernel_module[i])==0)
90 strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7);
91 }
92 }
93
94
95 f=zfopen(modules_pcimap_path, "r");
96 if (!f)
97 return -ENOMODULESPCIMAP;
98
99 strcpy(vendor_id,"0000");
100 strcpy(product_id,"0000");
101 strcpy(sub_product_id,"0000");
102 strcpy(sub_vendor_id,"0000");
103
104
105 while ( fgets(line, sizeof line, f) ) {
106
107 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10))
108 continue;
109
110 char *result = NULL;
111 int field=0;
112
113
114 result = strtok(line, delims);
115 while( result != NULL ) {
116
117
118 if (strlen(result)>1) {
119 switch (field) {
120
121
122
123
124 case 0:chrreplace(result,'-','_');strcpy(module_name,result); break;
125 case 1:strcpy(vendor_id,result); break;
126 case 2:strcpy(product_id,result); break;
127 case 3:strcpy(sub_vendor_id,result); break;
128 case 4:strcpy(sub_product_id,result); break;
129 }
130 field++;
131 }
132
133 result = strtok( NULL, delims );
134 }
135 int int_vendor_id=hex_to_int(vendor_id);
136 int int_sub_vendor_id=hex_to_int(sub_vendor_id);
137 int int_product_id=hex_to_int(product_id);
138 int int_sub_product_id=hex_to_int(sub_product_id);
139
140
141 for_each_pci_func(dev, domain) {
142 if (int_vendor_id == dev->vendor &&
143 int_product_id == dev->product &&
144 (int_sub_product_id & dev->sub_product)
145 == dev->sub_product &&
146 (int_sub_vendor_id & dev->sub_vendor)
147 == dev->sub_vendor) {
148 bool found=false;
149
150
151 for (int i=0; i<dev->dev_info->linux_kernel_module_count; i++) {
152
153
154 if (strstr(dev->dev_info->linux_kernel_module[i], module_name)) {
155 found=true;
156 break;
157 }
158 }
159
160 if (!found) {
161 strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name);
162 dev->dev_info->linux_kernel_module_count++;
163 }
164 }
165 }
166 }
167 fclose(f);
168 return 0;
169}
170
171
172
173int get_class_name_from_pci_ids(struct pci_domain *domain, char *pciids_path)
174{
175 char line[MAX_LINE];
176 char class_name[PCI_CLASS_NAME_SIZE];
177 char sub_class_name[PCI_CLASS_NAME_SIZE];
178 char class_id_str[5];
179 char sub_class_id_str[5];
180 FILE *f;
181 struct pci_device *dev;
182 bool class_mode = false;
183
184
185
186 for_each_pci_func(dev, domain) {
187
188 if (!dev->dev_info) {
189 dev->dev_info = zalloc(sizeof *dev->dev_info);
190 if (!dev->dev_info)
191 return -1;
192 }
193 strlcpy(dev->dev_info->class_name, "unknown", 7);
194 }
195
196
197 f = zfopen(pciids_path, "r");
198 if (!f)
199 return -ENOPCIIDS;
200
201
202 while (fgets(line, sizeof line, f)) {
203
204 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10))
205 continue;
206
207
208 if (line[0] == 'C')
209 class_mode = true;
210 if (class_mode == false)
211 continue;
212 strlcpy(class_name, "unknown", 7);
213
214 if (line[0] != '\t') {
215
216
217 strlcpy(class_id_str, &line[2], 2);
218 class_id_str[2] = 0;
219
220
221 strlcpy(class_name, skipspace(strstr(line, " ")),
222 PCI_CLASS_NAME_SIZE - 1);
223 remove_eol(class_name);
224
225 int int_class_id_str = hex_to_int(class_id_str);
226
227 for_each_pci_func(dev, domain) {
228 if (int_class_id_str == dev->class[2]) {
229 strlcpy(dev->dev_info->class_name, class_name,
230 PCI_CLASS_NAME_SIZE - 1);
231
232 strlcpy(dev->dev_info->category_name, class_name + 4,
233 PCI_CLASS_NAME_SIZE - 1);
234 }
235 }
236
237 } else if ((line[0] == '\t') && (line[1] != '\t')) {
238
239
240 strlcpy(sub_class_name, skipspace(strstr(line, " ")),
241 PCI_CLASS_NAME_SIZE - 1);
242 remove_eol(sub_class_name);
243
244
245 strlcpy(sub_class_id_str, &line[1], 2);
246 sub_class_id_str[2] = 0;
247
248 int int_class_id_str = hex_to_int(class_id_str);
249 int int_sub_class_id_str = hex_to_int(sub_class_id_str);
250
251 for_each_pci_func(dev, domain) {
252 if (int_class_id_str == dev->class[2] &&
253 int_sub_class_id_str == dev->class[1])
254 strlcpy(dev->dev_info->class_name, sub_class_name,
255 PCI_CLASS_NAME_SIZE - 1);
256 }
257
258 }
259 }
260 fclose(f);
261 return 0;
262}
263
264
265
266int get_name_from_pci_ids(struct pci_domain *domain, char *pciids_path)
267{
268 char line[MAX_LINE];
269 char vendor[PCI_VENDOR_NAME_SIZE];
270 char vendor_id[5];
271 char product[PCI_PRODUCT_NAME_SIZE];
272 char product_id[5];
273 char sub_product_id[5];
274 char sub_vendor_id[5];
275 FILE *f;
276 struct pci_device *dev;
277 bool skip_to_next_vendor = false;
278 uint16_t int_vendor_id;
279 uint16_t int_product_id;
280 uint16_t int_sub_product_id;
281 uint16_t int_sub_vendor_id;
282
283
284
285 for_each_pci_func(dev, domain) {
286
287 if (!dev->dev_info) {
288 dev->dev_info = zalloc(sizeof *dev->dev_info);
289 if (!dev->dev_info)
290 return -1;
291 }
292 strlcpy(dev->dev_info->vendor_name, "unknown", 7);
293 strlcpy(dev->dev_info->product_name, "unknown", 7);
294 }
295
296
297 f = zfopen(pciids_path, "r");
298 if (!f)
299 return -ENOPCIIDS;
300
301 strlcpy(vendor_id, "0000", 4);
302 strlcpy(product_id, "0000", 4);
303 strlcpy(sub_product_id, "0000", 4);
304 strlcpy(sub_vendor_id, "0000", 4);
305
306
307 while (fgets(line, sizeof line, f)) {
308
309 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 'C') ||
310 (line[0] == 10))
311 continue;
312
313
314 if (line[0] != '\t') {
315
316
317 strlcpy(vendor_id, line, 4);
318
319
320 vendor_id[4] = 0;
321 strlcpy(vendor, skipspace(strstr(line, " ")),
322 PCI_VENDOR_NAME_SIZE - 1);
323
324 remove_eol(vendor);
325
326 strlcpy(product_id, "0000", 4);
327 strlcpy(sub_product_id, "0000", 4);
328 strlcpy(sub_vendor_id, "0000", 4);
329
330
331 skip_to_next_vendor = true;
332
333 int_vendor_id = hex_to_int(vendor_id);
334
335 for_each_pci_func(dev, domain) {
336
337 if (int_vendor_id == dev->vendor) {
338
339 strlcpy(dev->dev_info->vendor_name, vendor,
340 PCI_VENDOR_NAME_SIZE - 1);
341
342 skip_to_next_vendor = false;
343
344 }
345 }
346
347
348 } else if ((line[0] == '\t') && (line[1] != '\t')
349 && (skip_to_next_vendor == false)) {
350
351
352 strlcpy(product, skipspace(strstr(line, " ")),
353 PCI_PRODUCT_NAME_SIZE - 1);
354 remove_eol(product);
355
356
357 strlcpy(product_id, &line[1], 4);
358 product_id[4] = 0;
359
360
361 strlcpy(sub_product_id, "0000", 4);
362 strlcpy(sub_vendor_id, "0000", 4);
363
364 int_vendor_id = hex_to_int(vendor_id);
365 int_product_id = hex_to_int(product_id);
366
367 for_each_pci_func(dev, domain) {
368 if (int_vendor_id == dev->vendor &&
369 int_product_id == dev->product) {
370 strlcpy(dev->dev_info->vendor_name, vendor,
371 PCI_VENDOR_NAME_SIZE - 1);
372 strlcpy(dev->dev_info->product_name, product,
373 PCI_PRODUCT_NAME_SIZE - 1);
374 }
375 }
376
377
378
379 } else if ((line[0] == '\t') && (line[1] == '\t')
380 && (skip_to_next_vendor == false)) {
381
382
383 strlcpy(product, skipspace(strstr(line, " ")),
384 PCI_PRODUCT_NAME_SIZE - 1);
385 strlcpy(product, skipspace(strstr(product, " ")),
386 PCI_PRODUCT_NAME_SIZE - 1);
387 remove_eol(product);
388
389
390 strlcpy(sub_vendor_id, &line[2], 4);
391 sub_vendor_id[4] = 0;
392
393
394 strlcpy(sub_product_id, &line[7], 4);
395 sub_product_id[4] = 0;
396
397 int_vendor_id = hex_to_int(vendor_id);
398 int_sub_vendor_id = hex_to_int(sub_vendor_id);
399 int_product_id = hex_to_int(product_id);
400 int_sub_product_id = hex_to_int(sub_product_id);
401
402 for_each_pci_func(dev, domain) {
403 if (int_vendor_id == dev->vendor &&
404 int_product_id == dev->product &&
405 int_sub_product_id == dev->sub_product &&
406 int_sub_vendor_id == dev->sub_vendor) {
407 strlcpy(dev->dev_info->vendor_name, vendor,
408 PCI_VENDOR_NAME_SIZE - 1);
409 strlcpy(dev->dev_info->product_name, product,
410 PCI_PRODUCT_NAME_SIZE - 1);
411 }
412 }
413 }
414 }
415 fclose(f);
416 return 0;
417}
418
419
420struct match *find_pci_device(const struct pci_domain *domain,
421 struct match *list)
422{
423 uint32_t did, sid;
424 struct match *m;
425 const struct pci_device *dev;
426
427
428 for (m = list; m; m = m->next) {
429
430 for_each_pci_func(dev, domain) {
431
432
433 sid = dev->svid_sdid;
434 did = dev->vid_did;
435
436 if (((did ^ m->did) & m->did_mask) == 0 &&
437 ((sid ^ m->sid) & m->sid_mask) == 0 &&
438 dev->revision >= m->rid_min && dev->revision <= m->rid_max) {
439 dprintf
440 ("PCI Match: Vendor=%04x Product=%04x Sub_vendor=%04x Sub_Product=%04x Release=%02x\n",
441 dev->vendor, dev->product, dev->sub_vendor,
442 dev->sub_product, dev->revision);
443
444 return m;
445 }
446 }
447 }
448 return NULL;
449}
450
451
452struct pci_domain *pci_scan(void)
453{
454 struct pci_domain *domain = NULL;
455 struct pci_bus *bus = NULL;
456 struct pci_slot *slot = NULL;
457 struct pci_device *func = NULL;
458 unsigned int nbus, ndev, nfunc, maxfunc;
459 uint32_t did, sid, rcid;
460 uint8_t hdrtype;
461 pciaddr_t a;
462 int cfgtype;
463
464 cfgtype = pci_set_config_type(PCI_CFG_AUTO);
465
466 dprintf("PCI configuration type %d\n", cfgtype);
467
468 if (cfgtype == PCI_CFG_NONE)
469 return NULL;
470
471 dprintf("Scanning PCI Buses\n");
472
473 for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) {
474 dprintf("Probing bus 0x%02x... \n", nbus);
475 bus = NULL;
476
477 for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) {
478 maxfunc = 1;
479 slot = NULL;
480
481 for (nfunc = 0; nfunc < maxfunc; nfunc++) {
482 a = pci_mkaddr(nbus, ndev, nfunc, 0);
483 did = pci_readl(a);
484
485 if (did == 0xffffffff || did == 0xffff0000 ||
486 did == 0x0000ffff || did == 0x00000000)
487 continue;
488
489 hdrtype = pci_readb(a + 0x0e);
490
491 if (hdrtype & 0x80)
492 maxfunc = MAX_PCI_FUNC;
493
494 rcid = pci_readl(a + 0x08);
495 sid = pci_readl(a + 0x2c);
496
497 if (!domain) {
498 domain = zalloc(sizeof *domain);
499 if (!domain)
500 goto bail;
501 }
502 if (!bus) {
503 bus = zalloc(sizeof *bus);
504 if (!bus)
505 goto bail;
506 domain->bus[nbus] = bus;
507 }
508 if (!slot) {
509 slot = zalloc(sizeof *slot);
510 if (!slot)
511 goto bail;
512 bus->slot[ndev] = slot;
513 }
514 func = zalloc(sizeof *func);
515 if (!func)
516 goto bail;
517
518 slot->func[nfunc] = func;
519
520 func->vid_did = did;
521 func->svid_sdid = sid;
522 func->rid_class = rcid;
523
524 dprintf
525 ("Scanning: BUS %02x DID %08x (%04x:%04x) SID %08x RID %02x\n",
526 nbus, did, did >> 16, (did << 16) >> 16, sid, rcid & 0xff);
527 }
528 }
529 }
530
531 return domain;
532
533bail:
534 free_pci_domain(domain);
535 return NULL;
536}
537
538
539void gather_additional_pci_config(struct pci_domain *domain)
540{
541 struct pci_device *dev;
542 pciaddr_t pci_addr;
543 int cfgtype;
544
545 cfgtype = pci_set_config_type(PCI_CFG_AUTO);
546 if (cfgtype == PCI_CFG_NONE)
547 return;
548
549 for_each_pci_func3(dev, domain, pci_addr) {
550 if (!dev->dev_info) {
551 dev->dev_info = zalloc(sizeof *dev->dev_info);
552 if (!dev->dev_info) {
553 return;
554 }
555 }
556 dev->dev_info->irq = pci_readb(pci_addr + 0x3c);
557 dev->dev_info->latency = pci_readb(pci_addr + 0x0d);
558 }
559}
560
561void free_pci_domain(struct pci_domain *domain)
562{
563 struct pci_bus *bus;
564 struct pci_slot *slot;
565 struct pci_device *func;
566 unsigned int nbus, ndev, nfunc;
567
568 if (domain) {
569 for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) {
570 bus = domain->bus[nbus];
571 if (bus) {
572 for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) {
573 slot = bus->slot[ndev];
574 if (slot) {
575 for (nfunc = 0; nfunc < MAX_PCI_FUNC; nfunc++) {
576 func = slot->func[nfunc];
577 if (func) {
578 if (func->dev_info)
579 free(func->dev_info);
580 free(func);
581 }
582 free(slot);
583 }
584 }
585 free(bus);
586 }
587 }
588 free(domain);
589 }
590 }
591}
592
593
594
595int get_module_name_from_alias(struct pci_domain *domain, char *modules_alias_path)
596{
597 char line[MAX_LINE];
598 char module_name[21];
599 char delims[]="*";
600 char vendor_id[16];
601 char product_id[16];
602 char sub_vendor_id[16];
603 char sub_product_id[16];
604 FILE *f;
605 struct pci_device *dev=NULL;
606
607
608
609 for_each_pci_func(dev, domain) {
610
611 if (! dev->dev_info) {
612 dev->dev_info = zalloc(sizeof *dev->dev_info);
613 if (!dev->dev_info)
614 return -1;
615 }
616 for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) {
617 if (strlen(dev->dev_info->linux_kernel_module[i])==0)
618 strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7);
619 }
620 }
621
622
623 f=zfopen(modules_alias_path, "r");
624 if (!f)
625 return -ENOMODULESALIAS;
626
627
628 while ( fgets(line, sizeof line, f) ) {
629
630 if ((line[0] == '#') || (strstr(line,"alias pci:v")==NULL))
631 continue;
632
633
634 memset(module_name,0,sizeof(module_name));
635 memset(vendor_id,0,sizeof(vendor_id));
636 memset(sub_vendor_id,0,sizeof(sub_vendor_id));
637 memset(product_id,0,sizeof(product_id));
638 memset(sub_product_id,0,sizeof(sub_product_id));
639 strcpy(vendor_id,"0000");
640 strcpy(product_id,"0000");
641
642
643 strcpy(sub_product_id,"ffff");
644 strcpy(sub_vendor_id,"ffff");
645
646 char *result = NULL;
647 int field=0;
648
649
650 result = strtok(line+strlen("alias pci:v"), delims);
651 while( result != NULL ) {
652 if (field==0) {
653
654
655 char *temp = strstr(result,"d");
656 if (temp != NULL) {
657 strlcpy(vendor_id,result,temp-result);
658 result+=strlen(vendor_id)+1;
659 }
660
661
662 temp = strstr(result,"sv");
663 if (temp != NULL) {
664 strlcpy(product_id,result,temp-result);
665 result+=strlen(product_id)+1;
666 }
667
668
669 temp = strstr(result,"sd");
670 if (temp != NULL) {
671 strlcpy(sub_vendor_id,result,temp-result);
672 result+=strlen(sub_vendor_id)+1;
673 }
674
675
676 temp = strstr(result,"bc");
677 if (temp != NULL) {
678 strlcpy(sub_product_id,result,temp-result);
679 result+=strlen(sub_product_id)+1;
680 }
681
682 } else if ((strlen(result)>2) &&
683 (result[0]==0x20))
684 strcpy(module_name,result+1);
685
686 module_name[strlen(module_name)-1]='\0';
687 field++;
688
689
690 result = strtok( NULL, delims );
691 }
692
693
694
695 int int_vendor_id=hex_to_int(vendor_id);
696 int int_sub_vendor_id=hex_to_int(sub_vendor_id);
697 int int_product_id=hex_to_int(product_id);
698 int int_sub_product_id=hex_to_int(sub_product_id);
699
700
701 for_each_pci_func(dev, domain) {
702 if (int_vendor_id == dev->vendor &&
703 int_product_id == dev->product &&
704 (int_sub_product_id & dev->sub_product)
705 == dev->sub_product &&
706 (int_sub_vendor_id & dev->sub_vendor)
707 == dev->sub_vendor) {
708 bool found=false;
709
710
711 for (int i=0; i<dev->dev_info->linux_kernel_module_count; i++) {
712
713
714 if (strstr(dev->dev_info->linux_kernel_module[i], module_name)) {
715 found=true;
716 break;
717 }
718 }
719
720 if (!found) {
721 strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name);
722 dev->dev_info->linux_kernel_module_count++;
723 }
724 }
725 }
726 }
727 fclose(f);
728 return 0;
729}
730