1 | /*␊ |
2 | *␊ |
3 | * Copyright 2008 by Islam M. Ahmed Zaid. All rights reserved.␊ |
4 | *␊ |
5 | */␊ |
6 | ␊ |
7 | #include "libsaio.h"␊ |
8 | #include "bootstruct.h"␊ |
9 | #include "pci.h"␊ |
10 | ␊ |
11 | #ifndef DEBUG_PCI␊ |
12 | #define DEBUG_PCI 0␊ |
13 | #endif␊ |
14 | ␊ |
15 | #if DEBUG_PCI␊ |
16 | #define DBG(x...)␉␉printf(x)␊ |
17 | #else␊ |
18 | #define DBG(x...)␊ |
19 | #endif␊ |
20 | ␊ |
21 | pci_dt_t␉*root_pci_dev;␊ |
22 | ␊ |
23 | ␊ |
24 | uint8_t pci_config_read8(uint32_t pci_addr, uint8_t reg)␊ |
25 | {␊ |
26 | ␉pci_addr |= reg & ~3;␊ |
27 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
28 | ␉return inb(PCI_DATA_REG + (reg & 3));␊ |
29 | }␊ |
30 | ␊ |
31 | uint16_t pci_config_read16(uint32_t pci_addr, uint8_t reg)␊ |
32 | {␊ |
33 | ␉pci_addr |= reg & ~3;␊ |
34 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
35 | ␉return inw(PCI_DATA_REG + (reg & 2));␊ |
36 | }␊ |
37 | ␊ |
38 | uint32_t pci_config_read32(uint32_t pci_addr, uint8_t reg)␊ |
39 | {␊ |
40 | ␉pci_addr |= reg & ~3;␊ |
41 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
42 | ␉return inl(PCI_DATA_REG);␊ |
43 | }␊ |
44 | ␊ |
45 | void pci_config_write8(uint32_t pci_addr, uint8_t reg, uint8_t data)␊ |
46 | {␊ |
47 | ␉pci_addr |= reg & ~3;␊ |
48 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
49 | ␉outb(PCI_DATA_REG + (reg & 3), data);␊ |
50 | }␊ |
51 | ␊ |
52 | void pci_config_write16(uint32_t pci_addr, uint8_t reg, uint16_t data)␊ |
53 | {␊ |
54 | ␉pci_addr |= reg & ~3;␊ |
55 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
56 | ␉outw(PCI_DATA_REG + (reg & 2), data);␊ |
57 | }␊ |
58 | ␊ |
59 | void pci_config_write32(uint32_t pci_addr, uint8_t reg, uint32_t data)␊ |
60 | {␊ |
61 | ␉pci_addr |= reg & ~3;␊ |
62 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
63 | ␉outl(PCI_DATA_REG, data);␊ |
64 | }␊ |
65 | ␊ |
66 | void scan_pci_bus(pci_dt_t *start, uint8_t bus)␊ |
67 | {␊ |
68 | ␉pci_dt_t␉*new;␊ |
69 | ␉pci_dt_t␉**current = &start->children;␊ |
70 | ␉uint32_t␉id;␊ |
71 | ␉uint32_t␉pci_addr;␊ |
72 | ␉uint8_t␉␉dev;␊ |
73 | ␉uint8_t␉␉func;␊ |
74 | ␉uint8_t␉␉secondary_bus;␊ |
75 | ␉uint8_t␉␉header_type;␊ |
76 | ␊ |
77 | ␉for (dev = 0; dev < 32; dev++) {␊ |
78 | ␉␉for (func = 0; func < 8; func++) {␊ |
79 | ␉␉␉pci_addr = PCIADDR(bus, dev, func);␊ |
80 | ␉␉␉id = pci_config_read32(pci_addr, PCI_VENDOR_ID);␊ |
81 | ␉␉␉if (!id || id == 0xffffffff) {␊ |
82 | ␉␉␉␉continue;␊ |
83 | ␉␉␉}␊ |
84 | ␉␉␉new = (pci_dt_t*)malloc(sizeof(pci_dt_t));␊ |
85 | ␉␉␉bzero(new, sizeof(pci_dt_t));␊ |
86 | ␉␉␉new->dev.addr␉= pci_addr;␊ |
87 | ␉␉␉new->vendor_id␉= id & 0xffff;␊ |
88 | ␉␉␉new->device_id␉= (id >> 16) & 0xffff;␊ |
89 | ␉␉␉new->class_id␉= pci_config_read16(pci_addr, PCI_CLASS_DEVICE);␊ |
90 | ␉␉␉new->parent␉= start;␊ |
91 | ␊ |
92 | ␉␉␉header_type = pci_config_read8(pci_addr, PCI_HEADER_TYPE);␊ |
93 | ␉␉␉switch (header_type & 0x7f) {␊ |
94 | ␉␉␉case PCI_HEADER_TYPE_BRIDGE:␊ |
95 | ␉␉␉case PCI_HEADER_TYPE_CARDBUS:␊ |
96 | ␉␉␉␉secondary_bus = pci_config_read8(pci_addr, PCI_SECONDARY_BUS);␊ |
97 | ␉␉␉␉if (secondary_bus != 0) {␊ |
98 | ␉␉␉␉␉scan_pci_bus(new, secondary_bus);␊ |
99 | ␉␉␉␉}␊ |
100 | ␉␉␉␉break;␊ |
101 | ␉␉␉}␊ |
102 | ␉␉␉*current = new;␊ |
103 | ␉␉␉current = &new->next;␊ |
104 | ␊ |
105 | ␉␉␉if ((func == 0) && ((header_type & 0x80) == 0)) {␊ |
106 | ␉␉␉␉break;␊ |
107 | ␉␉␉}␊ |
108 | ␉␉}␊ |
109 | ␉}␊ |
110 | }␊ |
111 | ␊ |
112 | void build_pci_dt(void)␊ |
113 | {␊ |
114 | ␉root_pci_dev = malloc(sizeof(pci_dt_t));␊ |
115 | ␉bzero(root_pci_dev, sizeof(pci_dt_t));␊ |
116 | ␉scan_pci_bus(root_pci_dev, 0);␊ |
117 | #if DEBUG_PCI␊ |
118 | ␉dump_pci_dt(root_pci_dev->children);␊ |
119 | ␉printf("(Press a key to continue...)\n");␊ |
120 | ␉getc();␊ |
121 | #endif␊ |
122 | }␊ |
123 | ␊ |
124 | static char dev_path[256];␊ |
125 | char *get_pci_dev_path(pci_dt_t *pci_dt)␊ |
126 | {␊ |
127 | ␉pci_dt_t␉*current;␊ |
128 | ␉pci_dt_t␉*end;␊ |
129 | ␉char␉␉tmp[64];␊ |
130 | ␊ |
131 | ␉dev_path[0] = 0;␊ |
132 | ␉end = root_pci_dev;␊ |
133 | ␉while (end != pci_dt) {␊ |
134 | ␉␉current = pci_dt;␊ |
135 | ␉␉while (current->parent != end) {␊ |
136 | ␉␉␉current = current->parent;␊ |
137 | ␉␉}␊ |
138 | ␉␉end = current;␊ |
139 | ␉␉sprintf(tmp, "%s/Pci(0x%x,0x%x)",␊ |
140 | ␉␉␉(current->parent == root_pci_dev) ? "PciRoot(0x0)" : "",␊ |
141 | ␉␉␉current->dev.bits.dev, current->dev.bits.func);␊ |
142 | ␉␉strcat(dev_path, tmp);␊ |
143 | ␉}␊ |
144 | ␉return dev_path;␊ |
145 | }␊ |
146 | ␊ |
147 | void dump_pci_dt(pci_dt_t *pci_dt)␊ |
148 | {␊ |
149 | ␉pci_dt_t␉*current;␊ |
150 | ␊ |
151 | ␉current = pci_dt;␊ |
152 | ␉while (current) {␊ |
153 | ␉␉printf("%02x:%02x.%x [%04x] [%04x:%04x] :: %s\n", ␊ |
154 | ␉␉␉current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func, ␊ |
155 | ␉␉␉current->class_id, current->vendor_id, current->device_id, ␊ |
156 | ␉␉␉get_pci_dev_path(current));␊ |
157 | ␉␉dump_pci_dt(current->children);␊ |
158 | ␉␉current = current->next;␊ |
159 | ␉}␊ |
160 | }␊ |
161 | |