1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /******************************************************************************* |
3 | * |
4 | * Module Name: rsxface - Public interfaces to the resource manager |
5 | * |
6 | ******************************************************************************/ |
7 | |
8 | #define EXPORT_ACPI_INTERFACES |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acresrc.h" |
13 | #include "acnamesp.h" |
14 | |
15 | #define _COMPONENT ACPI_RESOURCES |
16 | ACPI_MODULE_NAME("rsxface" ) |
17 | |
18 | /* Local macros for 16,32-bit to 64-bit conversion */ |
19 | #define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field) |
20 | #define ACPI_COPY_ADDRESS(out, in) \ |
21 | ACPI_COPY_FIELD(out, in, resource_type); \ |
22 | ACPI_COPY_FIELD(out, in, producer_consumer); \ |
23 | ACPI_COPY_FIELD(out, in, decode); \ |
24 | ACPI_COPY_FIELD(out, in, min_address_fixed); \ |
25 | ACPI_COPY_FIELD(out, in, max_address_fixed); \ |
26 | ACPI_COPY_FIELD(out, in, info); \ |
27 | ACPI_COPY_FIELD(out, in, address.granularity); \ |
28 | ACPI_COPY_FIELD(out, in, address.minimum); \ |
29 | ACPI_COPY_FIELD(out, in, address.maximum); \ |
30 | ACPI_COPY_FIELD(out, in, address.translation_offset); \ |
31 | ACPI_COPY_FIELD(out, in, address.address_length); \ |
32 | ACPI_COPY_FIELD(out, in, resource_source); |
33 | /* Local prototypes */ |
34 | static acpi_status |
35 | acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context); |
36 | |
37 | static acpi_status |
38 | acpi_rs_validate_parameters(acpi_handle device_handle, |
39 | struct acpi_buffer *buffer, |
40 | struct acpi_namespace_node **return_node); |
41 | |
42 | /******************************************************************************* |
43 | * |
44 | * FUNCTION: acpi_rs_validate_parameters |
45 | * |
46 | * PARAMETERS: device_handle - Handle to a device |
47 | * buffer - Pointer to a data buffer |
48 | * return_node - Pointer to where the device node is returned |
49 | * |
50 | * RETURN: Status |
51 | * |
52 | * DESCRIPTION: Common parameter validation for resource interfaces |
53 | * |
54 | ******************************************************************************/ |
55 | |
56 | static acpi_status |
57 | acpi_rs_validate_parameters(acpi_handle device_handle, |
58 | struct acpi_buffer *buffer, |
59 | struct acpi_namespace_node **return_node) |
60 | { |
61 | acpi_status status; |
62 | struct acpi_namespace_node *node; |
63 | |
64 | ACPI_FUNCTION_TRACE(rs_validate_parameters); |
65 | |
66 | /* |
67 | * Must have a valid handle to an ACPI device |
68 | */ |
69 | if (!device_handle) { |
70 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
71 | } |
72 | |
73 | node = acpi_ns_validate_handle(handle: device_handle); |
74 | if (!node) { |
75 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
76 | } |
77 | |
78 | if (node->type != ACPI_TYPE_DEVICE) { |
79 | return_ACPI_STATUS(AE_TYPE); |
80 | } |
81 | |
82 | /* |
83 | * Validate the user buffer object |
84 | * |
85 | * if there is a non-zero buffer length we also need a valid pointer in |
86 | * the buffer. If it's a zero buffer length, we'll be returning the |
87 | * needed buffer size (later), so keep going. |
88 | */ |
89 | status = acpi_ut_validate_buffer(buffer); |
90 | if (ACPI_FAILURE(status)) { |
91 | return_ACPI_STATUS(status); |
92 | } |
93 | |
94 | *return_node = node; |
95 | return_ACPI_STATUS(AE_OK); |
96 | } |
97 | |
98 | /******************************************************************************* |
99 | * |
100 | * FUNCTION: acpi_get_irq_routing_table |
101 | * |
102 | * PARAMETERS: device_handle - Handle to the Bus device we are querying |
103 | * ret_buffer - Pointer to a buffer to receive the |
104 | * current resources for the device |
105 | * |
106 | * RETURN: Status |
107 | * |
108 | * DESCRIPTION: This function is called to get the IRQ routing table for a |
109 | * specific bus. The caller must first acquire a handle for the |
110 | * desired bus. The routine table is placed in the buffer pointed |
111 | * to by the ret_buffer variable parameter. |
112 | * |
113 | * If the function fails an appropriate status will be returned |
114 | * and the value of ret_buffer is undefined. |
115 | * |
116 | * This function attempts to execute the _PRT method contained in |
117 | * the object indicated by the passed device_handle. |
118 | * |
119 | ******************************************************************************/ |
120 | |
121 | acpi_status |
122 | acpi_get_irq_routing_table(acpi_handle device_handle, |
123 | struct acpi_buffer *ret_buffer) |
124 | { |
125 | acpi_status status; |
126 | struct acpi_namespace_node *node; |
127 | |
128 | ACPI_FUNCTION_TRACE(acpi_get_irq_routing_table); |
129 | |
130 | /* Validate parameters then dispatch to internal routine */ |
131 | |
132 | status = acpi_rs_validate_parameters(device_handle, buffer: ret_buffer, return_node: &node); |
133 | if (ACPI_FAILURE(status)) { |
134 | return_ACPI_STATUS(status); |
135 | } |
136 | |
137 | status = acpi_rs_get_prt_method_data(node, ret_buffer); |
138 | return_ACPI_STATUS(status); |
139 | } |
140 | |
141 | ACPI_EXPORT_SYMBOL(acpi_get_irq_routing_table) |
142 | |
143 | /******************************************************************************* |
144 | * |
145 | * FUNCTION: acpi_get_current_resources |
146 | * |
147 | * PARAMETERS: device_handle - Handle to the device object for the |
148 | * device we are querying |
149 | * ret_buffer - Pointer to a buffer to receive the |
150 | * current resources for the device |
151 | * |
152 | * RETURN: Status |
153 | * |
154 | * DESCRIPTION: This function is called to get the current resources for a |
155 | * specific device. The caller must first acquire a handle for |
156 | * the desired device. The resource data is placed in the buffer |
157 | * pointed to by the ret_buffer variable parameter. |
158 | * |
159 | * If the function fails an appropriate status will be returned |
160 | * and the value of ret_buffer is undefined. |
161 | * |
162 | * This function attempts to execute the _CRS method contained in |
163 | * the object indicated by the passed device_handle. |
164 | * |
165 | ******************************************************************************/ |
166 | acpi_status |
167 | acpi_get_current_resources(acpi_handle device_handle, |
168 | struct acpi_buffer *ret_buffer) |
169 | { |
170 | acpi_status status; |
171 | struct acpi_namespace_node *node; |
172 | |
173 | ACPI_FUNCTION_TRACE(acpi_get_current_resources); |
174 | |
175 | /* Validate parameters then dispatch to internal routine */ |
176 | |
177 | status = acpi_rs_validate_parameters(device_handle, buffer: ret_buffer, return_node: &node); |
178 | if (ACPI_FAILURE(status)) { |
179 | return_ACPI_STATUS(status); |
180 | } |
181 | |
182 | status = acpi_rs_get_crs_method_data(node, ret_buffer); |
183 | return_ACPI_STATUS(status); |
184 | } |
185 | |
186 | ACPI_EXPORT_SYMBOL(acpi_get_current_resources) |
187 | |
188 | /******************************************************************************* |
189 | * |
190 | * FUNCTION: acpi_get_possible_resources |
191 | * |
192 | * PARAMETERS: device_handle - Handle to the device object for the |
193 | * device we are querying |
194 | * ret_buffer - Pointer to a buffer to receive the |
195 | * resources for the device |
196 | * |
197 | * RETURN: Status |
198 | * |
199 | * DESCRIPTION: This function is called to get a list of the possible resources |
200 | * for a specific device. The caller must first acquire a handle |
201 | * for the desired device. The resource data is placed in the |
202 | * buffer pointed to by the ret_buffer variable. |
203 | * |
204 | * If the function fails an appropriate status will be returned |
205 | * and the value of ret_buffer is undefined. |
206 | * |
207 | ******************************************************************************/ |
208 | acpi_status |
209 | acpi_get_possible_resources(acpi_handle device_handle, |
210 | struct acpi_buffer *ret_buffer) |
211 | { |
212 | acpi_status status; |
213 | struct acpi_namespace_node *node; |
214 | |
215 | ACPI_FUNCTION_TRACE(acpi_get_possible_resources); |
216 | |
217 | /* Validate parameters then dispatch to internal routine */ |
218 | |
219 | status = acpi_rs_validate_parameters(device_handle, buffer: ret_buffer, return_node: &node); |
220 | if (ACPI_FAILURE(status)) { |
221 | return_ACPI_STATUS(status); |
222 | } |
223 | |
224 | status = acpi_rs_get_prs_method_data(node, ret_buffer); |
225 | return_ACPI_STATUS(status); |
226 | } |
227 | |
228 | ACPI_EXPORT_SYMBOL(acpi_get_possible_resources) |
229 | |
230 | /******************************************************************************* |
231 | * |
232 | * FUNCTION: acpi_set_current_resources |
233 | * |
234 | * PARAMETERS: device_handle - Handle to the device object for the |
235 | * device we are setting resources |
236 | * in_buffer - Pointer to a buffer containing the |
237 | * resources to be set for the device |
238 | * |
239 | * RETURN: Status |
240 | * |
241 | * DESCRIPTION: This function is called to set the current resources for a |
242 | * specific device. The caller must first acquire a handle for |
243 | * the desired device. The resource data is passed to the routine |
244 | * the buffer pointed to by the in_buffer variable. |
245 | * |
246 | ******************************************************************************/ |
247 | acpi_status |
248 | acpi_set_current_resources(acpi_handle device_handle, |
249 | struct acpi_buffer *in_buffer) |
250 | { |
251 | acpi_status status; |
252 | struct acpi_namespace_node *node; |
253 | |
254 | ACPI_FUNCTION_TRACE(acpi_set_current_resources); |
255 | |
256 | /* Validate the buffer, don't allow zero length */ |
257 | |
258 | if ((!in_buffer) || (!in_buffer->pointer) || (!in_buffer->length)) { |
259 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
260 | } |
261 | |
262 | /* Validate parameters then dispatch to internal routine */ |
263 | |
264 | status = acpi_rs_validate_parameters(device_handle, buffer: in_buffer, return_node: &node); |
265 | if (ACPI_FAILURE(status)) { |
266 | return_ACPI_STATUS(status); |
267 | } |
268 | |
269 | status = acpi_rs_set_srs_method_data(node, ret_buffer: in_buffer); |
270 | return_ACPI_STATUS(status); |
271 | } |
272 | |
273 | ACPI_EXPORT_SYMBOL(acpi_set_current_resources) |
274 | |
275 | /******************************************************************************* |
276 | * |
277 | * FUNCTION: acpi_get_event_resources |
278 | * |
279 | * PARAMETERS: device_handle - Handle to the device object for the |
280 | * device we are getting resources |
281 | * in_buffer - Pointer to a buffer containing the |
282 | * resources to be set for the device |
283 | * |
284 | * RETURN: Status |
285 | * |
286 | * DESCRIPTION: This function is called to get the event resources for a |
287 | * specific device. The caller must first acquire a handle for |
288 | * the desired device. The resource data is passed to the routine |
289 | * the buffer pointed to by the in_buffer variable. Uses the |
290 | * _AEI method. |
291 | * |
292 | ******************************************************************************/ |
293 | acpi_status |
294 | acpi_get_event_resources(acpi_handle device_handle, |
295 | struct acpi_buffer *ret_buffer) |
296 | { |
297 | acpi_status status; |
298 | struct acpi_namespace_node *node; |
299 | |
300 | ACPI_FUNCTION_TRACE(acpi_get_event_resources); |
301 | |
302 | /* Validate parameters then dispatch to internal routine */ |
303 | |
304 | status = acpi_rs_validate_parameters(device_handle, buffer: ret_buffer, return_node: &node); |
305 | if (ACPI_FAILURE(status)) { |
306 | return_ACPI_STATUS(status); |
307 | } |
308 | |
309 | status = acpi_rs_get_aei_method_data(node, ret_buffer); |
310 | return_ACPI_STATUS(status); |
311 | } |
312 | |
313 | ACPI_EXPORT_SYMBOL(acpi_get_event_resources) |
314 | |
315 | /****************************************************************************** |
316 | * |
317 | * FUNCTION: acpi_resource_to_address64 |
318 | * |
319 | * PARAMETERS: resource - Pointer to a resource |
320 | * out - Pointer to the users's return buffer |
321 | * (a struct acpi_resource_address64) |
322 | * |
323 | * RETURN: Status |
324 | * |
325 | * DESCRIPTION: If the resource is an address16, address32, or address64, |
326 | * copy it to the address64 return buffer. This saves the |
327 | * caller from having to duplicate code for different-sized |
328 | * addresses. |
329 | * |
330 | ******************************************************************************/ |
331 | acpi_status |
332 | acpi_resource_to_address64(struct acpi_resource *resource, |
333 | struct acpi_resource_address64 *out) |
334 | { |
335 | struct acpi_resource_address16 *address16; |
336 | struct acpi_resource_address32 *address32; |
337 | |
338 | if (!resource || !out) { |
339 | return (AE_BAD_PARAMETER); |
340 | } |
341 | |
342 | /* Convert 16 or 32 address descriptor to 64 */ |
343 | |
344 | switch (resource->type) { |
345 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
346 | |
347 | address16 = |
348 | ACPI_CAST_PTR(struct acpi_resource_address16, |
349 | &resource->data); |
350 | ACPI_COPY_ADDRESS(out, address16); |
351 | break; |
352 | |
353 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
354 | |
355 | address32 = |
356 | ACPI_CAST_PTR(struct acpi_resource_address32, |
357 | &resource->data); |
358 | ACPI_COPY_ADDRESS(out, address32); |
359 | break; |
360 | |
361 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
362 | |
363 | /* Simple copy for 64 bit source */ |
364 | |
365 | memcpy(out, &resource->data, |
366 | sizeof(struct acpi_resource_address64)); |
367 | break; |
368 | |
369 | default: |
370 | |
371 | return (AE_BAD_PARAMETER); |
372 | } |
373 | |
374 | return (AE_OK); |
375 | } |
376 | |
377 | ACPI_EXPORT_SYMBOL(acpi_resource_to_address64) |
378 | |
379 | /******************************************************************************* |
380 | * |
381 | * FUNCTION: acpi_get_vendor_resource |
382 | * |
383 | * PARAMETERS: device_handle - Handle for the parent device object |
384 | * name - Method name for the parent resource |
385 | * (METHOD_NAME__CRS or METHOD_NAME__PRS) |
386 | * uuid - Pointer to the UUID to be matched. |
387 | * includes both subtype and 16-byte UUID |
388 | * ret_buffer - Where the vendor resource is returned |
389 | * |
390 | * RETURN: Status |
391 | * |
392 | * DESCRIPTION: Walk a resource template for the specified device to find a |
393 | * vendor-defined resource that matches the supplied UUID and |
394 | * UUID subtype. Returns a struct acpi_resource of type Vendor. |
395 | * |
396 | ******************************************************************************/ |
397 | acpi_status |
398 | acpi_get_vendor_resource(acpi_handle device_handle, |
399 | char *name, |
400 | struct acpi_vendor_uuid *uuid, |
401 | struct acpi_buffer *ret_buffer) |
402 | { |
403 | struct acpi_vendor_walk_info info; |
404 | acpi_status status; |
405 | |
406 | /* Other parameters are validated by acpi_walk_resources */ |
407 | |
408 | if (!uuid || !ret_buffer) { |
409 | return (AE_BAD_PARAMETER); |
410 | } |
411 | |
412 | info.uuid = uuid; |
413 | info.buffer = ret_buffer; |
414 | info.status = AE_NOT_EXIST; |
415 | |
416 | /* Walk the _CRS or _PRS resource list for this device */ |
417 | |
418 | status = |
419 | acpi_walk_resources(device: device_handle, name, |
420 | user_function: acpi_rs_match_vendor_resource, context: &info); |
421 | if (ACPI_FAILURE(status)) { |
422 | return (status); |
423 | } |
424 | |
425 | return (info.status); |
426 | } |
427 | |
428 | ACPI_EXPORT_SYMBOL(acpi_get_vendor_resource) |
429 | |
430 | /******************************************************************************* |
431 | * |
432 | * FUNCTION: acpi_rs_match_vendor_resource |
433 | * |
434 | * PARAMETERS: acpi_walk_resource_callback |
435 | * |
436 | * RETURN: Status |
437 | * |
438 | * DESCRIPTION: Match a vendor resource via the ACPI 3.0 UUID |
439 | * |
440 | ******************************************************************************/ |
441 | static acpi_status |
442 | acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) |
443 | { |
444 | struct acpi_vendor_walk_info *info = context; |
445 | struct acpi_resource_vendor_typed *vendor; |
446 | struct acpi_buffer *buffer; |
447 | acpi_status status; |
448 | |
449 | /* Ignore all descriptors except Vendor */ |
450 | |
451 | if (resource->type != ACPI_RESOURCE_TYPE_VENDOR) { |
452 | return (AE_OK); |
453 | } |
454 | |
455 | vendor = &resource->data.vendor_typed; |
456 | |
457 | /* |
458 | * For a valid match, these conditions must hold: |
459 | * |
460 | * 1) Length of descriptor data must be at least as long as a UUID struct |
461 | * 2) The UUID subtypes must match |
462 | * 3) The UUID data must match |
463 | */ |
464 | if ((vendor->byte_length < (ACPI_UUID_LENGTH + 1)) || |
465 | (vendor->uuid_subtype != info->uuid->subtype) || |
466 | (memcmp(p: vendor->uuid, q: info->uuid->data, ACPI_UUID_LENGTH))) { |
467 | return (AE_OK); |
468 | } |
469 | |
470 | /* Validate/Allocate/Clear caller buffer */ |
471 | |
472 | buffer = info->buffer; |
473 | status = acpi_ut_initialize_buffer(buffer, required_length: resource->length); |
474 | if (ACPI_FAILURE(status)) { |
475 | return (status); |
476 | } |
477 | |
478 | /* Found the correct resource, copy and return it */ |
479 | |
480 | memcpy(buffer->pointer, resource, resource->length); |
481 | buffer->length = resource->length; |
482 | |
483 | /* Found the desired descriptor, terminate resource walk */ |
484 | |
485 | info->status = AE_OK; |
486 | return (AE_CTRL_TERMINATE); |
487 | } |
488 | |
489 | /******************************************************************************* |
490 | * |
491 | * FUNCTION: acpi_walk_resource_buffer |
492 | * |
493 | * PARAMETERS: buffer - Formatted buffer returned by one of the |
494 | * various Get*Resource functions |
495 | * user_function - Called for each resource |
496 | * context - Passed to user_function |
497 | * |
498 | * RETURN: Status |
499 | * |
500 | * DESCRIPTION: Walks the input resource template. The user_function is called |
501 | * once for each resource in the list. |
502 | * |
503 | ******************************************************************************/ |
504 | |
505 | acpi_status |
506 | acpi_walk_resource_buffer(struct acpi_buffer *buffer, |
507 | acpi_walk_resource_callback user_function, |
508 | void *context) |
509 | { |
510 | acpi_status status = AE_OK; |
511 | struct acpi_resource *resource; |
512 | struct acpi_resource *resource_end; |
513 | |
514 | ACPI_FUNCTION_TRACE(acpi_walk_resource_buffer); |
515 | |
516 | /* Parameter validation */ |
517 | |
518 | if (!buffer || !buffer->pointer || !user_function) { |
519 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
520 | } |
521 | |
522 | /* Buffer contains the resource list and length */ |
523 | |
524 | resource = ACPI_CAST_PTR(struct acpi_resource, buffer->pointer); |
525 | resource_end = |
526 | ACPI_ADD_PTR(struct acpi_resource, buffer->pointer, buffer->length); |
527 | |
528 | /* Walk the resource list until the end_tag is found (or buffer end) */ |
529 | |
530 | while (resource < resource_end) { |
531 | |
532 | /* Sanity check the resource type */ |
533 | |
534 | if (resource->type > ACPI_RESOURCE_TYPE_MAX) { |
535 | status = AE_AML_INVALID_RESOURCE_TYPE; |
536 | break; |
537 | } |
538 | |
539 | /* Sanity check the length. It must not be zero, or we loop forever */ |
540 | |
541 | if (!resource->length) { |
542 | return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); |
543 | } |
544 | |
545 | /* Invoke the user function, abort on any error returned */ |
546 | |
547 | status = user_function(resource, context); |
548 | if (ACPI_FAILURE(status)) { |
549 | if (status == AE_CTRL_TERMINATE) { |
550 | |
551 | /* This is an OK termination by the user function */ |
552 | |
553 | status = AE_OK; |
554 | } |
555 | break; |
556 | } |
557 | |
558 | /* end_tag indicates end-of-list */ |
559 | |
560 | if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { |
561 | break; |
562 | } |
563 | |
564 | /* Get the next resource descriptor */ |
565 | |
566 | resource = ACPI_NEXT_RESOURCE(resource); |
567 | } |
568 | |
569 | return_ACPI_STATUS(status); |
570 | } |
571 | |
572 | ACPI_EXPORT_SYMBOL(acpi_walk_resource_buffer) |
573 | |
574 | /******************************************************************************* |
575 | * |
576 | * FUNCTION: acpi_walk_resources |
577 | * |
578 | * PARAMETERS: device_handle - Handle to the device object for the |
579 | * device we are querying |
580 | * name - Method name of the resources we want. |
581 | * (METHOD_NAME__CRS, METHOD_NAME__PRS, or |
582 | * METHOD_NAME__AEI or METHOD_NAME__DMA) |
583 | * user_function - Called for each resource |
584 | * context - Passed to user_function |
585 | * |
586 | * RETURN: Status |
587 | * |
588 | * DESCRIPTION: Retrieves the current or possible resource list for the |
589 | * specified device. The user_function is called once for |
590 | * each resource in the list. |
591 | * |
592 | ******************************************************************************/ |
593 | acpi_status |
594 | acpi_walk_resources(acpi_handle device_handle, |
595 | char *name, |
596 | acpi_walk_resource_callback user_function, void *context) |
597 | { |
598 | acpi_status status; |
599 | struct acpi_buffer buffer; |
600 | |
601 | ACPI_FUNCTION_TRACE(acpi_walk_resources); |
602 | |
603 | /* Parameter validation */ |
604 | |
605 | if (!device_handle || !user_function || !name || |
606 | (!ACPI_COMPARE_NAMESEG(name, METHOD_NAME__CRS) && |
607 | !ACPI_COMPARE_NAMESEG(name, METHOD_NAME__PRS) && |
608 | !ACPI_COMPARE_NAMESEG(name, METHOD_NAME__AEI) && |
609 | !ACPI_COMPARE_NAMESEG(name, METHOD_NAME__DMA))) { |
610 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
611 | } |
612 | |
613 | /* Get the _CRS/_PRS/_AEI/_DMA resource list */ |
614 | |
615 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
616 | status = acpi_rs_get_method_data(handle: device_handle, path: name, ret_buffer: &buffer); |
617 | if (ACPI_FAILURE(status)) { |
618 | return_ACPI_STATUS(status); |
619 | } |
620 | |
621 | /* Walk the resource list and cleanup */ |
622 | |
623 | status = acpi_walk_resource_buffer(&buffer, user_function, context); |
624 | ACPI_FREE(buffer.pointer); |
625 | return_ACPI_STATUS(status); |
626 | } |
627 | |
628 | ACPI_EXPORT_SYMBOL(acpi_walk_resources) |
629 | |