xref: /freebsd/sys/dev/acpica/acpi_resource.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
1 /*-
2  * Copyright (c) 2000 Michael Smith
3  * Copyright (c) 2000 BSDi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *	$FreeBSD$
28  */
29 
30 #include "opt_acpi.h"
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <machine/bus.h>
35 #include <machine/resource.h>
36 
37 #include "acpi.h"
38 
39 #include <dev/acpica/acpivar.h>
40 
41 /*
42  * Hooks for the ACPI CA debugging infrastructure
43  */
44 #define _COMPONENT	ACPI_BUS
45 MODULE_NAME("RESOURCE")
46 
47 /*
48  * Fetch a device's resources and associate them with the device.
49  *
50  * Note that it might be nice to also locate ACPI-specific resource items, such
51  * as GPE bits.
52  */
53 ACPI_STATUS
54 acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set)
55 {
56     ACPI_BUFFER		buf;
57     ACPI_RESOURCE	*res;
58     char		*curr, *last;
59     ACPI_STATUS		status;
60     int			i;
61     void		*context;
62 
63     FUNCTION_TRACE(__func__);
64 
65     /*
66      * Fetch the device resources
67      */
68     if (((status = acpi_GetIntoBuffer(handle, AcpiGetPossibleResources, &buf)) != AE_OK) &&
69 	((status = acpi_GetIntoBuffer(handle, AcpiGetCurrentResources, &buf)) != AE_OK)) {
70 	device_printf(dev, "can't fetch ACPI resources - %s\n", acpi_strerror(status));
71 	return_ACPI_STATUS(status);
72     }
73     DEBUG_PRINT(TRACE_RESOURCES, ("got %d bytes of resources\n", buf.Length));
74     set->set_init(dev, &context);
75 
76     /*
77      * Iterate through the resources
78      */
79     curr = buf.Pointer;
80     last = (char *)buf.Pointer + buf.Length;
81     while (curr < last) {
82 	res = (ACPI_RESOURCE *)curr;
83 	curr += res->Length;
84 
85 	/*
86 	 * Handle the individual resource types
87 	 */
88 	switch(res->Id) {
89 	case ACPI_RSTYPE_END_TAG:
90 	    DEBUG_PRINT(TRACE_RESOURCES, ("EndTag\n"));
91 	    curr = last;
92 	    break;
93 
94 	case ACPI_RSTYPE_FIXED_IO:
95 	    DEBUG_PRINT(TRACE_RESOURCES, ("FixedIo 0x%x/%d\n", res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength));
96 	    set->set_ioport(dev, context, res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength);
97 	    break;
98 
99 	case ACPI_RSTYPE_IO:
100 	    if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
101 		DEBUG_PRINT(TRACE_RESOURCES, ("Io 0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength));
102 		set->set_ioport(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength);
103 	    } else {
104 		DEBUG_PRINT(TRACE_RESOURCES, ("Io 0x%x-0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
105 					      res->Data.Io.RangeLength));
106 		set->set_iorange(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
107 				 res->Data.Io.RangeLength, res->Data.Io.Alignment);
108 	    }
109 	    break;
110 
111 	case ACPI_RSTYPE_FIXED_MEM32:
112 	    DEBUG_PRINT(TRACE_RESOURCES, ("FixedMemory32 0x%x/%d\n", res->Data.FixedMemory32.RangeBaseAddress,
113 					  res->Data.FixedMemory32.RangeLength));
114 	    set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress,
115 			    res->Data.FixedMemory32.RangeLength);
116 	    break;
117 
118 	case ACPI_RSTYPE_MEM32:
119 	    if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) {
120 		DEBUG_PRINT(TRACE_RESOURCES, ("Memory32 0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
121 					      res->Data.Memory32.RangeLength));
122 		set->set_memory(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.RangeLength);
123 	    } else {
124 		DEBUG_PRINT(TRACE_RESOURCES, ("Memory32 0x%x-0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
125 					      res->Data.Memory32.MaxBaseAddress, res->Data.Memory32.RangeLength));
126 		set->set_memoryrange(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.MaxBaseAddress,
127 				     res->Data.Memory32.RangeLength, res->Data.Memory32.Alignment);
128 	    }
129 	    break;
130 
131 	case ACPI_RSTYPE_MEM24:
132 	    if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) {
133 		DEBUG_PRINT(TRACE_RESOURCES, ("Memory24 0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
134 					      res->Data.Memory24.RangeLength));
135 		set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.RangeLength);
136 	    } else {
137 		DEBUG_PRINT(TRACE_RESOURCES, ("Memory24 0x%x-0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
138 					      res->Data.Memory24.MaxBaseAddress, res->Data.Memory24.RangeLength));
139 		set->set_memoryrange(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.MaxBaseAddress,
140 				     res->Data.Memory24.RangeLength, res->Data.Memory24.Alignment);
141 	    }
142 	    break;
143 
144 	case ACPI_RSTYPE_IRQ:
145 	    for (i = 0; i < res->Data.Irq.NumberOfInterrupts; i++) {
146 		DEBUG_PRINT(TRACE_RESOURCES, ("Irq %d\n", res->Data.Irq.Interrupts[i]));
147 		set->set_irq(dev, context, res->Data.Irq.Interrupts[i]);
148 	    }
149 	    break;
150 
151 	case ACPI_RSTYPE_DMA:
152 	    for (i = 0; i < res->Data.Dma.NumberOfChannels; i++) {
153 		DEBUG_PRINT(TRACE_RESOURCES, ("Drq %d\n", res->Data.Dma.Channels[i]));
154 		set->set_drq(dev, context, res->Data.Dma.Channels[i]);
155 	    }
156 	    break;
157 
158 	case ACPI_RSTYPE_START_DPF:
159 	    DEBUG_PRINT(TRACE_RESOURCES, ("start dependant functions"));
160 	    set->set_start_dependant(dev, context, res->Data.StartDpf.CompatibilityPriority);
161 	    break;
162 
163 	case ACPI_RSTYPE_END_DPF:
164 	    DEBUG_PRINT(TRACE_RESOURCES, ("end dependant functions"));
165 	    set->set_end_dependant(dev, context);
166 	    break;
167 
168 	case ACPI_RSTYPE_ADDRESS32:
169 	    DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented Address32 resource\n"));
170 	    break;
171 
172 	case ACPI_RSTYPE_ADDRESS16:
173 	    DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented Address16 resource\n"));
174 	    break;
175 
176 	case ACPI_RSTYPE_EXT_IRQ:
177 	    DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented ExtendedIrq resource\n"));
178 	    break;
179 
180 	case ACPI_RSTYPE_VENDOR:
181 	    DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented VendorSpecific resource\n"));
182 	    break;
183 	default:
184 	    break;
185 	}
186     }
187     AcpiOsFree(buf.Pointer);
188     set->set_done(dev, context);
189     return_ACPI_STATUS(AE_OK);
190 }
191 
192 static void	acpi_res_set_init(device_t dev, void **context);
193 static void	acpi_res_set_done(device_t dev, void *context);
194 static void	acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length);
195 static void	acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high,
196 				     u_int32_t length, u_int32_t align);
197 static void	acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
198 static void	acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high,
199 					 u_int32_t length, u_int32_t align);
200 static void	acpi_res_set_irq(device_t dev, void *context, u_int32_t irq);
201 static void	acpi_res_set_drq(device_t dev, void *context, u_int32_t drq);
202 static void	acpi_res_set_start_dependant(device_t dev, void *context, int preference);
203 static void	acpi_res_set_end_dependant(device_t dev, void *context);
204 
205 struct acpi_parse_resource_set acpi_res_parse_set = {
206     acpi_res_set_init,
207     acpi_res_set_done,
208     acpi_res_set_ioport,
209     acpi_res_set_iorange,
210     acpi_res_set_memory,
211     acpi_res_set_memoryrange,
212     acpi_res_set_irq,
213     acpi_res_set_drq,
214     acpi_res_set_start_dependant,
215     acpi_res_set_end_dependant
216 };
217 
218 struct acpi_res_context {
219     int		ar_nio;
220     int		ar_nmem;
221     int		ar_nirq;
222 };
223 
224 static void
225 acpi_res_set_init(device_t dev, void **context)
226 {
227     struct acpi_res_context	*cp;
228 
229     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
230 	bzero(cp, sizeof(*cp));
231 	*context = cp;
232     }
233 }
234 
235 static void
236 acpi_res_set_done(device_t dev, void *context)
237 {
238     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
239 
240     if (cp == NULL)
241 	return;
242     AcpiOsFree(cp);
243 }
244 
245 static void
246 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
247 {
248     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
249 
250     if (cp == NULL)
251 	return;
252     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
253 }
254 
255 static void
256 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
257 {
258     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
259 
260     if (cp == NULL)
261 	return;
262     device_printf(dev, "I/O range not supported\n");
263 }
264 
265 static void
266 acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
267 {
268     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
269 
270     if (cp == NULL)
271 	return;
272     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
273 }
274 
275 static void
276 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
277 {
278     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
279 
280     if (cp == NULL)
281 	return;
282     device_printf(dev, "memory range not supported\n");
283 }
284 
285 static void
286 acpi_res_set_irq(device_t dev, void *context, u_int32_t irq)
287 {
288     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
289 
290     if (cp == NULL)
291 	return;
292     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq, 1);
293 }
294 
295 static void
296 acpi_res_set_drq(device_t dev, void *context, u_int32_t drq)
297 {
298     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
299 
300     if (cp == NULL)
301 	return;
302     device_printf(dev, "DRQ not supported\n");
303 }
304 
305 static void
306 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
307 {
308     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
309 
310     if (cp == NULL)
311 	return;
312     device_printf(dev, "dependant functions not supported");
313 }
314 
315 static void
316 acpi_res_set_end_dependant(device_t dev, void *context)
317 {
318     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
319 
320     if (cp == NULL)
321 	return;
322 }
323