Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Address translation interface via ACPI DSM.
0004  * Copyright (C) 2018 Intel Corporation
0005  *
0006  * Specification for this interface is available at:
0007  *
0008  *  https://cdrdv2.intel.com/v1/dl/getContent/603354
0009  */
0010 
0011 #include <linux/acpi.h>
0012 #include <linux/adxl.h>
0013 
0014 #define ADXL_REVISION           0x1
0015 #define ADXL_IDX_GET_ADDR_PARAMS    0x1
0016 #define ADXL_IDX_FORWARD_TRANSLATE  0x2
0017 #define ACPI_ADXL_PATH          "\\_SB.ADXL"
0018 
0019 /*
0020  * The specification doesn't provide a limit on how many
0021  * components are in a memory address. But since we allocate
0022  * memory based on the number the BIOS tells us, we should
0023  * defend against insane values.
0024  */
0025 #define ADXL_MAX_COMPONENTS     500
0026 
0027 #undef pr_fmt
0028 #define pr_fmt(fmt) "ADXL: " fmt
0029 
0030 static acpi_handle handle;
0031 static union acpi_object *params;
0032 static const guid_t adxl_guid =
0033     GUID_INIT(0xAA3C050A, 0x7EA4, 0x4C1F,
0034           0xAF, 0xDA, 0x12, 0x67, 0xDF, 0xD3, 0xD4, 0x8D);
0035 
0036 static int adxl_count;
0037 static char **adxl_component_names;
0038 
0039 static union acpi_object *adxl_dsm(int cmd, union acpi_object argv[])
0040 {
0041     union acpi_object *obj, *o;
0042 
0043     obj = acpi_evaluate_dsm_typed(handle, &adxl_guid, ADXL_REVISION,
0044                       cmd, argv, ACPI_TYPE_PACKAGE);
0045     if (!obj) {
0046         pr_info("DSM call failed for cmd=%d\n", cmd);
0047         return NULL;
0048     }
0049 
0050     if (obj->package.count != 2) {
0051         pr_info("Bad pkg count %d\n", obj->package.count);
0052         goto err;
0053     }
0054 
0055     o = obj->package.elements;
0056     if (o->type != ACPI_TYPE_INTEGER) {
0057         pr_info("Bad 1st element type %d\n", o->type);
0058         goto err;
0059     }
0060     if (o->integer.value) {
0061         pr_info("Bad ret val %llu\n", o->integer.value);
0062         goto err;
0063     }
0064 
0065     o = obj->package.elements + 1;
0066     if (o->type != ACPI_TYPE_PACKAGE) {
0067         pr_info("Bad 2nd element type %d\n", o->type);
0068         goto err;
0069     }
0070     return obj;
0071 
0072 err:
0073     ACPI_FREE(obj);
0074     return NULL;
0075 }
0076 
0077 /**
0078  * adxl_get_component_names - get list of memory component names
0079  * Returns NULL terminated list of string names
0080  *
0081  * Give the caller a pointer to the list of memory component names
0082  * e.g. { "SystemAddress", "ProcessorSocketId", "ChannelId", ... NULL }
0083  * Caller should count how many strings in order to allocate a buffer
0084  * for the return from adxl_decode().
0085  */
0086 const char * const *adxl_get_component_names(void)
0087 {
0088     return (const char * const *)adxl_component_names;
0089 }
0090 EXPORT_SYMBOL_GPL(adxl_get_component_names);
0091 
0092 /**
0093  * adxl_decode - ask BIOS to decode a system address to memory address
0094  * @addr: the address to decode
0095  * @component_values: pointer to array of values for each component
0096  * Returns 0 on success, negative error code otherwise
0097  *
0098  * The index of each value returned in the array matches the index of
0099  * each component name returned by adxl_get_component_names().
0100  * Components that are not defined for this address translation (e.g.
0101  * mirror channel number for a non-mirrored address) are set to ~0ull.
0102  */
0103 int adxl_decode(u64 addr, u64 component_values[])
0104 {
0105     union acpi_object argv4[2], *results, *r;
0106     int i, cnt;
0107 
0108     if (!adxl_component_names)
0109         return -EOPNOTSUPP;
0110 
0111     argv4[0].type = ACPI_TYPE_PACKAGE;
0112     argv4[0].package.count = 1;
0113     argv4[0].package.elements = &argv4[1];
0114     argv4[1].integer.type = ACPI_TYPE_INTEGER;
0115     argv4[1].integer.value = addr;
0116 
0117     results = adxl_dsm(ADXL_IDX_FORWARD_TRANSLATE, argv4);
0118     if (!results)
0119         return -EINVAL;
0120 
0121     r = results->package.elements + 1;
0122     cnt = r->package.count;
0123     if (cnt != adxl_count) {
0124         ACPI_FREE(results);
0125         return -EINVAL;
0126     }
0127     r = r->package.elements;
0128 
0129     for (i = 0; i < cnt; i++)
0130         component_values[i] = r[i].integer.value;
0131 
0132     ACPI_FREE(results);
0133 
0134     return 0;
0135 }
0136 EXPORT_SYMBOL_GPL(adxl_decode);
0137 
0138 static int __init adxl_init(void)
0139 {
0140     char *path = ACPI_ADXL_PATH;
0141     union acpi_object *p;
0142     acpi_status status;
0143     int i;
0144 
0145     status = acpi_get_handle(NULL, path, &handle);
0146     if (ACPI_FAILURE(status)) {
0147         pr_debug("No ACPI handle for path %s\n", path);
0148         return -ENODEV;
0149     }
0150 
0151     if (!acpi_has_method(handle, "_DSM")) {
0152         pr_info("No DSM method\n");
0153         return -ENODEV;
0154     }
0155 
0156     if (!acpi_check_dsm(handle, &adxl_guid, ADXL_REVISION,
0157                 ADXL_IDX_GET_ADDR_PARAMS |
0158                 ADXL_IDX_FORWARD_TRANSLATE)) {
0159         pr_info("DSM method does not support forward translate\n");
0160         return -ENODEV;
0161     }
0162 
0163     params = adxl_dsm(ADXL_IDX_GET_ADDR_PARAMS, NULL);
0164     if (!params) {
0165         pr_info("Failed to get component names\n");
0166         return -ENODEV;
0167     }
0168 
0169     p = params->package.elements + 1;
0170     adxl_count = p->package.count;
0171     if (adxl_count > ADXL_MAX_COMPONENTS) {
0172         pr_info("Insane number of address component names %d\n", adxl_count);
0173         ACPI_FREE(params);
0174         return -ENODEV;
0175     }
0176     p = p->package.elements;
0177 
0178     /*
0179      * Allocate one extra for NULL termination.
0180      */
0181     adxl_component_names = kcalloc(adxl_count + 1, sizeof(char *), GFP_KERNEL);
0182     if (!adxl_component_names) {
0183         ACPI_FREE(params);
0184         return -ENOMEM;
0185     }
0186 
0187     for (i = 0; i < adxl_count; i++)
0188         adxl_component_names[i] = p[i].string.pointer;
0189 
0190     return 0;
0191 }
0192 subsys_initcall(adxl_init);