xref: /openbmc/linux/drivers/acpi/acpica/rsxface.c (revision 5599fb69)
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
acpi_rs_validate_parameters(acpi_handle device_handle,struct acpi_buffer * buffer,struct acpi_namespace_node ** return_node)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(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
acpi_get_irq_routing_table(acpi_handle device_handle,struct acpi_buffer * ret_buffer)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, ret_buffer, &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 
ACPI_EXPORT_SYMBOL(acpi_get_irq_routing_table)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, ret_buffer, &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 
ACPI_EXPORT_SYMBOL(acpi_get_current_resources)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, ret_buffer, &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 
ACPI_EXPORT_SYMBOL(acpi_get_possible_resources)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, in_buffer, &node);
265 	if (ACPI_FAILURE(status)) {
266 		return_ACPI_STATUS(status);
267 	}
268 
269 	status = acpi_rs_set_srs_method_data(node, in_buffer);
270 	return_ACPI_STATUS(status);
271 }
272 
ACPI_EXPORT_SYMBOL(acpi_set_current_resources)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, ret_buffer, &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 
ACPI_EXPORT_SYMBOL(acpi_get_event_resources)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 
ACPI_EXPORT_SYMBOL(acpi_resource_to_address64)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_handle, name,
420 				acpi_rs_match_vendor_resource, &info);
421 	if (ACPI_FAILURE(status)) {
422 		return (status);
423 	}
424 
425 	return (info.status);
426 }
427 
ACPI_EXPORT_SYMBOL(acpi_get_vendor_resource)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(vendor->uuid, 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, 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
acpi_walk_resource_buffer(struct acpi_buffer * buffer,acpi_walk_resource_callback user_function,void * context)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 
ACPI_EXPORT_SYMBOL(acpi_walk_resource_buffer)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(device_handle, name, &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