linux/drivers/acpi/acpica/rsxface.c
<<
>>
Prefs
   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
  16ACPI_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 */
  34static acpi_status
  35acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context);
  36
  37static acpi_status
  38acpi_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
  56static acpi_status
  57acpi_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
 121acpi_status
 122acpi_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
 141ACPI_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 ******************************************************************************/
 166acpi_status
 167acpi_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
 186ACPI_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 ******************************************************************************/
 208acpi_status
 209acpi_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
 228ACPI_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 ******************************************************************************/
 247acpi_status
 248acpi_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
 273ACPI_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 ******************************************************************************/
 293acpi_status
 294acpi_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
 313ACPI_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 ******************************************************************************/
 331acpi_status
 332acpi_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
 377ACPI_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 ******************************************************************************/
 397acpi_status
 398acpi_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
 428ACPI_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 ******************************************************************************/
 441static acpi_status
 442acpi_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
 505acpi_status
 506acpi_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
 572ACPI_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 ******************************************************************************/
 593acpi_status
 594acpi_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
 628ACPI_EXPORT_SYMBOL(acpi_walk_resources)
 629