1 #include <minix/driver.h>
2 #include <acpi.h>
3 #include <assert.h>
4 #include <minix/acpi.h>
5
6 #include "acpi_globals.h"
7
8 #define PCI_MAX_DEVICES 32
9 #define PCI_MAX_PINS 4
10
11 #define IRQ_TABLE_ENTRIES (PCI_MAX_DEVICES * PCI_MAX_PINS)
12
13 struct pci_bridge {
14 ACPI_HANDLE handle;
15 int irqtable[IRQ_TABLE_ENTRIES];
16 int primary_bus;
17 int secondary_bus;
18 unsigned device;
19 struct pci_bridge * parent;
20 struct pci_bridge * children[PCI_MAX_DEVICES];
21 };
22
23 static struct pci_bridge pci_root_bridge;
24
25 struct irq_resource {
26 struct pci_bridge * bridge;
27 ACPI_PCI_ROUTING_TABLE * tbl;
28 };
29
find_bridge(struct pci_bridge * root,int pbnr,int dev,int sbnr)30 static struct pci_bridge * find_bridge(struct pci_bridge * root,
31 int pbnr,
32 int dev,
33 int sbnr)
34 {
35 if (!root)
36 return NULL;
37
38 if (sbnr == -1) {
39 if (root->secondary_bus == pbnr)
40 return root->children[dev];
41 else {
42 /* serach all children */
43 unsigned d;
44 for (d = 0; d < PCI_MAX_DEVICES; d++) {
45 struct pci_bridge * b;
46 b = find_bridge(root->children[d],
47 pbnr, dev, sbnr);
48 if (b)
49 return b;
50 }
51 }
52 } else {
53 if (root->secondary_bus == sbnr)
54 return root;
55 else {
56 /* check all children */
57 unsigned d;
58 for (d = 0; d < PCI_MAX_DEVICES; d++) {
59 struct pci_bridge * b;
60 b = find_bridge(root->children[d],
61 pbnr, dev, sbnr);
62 if (b)
63 return b;
64 }
65 }
66 }
67
68 return NULL;
69 }
70
do_map_bridge(message * m)71 void do_map_bridge(message *m)
72 {
73 int err = OK;
74 unsigned dev = ((struct acpi_map_bridge_req *)m)->device;
75 unsigned pbnr = ((struct acpi_map_bridge_req *)m)->primary_bus;
76 unsigned sbnr = ((struct acpi_map_bridge_req *)m)->secondary_bus;
77
78 struct pci_bridge * bridge;
79
80 bridge = find_bridge(&pci_root_bridge, pbnr, dev, -1);
81
82 if (!bridge) {
83 err = ENODEV;
84 goto map_error;
85 }
86
87 bridge->primary_bus = pbnr;
88 bridge->secondary_bus = sbnr;
89
90 map_error:
91 ((struct acpi_map_bridge_resp *)m)->err = err;
92 }
93
94 #if 0
95 static ACPI_STATUS device_get_int(ACPI_HANDLE handle,
96 char * name,
97 ACPI_INTEGER * val)
98 {
99 ACPI_STATUS status;
100 char buff[sizeof(ACPI_OBJECT)];
101 ACPI_BUFFER abuff;
102
103 abuff.Length = sizeof(buff);
104 abuff.Pointer = buff;
105
106 status = AcpiEvaluateObjectTyped(handle, name, NULL,
107 &abuff, ACPI_TYPE_INTEGER);
108 if (ACPI_SUCCESS(status)) {
109 *val = ((ACPI_OBJECT *)abuff.Pointer)->Integer.Value;
110 }
111
112 return status;
113 }
114 #endif
115
do_get_irq(message * m)116 void do_get_irq(message *m)
117 {
118 struct pci_bridge * bridge;
119 int irq;
120
121 unsigned bus = ((struct acpi_get_irq_req *)m)->bus;
122 unsigned dev = ((struct acpi_get_irq_req *)m)->dev;
123 unsigned pin = ((struct acpi_get_irq_req *)m)->pin;
124
125 assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
126
127 bridge = find_bridge(&pci_root_bridge, -1, -1, bus);
128
129 if (!bridge)
130 irq = -1;
131 else
132 irq = bridge->irqtable[dev * PCI_MAX_PINS + pin];
133
134 ((struct acpi_get_irq_resp *)m)->irq = irq;
135 }
136
add_irq(struct pci_bridge * bridge,unsigned dev,unsigned pin,u8_t irq)137 static void add_irq(struct pci_bridge * bridge,
138 unsigned dev,
139 unsigned pin,
140 u8_t irq)
141 {
142 assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
143
144 bridge->irqtable[dev * PCI_MAX_PINS + pin] = irq;
145 }
146
get_irq_resource(ACPI_RESOURCE * res,void * context)147 static ACPI_STATUS get_irq_resource(ACPI_RESOURCE *res, void *context)
148 {
149 struct irq_resource * ires = (struct irq_resource *) context;
150
151 if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
152 ACPI_RESOURCE_IRQ *irq;
153
154 irq = &res->Data.Irq;
155 add_irq(ires->bridge, ires->tbl->Address >> 16, ires->tbl->Pin,
156 irq->Interrupts[ires->tbl->SourceIndex]);
157 } else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
158 ACPI_RESOURCE_EXTENDED_IRQ *irq;
159
160 irq = &res->Data.ExtendedIrq;
161 add_irq(ires->bridge, ires->tbl->Address >> 16, ires->tbl->Pin,
162 irq->Interrupts[ires->tbl->SourceIndex]);
163 }
164
165 return AE_OK;
166 }
167
get_pci_irq_routing(struct pci_bridge * bridge)168 static ACPI_STATUS get_pci_irq_routing(struct pci_bridge * bridge)
169 {
170 ACPI_STATUS status;
171 ACPI_BUFFER abuff;
172 char buff[4096];
173 ACPI_PCI_ROUTING_TABLE *tbl;
174 ACPI_DEVICE_INFO *info;
175 int i;
176
177 abuff.Length = sizeof(buff);
178 abuff.Pointer = buff;
179
180 status = AcpiGetIrqRoutingTable(bridge->handle, &abuff);
181 if (ACPI_FAILURE(status)) {
182 return AE_OK;
183 }
184
185 info = abuff.Pointer;
186 status = AcpiGetObjectInfo(bridge->handle, &info);
187 if (ACPI_FAILURE(status))
188 return status;
189 /*
190 * Decode the device number (upper half of the address) and attach the
191 * new bridge in the children list of its parent
192 */
193 bridge->device = info->Address >> 16;
194 if (bridge != &pci_root_bridge) {
195 bridge->parent->children[bridge->device] = bridge;
196 bridge->primary_bus = bridge->secondary_bus = -1;
197 }
198
199
200 for (i = 0; i < PCI_MAX_DEVICES; i++)
201 bridge->children[i] = NULL;
202
203 for (tbl = (ACPI_PCI_ROUTING_TABLE *)abuff.Pointer; tbl->Length;
204 tbl = (ACPI_PCI_ROUTING_TABLE *)
205 ((char *)tbl + tbl->Length)) {
206 ACPI_HANDLE src_handle;
207 struct irq_resource ires;
208
209 if (*(char*)tbl->Source == '\0') {
210 add_irq(bridge, tbl->Address >> 16,
211 tbl->Pin, tbl->SourceIndex);
212 continue;
213 }
214
215 status = AcpiGetHandle(bridge->handle, tbl->Source, &src_handle);
216 if (ACPI_FAILURE(status)) {
217 printf("Failed AcpiGetHandle\n");
218 continue;
219 }
220 ires.bridge = bridge;
221 ires.tbl = tbl;
222 status = AcpiWalkResources(src_handle, METHOD_NAME__CRS,
223 get_irq_resource, &ires);
224 if (ACPI_FAILURE(status)) {
225 printf("Failed IRQ resource\n");
226 continue;
227 }
228 }
229
230 return AE_OK;
231 }
232
bridge_init_irqtable(struct pci_bridge * bridge)233 static void bridge_init_irqtable(struct pci_bridge * bridge)
234 {
235 int i;
236
237 for (i = 0; i < IRQ_TABLE_ENTRIES; i++)
238 bridge->irqtable[i] = -1;
239 }
240
add_pci_dev(ACPI_HANDLE handle,UINT32 level,void * context,void ** retval)241 static ACPI_STATUS add_pci_dev(ACPI_HANDLE handle,
242 UINT32 level,
243 void *context,
244 void **retval)
245 {
246 ACPI_STATUS status;
247 ACPI_BUFFER abuff;
248 char buff[4096];
249 ACPI_HANDLE parent_handle;
250 struct pci_bridge * bridge;
251 struct pci_bridge * parent_bridge = (struct pci_bridge *) context;
252
253
254 /* skip pci root when we get to it again */
255 if (handle == pci_root_bridge.handle)
256 return AE_OK;
257
258 status = AcpiGetParent(handle, &parent_handle);
259 if (!ACPI_SUCCESS(status))
260 return status;
261 /* skip devices that have a different parent */
262 if (parent_handle != parent_bridge->handle)
263 return AE_OK;
264
265 abuff.Length = sizeof(buff);
266 abuff.Pointer = buff;
267
268 bridge = malloc(sizeof(struct pci_bridge));
269 if (!bridge)
270 return AE_NO_MEMORY;
271 bridge->handle = handle;
272 bridge->parent = parent_bridge;
273 bridge_init_irqtable(bridge);
274
275 status = get_pci_irq_routing(bridge);
276 if (!(ACPI_SUCCESS(status))) {
277 free(bridge);
278 return status;
279 }
280
281 /* get the pci bridges */
282 status = AcpiGetDevices(NULL, add_pci_dev, bridge, NULL);
283 return status;
284 }
285
add_pci_root_dev(ACPI_HANDLE handle,UINT32 level,void * context,void ** retval)286 static ACPI_STATUS add_pci_root_dev(ACPI_HANDLE handle,
287 UINT32 level,
288 void *context,
289 void **retval)
290 {
291 static unsigned called;
292 ACPI_STATUS status;
293
294 if (++called > 1) {
295 printf("ACPI: Warning! Multi rooted PCI is not supported!\n");
296 return AE_OK;
297 }
298
299 pci_root_bridge.handle = handle;
300 pci_root_bridge.primary_bus = -1; /* undefined */
301 pci_root_bridge.secondary_bus = 0; /* root bus is 0 in a single root
302 system */
303 bridge_init_irqtable(&pci_root_bridge);
304
305 status = get_pci_irq_routing(&pci_root_bridge);
306 if (!ACPI_SUCCESS(status))
307 return status;
308
309 /* get the pci bridges */
310 status = AcpiGetDevices(NULL, add_pci_dev, &pci_root_bridge, NULL);
311 return status;
312 }
313
pci_scan_devices(void)314 void pci_scan_devices(void)
315 {
316 ACPI_STATUS status;
317
318 /* do not scan devices in PIC mode */
319 if (!machine.apic_enabled)
320 return;
321
322 /* get the root first */
323 status = AcpiGetDevices("PNP0A03", add_pci_root_dev, NULL, NULL);
324 assert(ACPI_SUCCESS(status));
325 }
326