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 | #include "pci_root.h"␊ |
11 | ␊ |
12 | #ifndef DEBUG_PCI␊ |
13 | #define DEBUG_PCI 0␊ |
14 | #endif␊ |
15 | ␊ |
16 | #if DEBUG_PCI␊ |
17 | #define DBG(x...)␉printf(x)␊ |
18 | #else␊ |
19 | #define DBG(x...)␉msglog(x)␊ |
20 | #endif␊ |
21 | ␊ |
22 | pci_dt_t␉*root_pci_dev;␊ |
23 | ␊ |
24 | ␊ |
25 | uint8_t pci_config_read8(uint32_t pci_addr, uint8_t reg)␊ |
26 | {␊ |
27 | ␉pci_addr |= reg & ~3;␊ |
28 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
29 | ␉return inb(PCI_DATA_REG + (reg & 3));␊ |
30 | }␊ |
31 | ␊ |
32 | uint16_t pci_config_read16(uint32_t pci_addr, uint8_t reg)␊ |
33 | {␊ |
34 | ␉pci_addr |= reg & ~3;␊ |
35 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
36 | ␉return inw(PCI_DATA_REG + (reg & 2));␊ |
37 | }␊ |
38 | ␊ |
39 | uint32_t pci_config_read32(uint32_t pci_addr, uint8_t reg)␊ |
40 | {␊ |
41 | ␉pci_addr |= reg & ~3;␊ |
42 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
43 | ␉return inl(PCI_DATA_REG);␊ |
44 | }␊ |
45 | ␊ |
46 | void pci_config_write8(uint32_t pci_addr, uint8_t reg, uint8_t data)␊ |
47 | {␊ |
48 | ␉pci_addr |= reg & ~3;␊ |
49 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
50 | ␉outb(PCI_DATA_REG + (reg & 3), data);␊ |
51 | }␊ |
52 | ␊ |
53 | void pci_config_write16(uint32_t pci_addr, uint8_t reg, uint16_t data)␊ |
54 | {␊ |
55 | ␉pci_addr |= reg & ~3;␊ |
56 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
57 | ␉outw(PCI_DATA_REG + (reg & 2), data);␊ |
58 | }␊ |
59 | ␊ |
60 | void pci_config_write32(uint32_t pci_addr, uint8_t reg, uint32_t data)␊ |
61 | {␊ |
62 | ␉pci_addr |= reg & ~3;␊ |
63 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
64 | ␉outl(PCI_DATA_REG, data);␊ |
65 | }␊ |
66 | ␊ |
67 | void scan_pci_bus(pci_dt_t *start, uint8_t bus)␊ |
68 | {␊ |
69 | ␉pci_dt_t␉*new;␊ |
70 | ␉pci_dt_t␉**current = &start->children;␊ |
71 | ␉uint32_t␉id;␊ |
72 | ␉uint32_t␉pci_addr;␊ |
73 | ␉uint8_t␉␉dev = 0;␊ |
74 | ␉uint8_t␉␉func = 0;␊ |
75 | ␉uint8_t␉␉secondary_bus;␊ |
76 | ␉uint8_t␉␉header_type;␊ |
77 | ␊ |
78 | ␉for (dev = 0; dev < 32; dev++)␊ |
79 | ␉{␊ |
80 | ␉␉for (func = 0; func < 8; func++)␊ |
81 | ␉␉{␊ |
82 | ␉␉␉pci_addr = PCIADDR(bus, dev, func);␊ |
83 | ␉␉␉id = pci_config_read32(pci_addr, PCI_VENDOR_ID);␊ |
84 | ␉␉␉if (!id || id == 0xfffffffful)␊ |
85 | ␉␉␉{␊ |
86 | ␉␉␉␉continue;␊ |
87 | ␉␉␉}␊ |
88 | ␊ |
89 | ␉␉␉new = (pci_dt_t*)malloc(sizeof(pci_dt_t));␊ |
90 | ␉␉␉if (!new)␊ |
91 | ␉␉␉{␊ |
92 | ␉␉␉␉continue;␊ |
93 | ␉␉␉}␊ |
94 | ␊ |
95 | ␉␉␉bzero(new, sizeof(pci_dt_t));␊ |
96 | ␊ |
97 | ␉␉␉new->dev.addr␉␉␉␉= pci_addr;␊ |
98 | ␉␉␉new->vendor_id␉␉␉␉= id & 0xffff;␊ |
99 | ␉␉␉new->device_id␉␉␉␉= (id >> 16) & 0xffff;␊ |
100 | ␉␉␉new->progif␉␉␉␉= pci_config_read8(pci_addr, PCI_CLASS_PROG);␊ |
101 | ␉␉␉new->revision_id␉␉␉= pci_config_read8(pci_addr, PCI_CLASS_REVISION);␊ |
102 | ␉␉␉new->subsys_id.subsys_id␉␉= pci_config_read32(pci_addr, PCI_SUBSYSTEM_VENDOR_ID);␊ |
103 | ␉␉␉new->class_id␉␉␉␉= pci_config_read16(pci_addr, PCI_CLASS_DEVICE);␊ |
104 | ␉␉␉//new->subclass_id␉␉␉= pci_config_read16(pci_addr, PCI_SUBCLASS_DEVICE);␊ |
105 | ␉␉␉new->parent␉= start;␊ |
106 | ␊ |
107 | ␉␉␉header_type = pci_config_read8(pci_addr, PCI_HEADER_TYPE);␊ |
108 | ␉␉␉switch (header_type & 0x7f)␊ |
109 | ␉␉␉{␊ |
110 | ␉␉␉␉case PCI_HEADER_TYPE_BRIDGE:␊ |
111 | ␉␉␉␉case PCI_HEADER_TYPE_CARDBUS:␊ |
112 | ␉␉␉␉␉secondary_bus = pci_config_read8(pci_addr, PCI_SECONDARY_BUS);␊ |
113 | ␉␉␉␉␉if (secondary_bus != 0)␊ |
114 | ␉␉␉␉␉{␊ |
115 | ␉␉␉␉␉␉scan_pci_bus(new, secondary_bus);␊ |
116 | ␉␉␉␉␉}␊ |
117 | ␉␉␉␉␉break;␊ |
118 | ␉␉␉␉default:␊ |
119 | ␉␉␉␉␉break;␊ |
120 | ␉␉␉}␊ |
121 | ␊ |
122 | ␉␉␉*current = new;␊ |
123 | ␉␉␉current = &new->next;␊ |
124 | ␊ |
125 | ␉␉␉if ((func == 0) && ((header_type & 0x80) == 0))␊ |
126 | ␉␉␉{␊ |
127 | ␉␉␉␉break;␊ |
128 | ␉␉␉}␊ |
129 | ␉␉}␊ |
130 | ␉}␊ |
131 | }␊ |
132 | ␊ |
133 | void enable_pci_devs(void)␊ |
134 | {␊ |
135 | ␉uint16_t id;␊ |
136 | ␉uint32_t rcba, *fd;␊ |
137 | ␊ |
138 | ␉id = pci_config_read16(PCIADDR(0, 0x00, 0), 0x00);␊ |
139 | ␉/* make sure we're on Intel chipset */␊ |
140 | ␉if (id != 0x8086)␊ |
141 | ␉{␊ |
142 | ␉␉return;␊ |
143 | ␉}␊ |
144 | ␊ |
145 | ␉rcba = pci_config_read32(PCIADDR(0, 0x1f, 0), 0xf0) & ~1; //this is LPC host␊ |
146 | ␉fd = (uint32_t *)(rcba + 0x3418);␊ |
147 | ␉/* set SMBus Disable (SD) to 0 */␊ |
148 | ␉*fd &= ~0x8;␊ |
149 | ␉/* and all devices? */␊ |
150 | ␉//*fd = 0x1;␊ |
151 | }␊ |
152 | ␊ |
153 | ␊ |
154 | void build_pci_dt(void)␊ |
155 | {␊ |
156 | ␉root_pci_dev = malloc(sizeof(pci_dt_t));␊ |
157 | ␊ |
158 | ␉if (!root_pci_dev)␊ |
159 | ␉{␊ |
160 | ␉␉return;␊ |
161 | ␉}␊ |
162 | ␊ |
163 | ␉bzero(root_pci_dev, sizeof(pci_dt_t));␊ |
164 | ␉enable_pci_devs();␊ |
165 | ␉scan_pci_bus(root_pci_dev, 0);␊ |
166 | ␊ |
167 | #if DEBUG_PCI␊ |
168 | ␉dump_pci_dt(root_pci_dev->children);␊ |
169 | ␉pause();␊ |
170 | #endif␊ |
171 | }␊ |
172 | ␊ |
173 | static char dev_path[256];␊ |
174 | ␊ |
175 | char *get_pci_dev_path(pci_dt_t *pci_dt)␊ |
176 | {␊ |
177 | ␉pci_dt_t␉*current;␊ |
178 | ␉pci_dt_t␉*end;␊ |
179 | ␉int␉␉dev_path_len = 0;␊ |
180 | ␊ |
181 | ␉dev_path[0] = 0;␊ |
182 | ␉end = root_pci_dev;␊ |
183 | ␉␊ |
184 | ␉int uid = getPciRootUID();␊ |
185 | ␉while (end != pci_dt)␊ |
186 | ␉{␊ |
187 | ␉␉current = pci_dt;␊ |
188 | ␉␉while (current->parent != end)␊ |
189 | ␉␉␉current = current->parent;␉␉␉␊ |
190 | ␉␉end = current;␊ |
191 | ␉␉if (current->parent == root_pci_dev)␊ |
192 | ␉␉{␊ |
193 | ␉␉␉dev_path_len += ␊ |
194 | ␉␉␉␉snprintf(dev_path + dev_path_len, sizeof(dev_path) - dev_path_len, "PciRoot(0x%x)/Pci(0x%x,0x%x)", uid, ␊ |
195 | ␉␉␉␉current->dev.bits.dev, current->dev.bits.func);␊ |
196 | ␉␉}␊ |
197 | ␉␉else␊ |
198 | ␉␉{␊ |
199 | ␉␉␉dev_path_len +=␊ |
200 | ␉␉␉␉snprintf(dev_path + dev_path_len, sizeof(dev_path) - dev_path_len, "/Pci(0x%x,0x%x)", ␊ |
201 | ␉␉␉␉current->dev.bits.dev, current->dev.bits.func);␊ |
202 | ␉␉}␊ |
203 | ␊ |
204 | ␉}␊ |
205 | ␉return dev_path;␊ |
206 | }␊ |
207 | ␊ |
208 | void dump_pci_dt(pci_dt_t *pci_dt)␊ |
209 | {␊ |
210 | ␉pci_dt_t␉*current;␊ |
211 | ␊ |
212 | ␉current = pci_dt;␊ |
213 | ␉while (current) {␊ |
214 | ␉␉printf("%02x:%02x.%x [%04x%02x] [%04x:%04x] (subsys [%04x:%04x]):: %s\n", ␊ |
215 | ␉␉␉current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func, ␊ |
216 | ␉␉␉current->class_id, current->progif,␊ |
217 | ␉␉␉current->vendor_id, current->device_id,␊ |
218 | ␉␉␉current->subsys_id.subsys.vendor_id, current->subsys_id.subsys.device_id, ␊ |
219 | ␉␉␉get_pci_dev_path(current));␊ |
220 | ␉␉dump_pci_dt(current->children);␊ |
221 | ␉␉current = current->next;␊ |
222 | ␉}␊ |
223 | }␊ |
224 | |