kernel: scheduling fix for ARM
[minix.git] / drivers / acpi / pci.c
blob6db5259d7a64f4ae0c90f534c6f6145f84c29bf9
1 #include <minix/driver.h>
2 #include <acpi.h>
3 #include <assert.h>
4 #include <minix/acpi.h>
6 #include "acpi_globals.h"
8 #define PCI_MAX_DEVICES 32
9 #define PCI_MAX_PINS 4
11 #define IRQ_TABLE_ENTRIES (PCI_MAX_DEVICES * PCI_MAX_PINS)
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];
23 static struct pci_bridge pci_root_bridge;
25 struct irq_resource {
26 struct pci_bridge * bridge;
27 ACPI_PCI_ROUTING_TABLE * tbl;
30 static struct pci_bridge * find_bridge(struct pci_bridge * root,
31 int pbnr,
32 int dev,
33 int sbnr)
35 if (!root)
36 return NULL;
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;
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;
68 return NULL;
71 void do_map_bridge(message *m)
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;
78 struct pci_bridge * bridge;
80 bridge = find_bridge(&pci_root_bridge, pbnr, dev, -1);
82 if (!bridge) {
83 err = ENODEV;
84 goto map_error;
87 bridge->primary_bus = pbnr;
88 bridge->secondary_bus = sbnr;
90 map_error:
91 ((struct acpi_map_bridge_resp *)m)->err = err;
94 #if 0
95 static ACPI_STATUS device_get_int(ACPI_HANDLE handle,
96 char * name,
97 ACPI_INTEGER * val)
99 ACPI_STATUS status;
100 char buff[sizeof(ACPI_OBJECT)];
101 ACPI_BUFFER abuff;
103 abuff.Length = sizeof(buff);
104 abuff.Pointer = buff;
106 status = AcpiEvaluateObjectTyped(handle, name, NULL,
107 &abuff, ACPI_TYPE_INTEGER);
108 if (ACPI_SUCCESS(status)) {
109 *val = ((ACPI_OBJECT *)abuff.Pointer)->Integer.Value;
112 return status;
114 #endif
116 void do_get_irq(message *m)
118 struct pci_bridge * bridge;
119 int irq;
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;
125 assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
127 bridge = find_bridge(&pci_root_bridge, -1, -1, bus);
129 if (!bridge)
130 irq = -1;
131 else
132 irq = bridge->irqtable[dev * PCI_MAX_PINS + pin];
134 ((struct acpi_get_irq_resp *)m)->irq = irq;
137 static void add_irq(struct pci_bridge * bridge,
138 unsigned dev,
139 unsigned pin,
140 u8_t irq)
142 assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
144 bridge->irqtable[dev * PCI_MAX_PINS + pin] = irq;
147 static ACPI_STATUS get_irq_resource(ACPI_RESOURCE *res, void *context)
149 struct irq_resource * ires = (struct irq_resource *) context;
151 if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
152 ACPI_RESOURCE_IRQ *irq;
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;
160 irq = &res->Data.ExtendedIrq;
161 add_irq(ires->bridge, ires->tbl->Address >> 16, ires->tbl->Pin,
162 irq->Interrupts[ires->tbl->SourceIndex]);
165 return AE_OK;
168 static ACPI_STATUS get_pci_irq_routing(struct pci_bridge * bridge)
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;
177 abuff.Length = sizeof(buff);
178 abuff.Pointer = buff;
180 status = AcpiGetIrqRoutingTable(bridge->handle, &abuff);
181 if (ACPI_FAILURE(status)) {
182 return AE_OK;
185 info = abuff.Pointer;
186 status = AcpiGetObjectInfo(bridge->handle, &info);
187 if (ACPI_FAILURE(status))
188 return status;
190 * Decode the device number (upper half of the address) and attach the
191 * new bridge in the children list of its parent
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;
200 for (i = 0; i < PCI_MAX_DEVICES; i++)
201 bridge->children[i] = NULL;
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;
209 if (*(char*)tbl->Source == '\0') {
210 add_irq(bridge, tbl->Address >> 16,
211 tbl->Pin, tbl->SourceIndex);
212 continue;
215 status = AcpiGetHandle(bridge->handle, tbl->Source, &src_handle);
216 if (ACPI_FAILURE(status)) {
217 printf("Failed AcpiGetHandle\n");
218 continue;
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;
230 return AE_OK;
233 static void bridge_init_irqtable(struct pci_bridge * bridge)
235 int i;
237 for (i = 0; i < IRQ_TABLE_ENTRIES; i++)
238 bridge->irqtable[i] = -1;
241 static ACPI_STATUS add_pci_dev(ACPI_HANDLE handle,
242 UINT32 level,
243 void *context,
244 void **retval)
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;
254 /* skip pci root when we get to it again */
255 if (handle == pci_root_bridge.handle)
256 return AE_OK;
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;
265 abuff.Length = sizeof(buff);
266 abuff.Pointer = buff;
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);
275 status = get_pci_irq_routing(bridge);
276 if (!(ACPI_SUCCESS(status))) {
277 free(bridge);
278 return status;
281 /* get the pci bridges */
282 status = AcpiGetDevices(NULL, add_pci_dev, bridge, NULL);
283 return status;
286 static ACPI_STATUS add_pci_root_dev(ACPI_HANDLE handle,
287 UINT32 level,
288 void *context,
289 void **retval)
291 static unsigned called;
292 ACPI_STATUS status;
294 if (++called > 1) {
295 printf("ACPI: Warning! Multi rooted PCI is not supported!\n");
296 return AE_OK;
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);
305 status = get_pci_irq_routing(&pci_root_bridge);
306 if (!ACPI_SUCCESS(status))
307 return status;
309 /* get the pci bridges */
310 status = AcpiGetDevices(NULL, add_pci_dev, &pci_root_bridge, NULL);
311 return status;
314 void pci_scan_devices(void)
316 ACPI_STATUS status;
318 /* do not scan devices in PIC mode */
319 if (!machine.apic_enabled)
320 return;
322 /* get the root first */
323 status = AcpiGetDevices("PNP0A03", add_pci_root_dev, NULL, NULL);
324 assert(ACPI_SUCCESS(status));