xref: /minix/minix/drivers/power/acpi/pci.c (revision 7f5f010b)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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