1d9836fb4SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2d9836fb4SBjoern A. Zeeb /* 3d9836fb4SBjoern A. Zeeb * Copyright (C) 2017 Intel Deutschland GmbH 4*a4128aadSBjoern A. Zeeb * Copyright (C) 2019-2024 Intel Corporation 5d9836fb4SBjoern A. Zeeb */ 6d9836fb4SBjoern A. Zeeb #include <linux/uuid.h> 7d9836fb4SBjoern A. Zeeb #include "iwl-drv.h" 8d9836fb4SBjoern A. Zeeb #include "iwl-debug.h" 9d9836fb4SBjoern A. Zeeb #include "acpi.h" 10d9836fb4SBjoern A. Zeeb #include "fw/runtime.h" 11d9836fb4SBjoern A. Zeeb 12d9836fb4SBjoern A. Zeeb const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, 13d9836fb4SBjoern A. Zeeb 0xA5, 0xB3, 0x1F, 0x73, 14d9836fb4SBjoern A. Zeeb 0x8E, 0x28, 0x5A, 0xDE); 15d9836fb4SBjoern A. Zeeb 16*a4128aadSBjoern A. Zeeb static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = { 17*a4128aadSBjoern A. Zeeb [DSM_FUNC_QUERY] = sizeof(u32), 18*a4128aadSBjoern A. Zeeb [DSM_FUNC_DISABLE_SRD] = sizeof(u8), 19*a4128aadSBjoern A. Zeeb [DSM_FUNC_ENABLE_INDONESIA_5G2] = sizeof(u8), 20*a4128aadSBjoern A. Zeeb [DSM_FUNC_ENABLE_6E] = sizeof(u32), 21*a4128aadSBjoern A. Zeeb [DSM_FUNC_REGULATORY_CONFIG] = sizeof(u32), 22*a4128aadSBjoern A. Zeeb /* Not supported in driver */ 23*a4128aadSBjoern A. Zeeb [5] = (size_t)0, 24*a4128aadSBjoern A. Zeeb [DSM_FUNC_11AX_ENABLEMENT] = sizeof(u32), 25*a4128aadSBjoern A. Zeeb [DSM_FUNC_ENABLE_UNII4_CHAN] = sizeof(u32), 26*a4128aadSBjoern A. Zeeb [DSM_FUNC_ACTIVATE_CHANNEL] = sizeof(u32), 27*a4128aadSBjoern A. Zeeb [DSM_FUNC_FORCE_DISABLE_CHANNELS] = sizeof(u32), 28*a4128aadSBjoern A. Zeeb [DSM_FUNC_ENERGY_DETECTION_THRESHOLD] = sizeof(u32), 29*a4128aadSBjoern A. Zeeb [DSM_FUNC_RFI_CONFIG] = sizeof(u32), 30*a4128aadSBjoern A. Zeeb [DSM_FUNC_ENABLE_11BE] = sizeof(u32), 31fac1f593SBjoern A. Zeeb }; 32fac1f593SBjoern A. Zeeb 33d9836fb4SBjoern A. Zeeb static int iwl_acpi_get_handle(struct device *dev, acpi_string method, 34d9836fb4SBjoern A. Zeeb acpi_handle *ret_handle) 35d9836fb4SBjoern A. Zeeb { 36d9836fb4SBjoern A. Zeeb acpi_handle root_handle; 37d9836fb4SBjoern A. Zeeb acpi_status status; 38d9836fb4SBjoern A. Zeeb 39d9836fb4SBjoern A. Zeeb root_handle = ACPI_HANDLE(dev); 40d9836fb4SBjoern A. Zeeb if (!root_handle) { 41d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, 42d9836fb4SBjoern A. Zeeb "ACPI: Could not retrieve root port handle\n"); 43d9836fb4SBjoern A. Zeeb return -ENOENT; 44d9836fb4SBjoern A. Zeeb } 45d9836fb4SBjoern A. Zeeb 46d9836fb4SBjoern A. Zeeb status = acpi_get_handle(root_handle, method, ret_handle); 47d9836fb4SBjoern A. Zeeb if (ACPI_FAILURE(status)) { 48d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, 49d9836fb4SBjoern A. Zeeb "ACPI: %s method not found\n", method); 50d9836fb4SBjoern A. Zeeb return -ENOENT; 51d9836fb4SBjoern A. Zeeb } 52d9836fb4SBjoern A. Zeeb return 0; 53d9836fb4SBjoern A. Zeeb } 54d9836fb4SBjoern A. Zeeb 559af1bba4SBjoern A. Zeeb static void *iwl_acpi_get_object(struct device *dev, acpi_string method) 56d9836fb4SBjoern A. Zeeb { 57d9836fb4SBjoern A. Zeeb struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; 58d9836fb4SBjoern A. Zeeb acpi_handle handle; 59d9836fb4SBjoern A. Zeeb acpi_status status; 60d9836fb4SBjoern A. Zeeb int ret; 61d9836fb4SBjoern A. Zeeb 62d9836fb4SBjoern A. Zeeb ret = iwl_acpi_get_handle(dev, method, &handle); 63d9836fb4SBjoern A. Zeeb if (ret) 64d9836fb4SBjoern A. Zeeb return ERR_PTR(-ENOENT); 65d9836fb4SBjoern A. Zeeb 66d9836fb4SBjoern A. Zeeb /* Call the method with no arguments */ 67d9836fb4SBjoern A. Zeeb status = acpi_evaluate_object(handle, NULL, NULL, &buf); 68d9836fb4SBjoern A. Zeeb if (ACPI_FAILURE(status)) { 69d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, 70d9836fb4SBjoern A. Zeeb "ACPI: %s method invocation failed (status: 0x%x)\n", 71d9836fb4SBjoern A. Zeeb method, status); 72d9836fb4SBjoern A. Zeeb return ERR_PTR(-ENOENT); 73d9836fb4SBjoern A. Zeeb } 74d9836fb4SBjoern A. Zeeb return buf.pointer; 75d9836fb4SBjoern A. Zeeb } 76d9836fb4SBjoern A. Zeeb 77d9836fb4SBjoern A. Zeeb /* 78d9836fb4SBjoern A. Zeeb * Generic function for evaluating a method defined in the device specific 79d9836fb4SBjoern A. Zeeb * method (DSM) interface. The returned acpi object must be freed by calling 80d9836fb4SBjoern A. Zeeb * function. 81d9836fb4SBjoern A. Zeeb */ 82d9836fb4SBjoern A. Zeeb static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func, 83d9836fb4SBjoern A. Zeeb union acpi_object *args, 84d9836fb4SBjoern A. Zeeb const guid_t *guid) 85d9836fb4SBjoern A. Zeeb { 86d9836fb4SBjoern A. Zeeb union acpi_object *obj; 87d9836fb4SBjoern A. Zeeb 88d9836fb4SBjoern A. Zeeb obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func, 89d9836fb4SBjoern A. Zeeb args); 90d9836fb4SBjoern A. Zeeb if (!obj) { 91d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, 92d9836fb4SBjoern A. Zeeb "ACPI: DSM method invocation failed (rev: %d, func:%d)\n", 93d9836fb4SBjoern A. Zeeb rev, func); 94d9836fb4SBjoern A. Zeeb return ERR_PTR(-ENOENT); 95d9836fb4SBjoern A. Zeeb } 96d9836fb4SBjoern A. Zeeb return obj; 97d9836fb4SBjoern A. Zeeb } 98d9836fb4SBjoern A. Zeeb 99d9836fb4SBjoern A. Zeeb /* 100d9836fb4SBjoern A. Zeeb * Generic function to evaluate a DSM with no arguments 101d9836fb4SBjoern A. Zeeb * and an integer return value, 102d9836fb4SBjoern A. Zeeb * (as an integer object or inside a buffer object), 103d9836fb4SBjoern A. Zeeb * verify and assign the value in the "value" parameter. 104d9836fb4SBjoern A. Zeeb * return 0 in success and the appropriate errno otherwise. 105d9836fb4SBjoern A. Zeeb */ 106d9836fb4SBjoern A. Zeeb static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func, 107d9836fb4SBjoern A. Zeeb const guid_t *guid, u64 *value, 108d9836fb4SBjoern A. Zeeb size_t expected_size) 109d9836fb4SBjoern A. Zeeb { 110d9836fb4SBjoern A. Zeeb union acpi_object *obj; 111d9836fb4SBjoern A. Zeeb int ret = 0; 112d9836fb4SBjoern A. Zeeb 113d9836fb4SBjoern A. Zeeb obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid); 114d9836fb4SBjoern A. Zeeb if (IS_ERR(obj)) { 115d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, 116d9836fb4SBjoern A. Zeeb "Failed to get DSM object. func= %d\n", 117d9836fb4SBjoern A. Zeeb func); 118d9836fb4SBjoern A. Zeeb return -ENOENT; 119d9836fb4SBjoern A. Zeeb } 120d9836fb4SBjoern A. Zeeb 121d9836fb4SBjoern A. Zeeb if (obj->type == ACPI_TYPE_INTEGER) { 122d9836fb4SBjoern A. Zeeb *value = obj->integer.value; 123d9836fb4SBjoern A. Zeeb } else if (obj->type == ACPI_TYPE_BUFFER) { 124d9836fb4SBjoern A. Zeeb __le64 le_value = 0; 125d9836fb4SBjoern A. Zeeb 126d9836fb4SBjoern A. Zeeb if (WARN_ON_ONCE(expected_size > sizeof(le_value))) 127d9836fb4SBjoern A. Zeeb return -EINVAL; 128d9836fb4SBjoern A. Zeeb 129d9836fb4SBjoern A. Zeeb /* if the buffer size doesn't match the expected size */ 130d9836fb4SBjoern A. Zeeb if (obj->buffer.length != expected_size) 131d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, 132d9836fb4SBjoern A. Zeeb "ACPI: DSM invalid buffer size, padding or truncating (%d)\n", 133d9836fb4SBjoern A. Zeeb obj->buffer.length); 134d9836fb4SBjoern A. Zeeb 135d9836fb4SBjoern A. Zeeb /* assuming LE from Intel BIOS spec */ 136d9836fb4SBjoern A. Zeeb memcpy(&le_value, obj->buffer.pointer, 137d9836fb4SBjoern A. Zeeb min_t(size_t, expected_size, (size_t)obj->buffer.length)); 138d9836fb4SBjoern A. Zeeb *value = le64_to_cpu(le_value); 139d9836fb4SBjoern A. Zeeb } else { 140d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, 141d9836fb4SBjoern A. Zeeb "ACPI: DSM method did not return a valid object, type=%d\n", 142d9836fb4SBjoern A. Zeeb obj->type); 143d9836fb4SBjoern A. Zeeb ret = -EINVAL; 144d9836fb4SBjoern A. Zeeb goto out; 145d9836fb4SBjoern A. Zeeb } 146d9836fb4SBjoern A. Zeeb 147d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, 148d9836fb4SBjoern A. Zeeb "ACPI: DSM method evaluated: func=%d, ret=%d\n", 149d9836fb4SBjoern A. Zeeb func, ret); 150d9836fb4SBjoern A. Zeeb out: 151d9836fb4SBjoern A. Zeeb ACPI_FREE(obj); 152d9836fb4SBjoern A. Zeeb return ret; 153d9836fb4SBjoern A. Zeeb } 154d9836fb4SBjoern A. Zeeb 155d9836fb4SBjoern A. Zeeb /* 156*a4128aadSBjoern A. Zeeb * This function receives a DSM function number, calculates its expected size 157*a4128aadSBjoern A. Zeeb * according to Intel BIOS spec, and fills in the value in a 32-bit field. 158*a4128aadSBjoern A. Zeeb * In case the expected size is smaller than 32-bit, padding will be added. 159d9836fb4SBjoern A. Zeeb */ 160*a4128aadSBjoern A. Zeeb int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, 161*a4128aadSBjoern A. Zeeb enum iwl_dsm_funcs func, u32 *value) 162d9836fb4SBjoern A. Zeeb { 163*a4128aadSBjoern A. Zeeb size_t expected_size; 164*a4128aadSBjoern A. Zeeb u64 tmp; 165d9836fb4SBjoern A. Zeeb int ret; 166d9836fb4SBjoern A. Zeeb 167*a4128aadSBjoern A. Zeeb BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS); 168d9836fb4SBjoern A. Zeeb 169*a4128aadSBjoern A. Zeeb if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size))) 170*a4128aadSBjoern A. Zeeb return -EINVAL; 171*a4128aadSBjoern A. Zeeb 172*a4128aadSBjoern A. Zeeb expected_size = acpi_dsm_size[func]; 173*a4128aadSBjoern A. Zeeb 174*a4128aadSBjoern A. Zeeb /* Currently all ACPI DSMs are either 8-bit or 32-bit */ 175*a4128aadSBjoern A. Zeeb if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) 176*a4128aadSBjoern A. Zeeb return -EOPNOTSUPP; 177*a4128aadSBjoern A. Zeeb 178*a4128aadSBjoern A. Zeeb ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, 179*a4128aadSBjoern A. Zeeb &iwl_guid, &tmp, expected_size); 180*a4128aadSBjoern A. Zeeb if (ret) 181d9836fb4SBjoern A. Zeeb return ret; 182d9836fb4SBjoern A. Zeeb 183*a4128aadSBjoern A. Zeeb if ((expected_size == sizeof(u8) && tmp != (u8)tmp) || 184*a4128aadSBjoern A. Zeeb (expected_size == sizeof(u32) && tmp != (u32)tmp)) 185*a4128aadSBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, 186*a4128aadSBjoern A. Zeeb "DSM value overflows the expected size, truncating\n"); 187*a4128aadSBjoern A. Zeeb *value = (u32)tmp; 188*a4128aadSBjoern A. Zeeb 189d9836fb4SBjoern A. Zeeb return 0; 190d9836fb4SBjoern A. Zeeb } 191d9836fb4SBjoern A. Zeeb 1929af1bba4SBjoern A. Zeeb static union acpi_object * 1939af1bba4SBjoern A. Zeeb iwl_acpi_get_wifi_pkg_range(struct device *dev, 194d9836fb4SBjoern A. Zeeb union acpi_object *data, 195d9836fb4SBjoern A. Zeeb int min_data_size, 196d9836fb4SBjoern A. Zeeb int max_data_size, 197d9836fb4SBjoern A. Zeeb int *tbl_rev) 198d9836fb4SBjoern A. Zeeb { 199d9836fb4SBjoern A. Zeeb int i; 200d9836fb4SBjoern A. Zeeb union acpi_object *wifi_pkg; 201d9836fb4SBjoern A. Zeeb 202d9836fb4SBjoern A. Zeeb /* 203d9836fb4SBjoern A. Zeeb * We need at least one entry in the wifi package that 204d9836fb4SBjoern A. Zeeb * describes the domain, and one more entry, otherwise there's 205d9836fb4SBjoern A. Zeeb * no point in reading it. 206d9836fb4SBjoern A. Zeeb */ 207d9836fb4SBjoern A. Zeeb if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size)) 208d9836fb4SBjoern A. Zeeb return ERR_PTR(-EINVAL); 209d9836fb4SBjoern A. Zeeb 210d9836fb4SBjoern A. Zeeb /* 211d9836fb4SBjoern A. Zeeb * We need at least two packages, one for the revision and one 212d9836fb4SBjoern A. Zeeb * for the data itself. Also check that the revision is valid 213d9836fb4SBjoern A. Zeeb * (i.e. it is an integer (each caller has to check by itself 214d9836fb4SBjoern A. Zeeb * if the returned revision is supported)). 215d9836fb4SBjoern A. Zeeb */ 216d9836fb4SBjoern A. Zeeb if (data->type != ACPI_TYPE_PACKAGE || 217d9836fb4SBjoern A. Zeeb data->package.count < 2 || 218d9836fb4SBjoern A. Zeeb data->package.elements[0].type != ACPI_TYPE_INTEGER) { 219d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n"); 220d9836fb4SBjoern A. Zeeb return ERR_PTR(-EINVAL); 221d9836fb4SBjoern A. Zeeb } 222d9836fb4SBjoern A. Zeeb 223d9836fb4SBjoern A. Zeeb *tbl_rev = data->package.elements[0].integer.value; 224d9836fb4SBjoern A. Zeeb 225d9836fb4SBjoern A. Zeeb /* loop through all the packages to find the one for WiFi */ 226d9836fb4SBjoern A. Zeeb for (i = 1; i < data->package.count; i++) { 227d9836fb4SBjoern A. Zeeb union acpi_object *domain; 228d9836fb4SBjoern A. Zeeb 229d9836fb4SBjoern A. Zeeb wifi_pkg = &data->package.elements[i]; 230d9836fb4SBjoern A. Zeeb 231d9836fb4SBjoern A. Zeeb /* skip entries that are not a package with the right size */ 232d9836fb4SBjoern A. Zeeb if (wifi_pkg->type != ACPI_TYPE_PACKAGE || 233d9836fb4SBjoern A. Zeeb wifi_pkg->package.count < min_data_size || 234d9836fb4SBjoern A. Zeeb wifi_pkg->package.count > max_data_size) 235d9836fb4SBjoern A. Zeeb continue; 236d9836fb4SBjoern A. Zeeb 237d9836fb4SBjoern A. Zeeb domain = &wifi_pkg->package.elements[0]; 238d9836fb4SBjoern A. Zeeb if (domain->type == ACPI_TYPE_INTEGER && 239d9836fb4SBjoern A. Zeeb domain->integer.value == ACPI_WIFI_DOMAIN) 240d9836fb4SBjoern A. Zeeb goto found; 241d9836fb4SBjoern A. Zeeb } 242d9836fb4SBjoern A. Zeeb 243d9836fb4SBjoern A. Zeeb return ERR_PTR(-ENOENT); 244d9836fb4SBjoern A. Zeeb 245d9836fb4SBjoern A. Zeeb found: 246d9836fb4SBjoern A. Zeeb return wifi_pkg; 247d9836fb4SBjoern A. Zeeb } 2489af1bba4SBjoern A. Zeeb 2499af1bba4SBjoern A. Zeeb static union acpi_object * 2509af1bba4SBjoern A. Zeeb iwl_acpi_get_wifi_pkg(struct device *dev, 2519af1bba4SBjoern A. Zeeb union acpi_object *data, 2529af1bba4SBjoern A. Zeeb int data_size, int *tbl_rev) 2539af1bba4SBjoern A. Zeeb { 2549af1bba4SBjoern A. Zeeb return iwl_acpi_get_wifi_pkg_range(dev, data, data_size, data_size, 2559af1bba4SBjoern A. Zeeb tbl_rev); 2569af1bba4SBjoern A. Zeeb } 2579af1bba4SBjoern A. Zeeb 258*a4128aadSBjoern A. Zeeb int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, 259*a4128aadSBjoern A. Zeeb struct iwl_tas_data *tas_data) 260d9836fb4SBjoern A. Zeeb { 261d9836fb4SBjoern A. Zeeb union acpi_object *wifi_pkg, *data; 262d9836fb4SBjoern A. Zeeb int ret, tbl_rev, i, block_list_size, enabled; 263d9836fb4SBjoern A. Zeeb 264d9836fb4SBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD); 265d9836fb4SBjoern A. Zeeb if (IS_ERR(data)) 266d9836fb4SBjoern A. Zeeb return PTR_ERR(data); 267d9836fb4SBjoern A. Zeeb 268d9836fb4SBjoern A. Zeeb /* try to read wtas table revision 1 or revision 0*/ 269d9836fb4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 270d9836fb4SBjoern A. Zeeb ACPI_WTAS_WIFI_DATA_SIZE, 271d9836fb4SBjoern A. Zeeb &tbl_rev); 272d9836fb4SBjoern A. Zeeb if (IS_ERR(wifi_pkg)) { 273d9836fb4SBjoern A. Zeeb ret = PTR_ERR(wifi_pkg); 274d9836fb4SBjoern A. Zeeb goto out_free; 275d9836fb4SBjoern A. Zeeb } 276d9836fb4SBjoern A. Zeeb 277d9836fb4SBjoern A. Zeeb if (tbl_rev == 1 && wifi_pkg->package.elements[1].type == 278d9836fb4SBjoern A. Zeeb ACPI_TYPE_INTEGER) { 279d9836fb4SBjoern A. Zeeb u32 tas_selection = 280d9836fb4SBjoern A. Zeeb (u32)wifi_pkg->package.elements[1].integer.value; 281d9836fb4SBjoern A. Zeeb 282*a4128aadSBjoern A. Zeeb enabled = iwl_parse_tas_selection(fwrt, tas_data, 283*a4128aadSBjoern A. Zeeb tas_selection); 284d9836fb4SBjoern A. Zeeb 285d9836fb4SBjoern A. Zeeb } else if (tbl_rev == 0 && 286d9836fb4SBjoern A. Zeeb wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) { 287d9836fb4SBjoern A. Zeeb enabled = !!wifi_pkg->package.elements[1].integer.value; 288d9836fb4SBjoern A. Zeeb } else { 289d9836fb4SBjoern A. Zeeb ret = -EINVAL; 290d9836fb4SBjoern A. Zeeb goto out_free; 291d9836fb4SBjoern A. Zeeb } 292d9836fb4SBjoern A. Zeeb 293d9836fb4SBjoern A. Zeeb if (!enabled) { 294d9836fb4SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n"); 295d9836fb4SBjoern A. Zeeb ret = 0; 296d9836fb4SBjoern A. Zeeb goto out_free; 297d9836fb4SBjoern A. Zeeb } 298d9836fb4SBjoern A. Zeeb 299d9836fb4SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev); 300d9836fb4SBjoern A. Zeeb if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER || 301d9836fb4SBjoern A. Zeeb wifi_pkg->package.elements[2].integer.value > 302*a4128aadSBjoern A. Zeeb IWL_WTAS_BLACK_LIST_MAX) { 303d9836fb4SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", 304d9836fb4SBjoern A. Zeeb wifi_pkg->package.elements[2].integer.value); 305d9836fb4SBjoern A. Zeeb ret = -EINVAL; 306d9836fb4SBjoern A. Zeeb goto out_free; 307d9836fb4SBjoern A. Zeeb } 308d9836fb4SBjoern A. Zeeb block_list_size = wifi_pkg->package.elements[2].integer.value; 309*a4128aadSBjoern A. Zeeb tas_data->block_list_size = cpu_to_le32(block_list_size); 310d9836fb4SBjoern A. Zeeb 311d9836fb4SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size); 312d9836fb4SBjoern A. Zeeb 313d9836fb4SBjoern A. Zeeb for (i = 0; i < block_list_size; i++) { 314d9836fb4SBjoern A. Zeeb u32 country; 315d9836fb4SBjoern A. Zeeb 316d9836fb4SBjoern A. Zeeb if (wifi_pkg->package.elements[3 + i].type != 317d9836fb4SBjoern A. Zeeb ACPI_TYPE_INTEGER) { 318d9836fb4SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, 319d9836fb4SBjoern A. Zeeb "TAS invalid array elem %d\n", 3 + i); 320d9836fb4SBjoern A. Zeeb ret = -EINVAL; 321d9836fb4SBjoern A. Zeeb goto out_free; 322d9836fb4SBjoern A. Zeeb } 323d9836fb4SBjoern A. Zeeb 324d9836fb4SBjoern A. Zeeb country = wifi_pkg->package.elements[3 + i].integer.value; 325*a4128aadSBjoern A. Zeeb tas_data->block_list_array[i] = cpu_to_le32(country); 326d9836fb4SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); 327d9836fb4SBjoern A. Zeeb } 328d9836fb4SBjoern A. Zeeb 329d9836fb4SBjoern A. Zeeb ret = 1; 330d9836fb4SBjoern A. Zeeb out_free: 331d9836fb4SBjoern A. Zeeb kfree(data); 332d9836fb4SBjoern A. Zeeb return ret; 333d9836fb4SBjoern A. Zeeb } 334d9836fb4SBjoern A. Zeeb 335*a4128aadSBjoern A. Zeeb int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) 336d9836fb4SBjoern A. Zeeb { 337d9836fb4SBjoern A. Zeeb union acpi_object *wifi_pkg, *data; 338d9836fb4SBjoern A. Zeeb u32 mcc_val; 339d9836fb4SBjoern A. Zeeb int ret, tbl_rev; 340d9836fb4SBjoern A. Zeeb 341*a4128aadSBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDD_METHOD); 342d9836fb4SBjoern A. Zeeb if (IS_ERR(data)) 343d9836fb4SBjoern A. Zeeb return PTR_ERR(data); 344d9836fb4SBjoern A. Zeeb 345*a4128aadSBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 346*a4128aadSBjoern A. Zeeb ACPI_WRDD_WIFI_DATA_SIZE, 347d9836fb4SBjoern A. Zeeb &tbl_rev); 348d9836fb4SBjoern A. Zeeb if (IS_ERR(wifi_pkg)) { 349d9836fb4SBjoern A. Zeeb ret = PTR_ERR(wifi_pkg); 350d9836fb4SBjoern A. Zeeb goto out_free; 351d9836fb4SBjoern A. Zeeb } 352d9836fb4SBjoern A. Zeeb 353d9836fb4SBjoern A. Zeeb if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 354d9836fb4SBjoern A. Zeeb tbl_rev != 0) { 355d9836fb4SBjoern A. Zeeb ret = -EINVAL; 356d9836fb4SBjoern A. Zeeb goto out_free; 357d9836fb4SBjoern A. Zeeb } 358d9836fb4SBjoern A. Zeeb 359d9836fb4SBjoern A. Zeeb mcc_val = wifi_pkg->package.elements[1].integer.value; 360d9836fb4SBjoern A. Zeeb 361d9836fb4SBjoern A. Zeeb mcc[0] = (mcc_val >> 8) & 0xff; 362d9836fb4SBjoern A. Zeeb mcc[1] = mcc_val & 0xff; 363d9836fb4SBjoern A. Zeeb mcc[2] = '\0'; 364d9836fb4SBjoern A. Zeeb 365d9836fb4SBjoern A. Zeeb ret = 0; 366d9836fb4SBjoern A. Zeeb out_free: 367d9836fb4SBjoern A. Zeeb kfree(data); 368d9836fb4SBjoern A. Zeeb return ret; 369d9836fb4SBjoern A. Zeeb } 370d9836fb4SBjoern A. Zeeb 371*a4128aadSBjoern A. Zeeb int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit) 372d9836fb4SBjoern A. Zeeb { 373d9836fb4SBjoern A. Zeeb union acpi_object *data, *wifi_pkg; 374*a4128aadSBjoern A. Zeeb int tbl_rev, ret = -EINVAL; 375d9836fb4SBjoern A. Zeeb 376*a4128aadSBjoern A. Zeeb *dflt_pwr_limit = 0; 377*a4128aadSBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_SPLC_METHOD); 378*a4128aadSBjoern A. Zeeb if (IS_ERR(data)) 379d9836fb4SBjoern A. Zeeb goto out; 380d9836fb4SBjoern A. Zeeb 381*a4128aadSBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 382d9836fb4SBjoern A. Zeeb ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev); 383d9836fb4SBjoern A. Zeeb if (IS_ERR(wifi_pkg) || tbl_rev != 0 || 384*a4128aadSBjoern A. Zeeb wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) 385d9836fb4SBjoern A. Zeeb goto out_free; 386d9836fb4SBjoern A. Zeeb 387*a4128aadSBjoern A. Zeeb *dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; 388*a4128aadSBjoern A. Zeeb ret = 0; 389d9836fb4SBjoern A. Zeeb out_free: 390d9836fb4SBjoern A. Zeeb kfree(data); 391d9836fb4SBjoern A. Zeeb out: 392*a4128aadSBjoern A. Zeeb return ret; 393d9836fb4SBjoern A. Zeeb } 394d9836fb4SBjoern A. Zeeb 395*a4128aadSBjoern A. Zeeb int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) 396d9836fb4SBjoern A. Zeeb { 397d9836fb4SBjoern A. Zeeb union acpi_object *wifi_pkg, *data; 398d9836fb4SBjoern A. Zeeb int ret, tbl_rev; 399d9836fb4SBjoern A. Zeeb 400*a4128aadSBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_ECKV_METHOD); 401d9836fb4SBjoern A. Zeeb if (IS_ERR(data)) 402d9836fb4SBjoern A. Zeeb return PTR_ERR(data); 403d9836fb4SBjoern A. Zeeb 404*a4128aadSBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 405*a4128aadSBjoern A. Zeeb ACPI_ECKV_WIFI_DATA_SIZE, 406d9836fb4SBjoern A. Zeeb &tbl_rev); 407d9836fb4SBjoern A. Zeeb if (IS_ERR(wifi_pkg)) { 408d9836fb4SBjoern A. Zeeb ret = PTR_ERR(wifi_pkg); 409d9836fb4SBjoern A. Zeeb goto out_free; 410d9836fb4SBjoern A. Zeeb } 411d9836fb4SBjoern A. Zeeb 412d9836fb4SBjoern A. Zeeb if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 413d9836fb4SBjoern A. Zeeb tbl_rev != 0) { 414d9836fb4SBjoern A. Zeeb ret = -EINVAL; 415d9836fb4SBjoern A. Zeeb goto out_free; 416d9836fb4SBjoern A. Zeeb } 417d9836fb4SBjoern A. Zeeb 418d9836fb4SBjoern A. Zeeb *extl_clk = wifi_pkg->package.elements[1].integer.value; 419d9836fb4SBjoern A. Zeeb 420d9836fb4SBjoern A. Zeeb ret = 0; 421d9836fb4SBjoern A. Zeeb 422d9836fb4SBjoern A. Zeeb out_free: 423d9836fb4SBjoern A. Zeeb kfree(data); 424d9836fb4SBjoern A. Zeeb return ret; 425d9836fb4SBjoern A. Zeeb } 426d9836fb4SBjoern A. Zeeb 427*a4128aadSBjoern A. Zeeb static int iwl_acpi_sar_set_profile(union acpi_object *table, 428d9836fb4SBjoern A. Zeeb struct iwl_sar_profile *profile, 429*a4128aadSBjoern A. Zeeb bool enabled, u8 num_chains, 430*a4128aadSBjoern A. Zeeb u8 num_sub_bands) 431d9836fb4SBjoern A. Zeeb { 432d9836fb4SBjoern A. Zeeb int i, j, idx = 0; 433d9836fb4SBjoern A. Zeeb 434d9836fb4SBjoern A. Zeeb /* 435d9836fb4SBjoern A. Zeeb * The table from ACPI is flat, but we store it in a 436d9836fb4SBjoern A. Zeeb * structured array. 437d9836fb4SBjoern A. Zeeb */ 438*a4128aadSBjoern A. Zeeb for (i = 0; i < BIOS_SAR_MAX_CHAINS_PER_PROFILE; i++) { 439*a4128aadSBjoern A. Zeeb for (j = 0; j < BIOS_SAR_MAX_SUB_BANDS_NUM; j++) { 440d9836fb4SBjoern A. Zeeb /* if we don't have the values, use the default */ 441d9836fb4SBjoern A. Zeeb if (i >= num_chains || j >= num_sub_bands) { 442d9836fb4SBjoern A. Zeeb profile->chains[i].subbands[j] = 0; 443d9836fb4SBjoern A. Zeeb } else { 444d9836fb4SBjoern A. Zeeb if (table[idx].type != ACPI_TYPE_INTEGER || 445d9836fb4SBjoern A. Zeeb table[idx].integer.value > U8_MAX) 446d9836fb4SBjoern A. Zeeb return -EINVAL; 447d9836fb4SBjoern A. Zeeb 448d9836fb4SBjoern A. Zeeb profile->chains[i].subbands[j] = 449d9836fb4SBjoern A. Zeeb table[idx].integer.value; 450d9836fb4SBjoern A. Zeeb 451d9836fb4SBjoern A. Zeeb idx++; 452d9836fb4SBjoern A. Zeeb } 453d9836fb4SBjoern A. Zeeb } 454d9836fb4SBjoern A. Zeeb } 455d9836fb4SBjoern A. Zeeb 456d9836fb4SBjoern A. Zeeb /* Only if all values were valid can the profile be enabled */ 457d9836fb4SBjoern A. Zeeb profile->enabled = enabled; 458d9836fb4SBjoern A. Zeeb 459d9836fb4SBjoern A. Zeeb return 0; 460d9836fb4SBjoern A. Zeeb } 461d9836fb4SBjoern A. Zeeb 462*a4128aadSBjoern A. Zeeb int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) 463d9836fb4SBjoern A. Zeeb { 464d9836fb4SBjoern A. Zeeb union acpi_object *wifi_pkg, *table, *data; 465d9836fb4SBjoern A. Zeeb int ret, tbl_rev; 466fac1f593SBjoern A. Zeeb u32 flags; 467d9836fb4SBjoern A. Zeeb u8 num_chains, num_sub_bands; 468d9836fb4SBjoern A. Zeeb 469d9836fb4SBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); 470d9836fb4SBjoern A. Zeeb if (IS_ERR(data)) 471d9836fb4SBjoern A. Zeeb return PTR_ERR(data); 472d9836fb4SBjoern A. Zeeb 473d9836fb4SBjoern A. Zeeb /* start by trying to read revision 2 */ 474d9836fb4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 475d9836fb4SBjoern A. Zeeb ACPI_WRDS_WIFI_DATA_SIZE_REV2, 476d9836fb4SBjoern A. Zeeb &tbl_rev); 477d9836fb4SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 478d9836fb4SBjoern A. Zeeb if (tbl_rev != 2) { 479*a4128aadSBjoern A. Zeeb ret = -EINVAL; 480d9836fb4SBjoern A. Zeeb goto out_free; 481d9836fb4SBjoern A. Zeeb } 482d9836fb4SBjoern A. Zeeb 483d9836fb4SBjoern A. Zeeb num_chains = ACPI_SAR_NUM_CHAINS_REV2; 484d9836fb4SBjoern A. Zeeb num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; 485d9836fb4SBjoern A. Zeeb 486d9836fb4SBjoern A. Zeeb goto read_table; 487d9836fb4SBjoern A. Zeeb } 488d9836fb4SBjoern A. Zeeb 489d9836fb4SBjoern A. Zeeb /* then try revision 1 */ 490d9836fb4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 491d9836fb4SBjoern A. Zeeb ACPI_WRDS_WIFI_DATA_SIZE_REV1, 492d9836fb4SBjoern A. Zeeb &tbl_rev); 493d9836fb4SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 494d9836fb4SBjoern A. Zeeb if (tbl_rev != 1) { 495*a4128aadSBjoern A. Zeeb ret = -EINVAL; 496d9836fb4SBjoern A. Zeeb goto out_free; 497d9836fb4SBjoern A. Zeeb } 498d9836fb4SBjoern A. Zeeb 499d9836fb4SBjoern A. Zeeb num_chains = ACPI_SAR_NUM_CHAINS_REV1; 500d9836fb4SBjoern A. Zeeb num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; 501d9836fb4SBjoern A. Zeeb 502d9836fb4SBjoern A. Zeeb goto read_table; 503d9836fb4SBjoern A. Zeeb } 504d9836fb4SBjoern A. Zeeb 505d9836fb4SBjoern A. Zeeb /* then finally revision 0 */ 506d9836fb4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 507d9836fb4SBjoern A. Zeeb ACPI_WRDS_WIFI_DATA_SIZE_REV0, 508d9836fb4SBjoern A. Zeeb &tbl_rev); 509d9836fb4SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 510d9836fb4SBjoern A. Zeeb if (tbl_rev != 0) { 511*a4128aadSBjoern A. Zeeb ret = -EINVAL; 512d9836fb4SBjoern A. Zeeb goto out_free; 513d9836fb4SBjoern A. Zeeb } 514d9836fb4SBjoern A. Zeeb 515d9836fb4SBjoern A. Zeeb num_chains = ACPI_SAR_NUM_CHAINS_REV0; 516d9836fb4SBjoern A. Zeeb num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; 517d9836fb4SBjoern A. Zeeb 518d9836fb4SBjoern A. Zeeb goto read_table; 519d9836fb4SBjoern A. Zeeb } 520d9836fb4SBjoern A. Zeeb 521d9836fb4SBjoern A. Zeeb ret = PTR_ERR(wifi_pkg); 522d9836fb4SBjoern A. Zeeb goto out_free; 523d9836fb4SBjoern A. Zeeb 524d9836fb4SBjoern A. Zeeb read_table: 525d9836fb4SBjoern A. Zeeb if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { 526d9836fb4SBjoern A. Zeeb ret = -EINVAL; 527d9836fb4SBjoern A. Zeeb goto out_free; 528d9836fb4SBjoern A. Zeeb } 529d9836fb4SBjoern A. Zeeb 530d9836fb4SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); 531d9836fb4SBjoern A. Zeeb 532fac1f593SBjoern A. Zeeb flags = wifi_pkg->package.elements[1].integer.value; 533fac1f593SBjoern A. Zeeb fwrt->reduced_power_flags = flags >> IWL_REDUCE_POWER_FLAGS_POS; 534d9836fb4SBjoern A. Zeeb 535d9836fb4SBjoern A. Zeeb /* position of the actual table */ 536d9836fb4SBjoern A. Zeeb table = &wifi_pkg->package.elements[2]; 537d9836fb4SBjoern A. Zeeb 538d9836fb4SBjoern A. Zeeb /* The profile from WRDS is officially profile 1, but goes 539d9836fb4SBjoern A. Zeeb * into sar_profiles[0] (because we don't have a profile 0). 540d9836fb4SBjoern A. Zeeb */ 541*a4128aadSBjoern A. Zeeb ret = iwl_acpi_sar_set_profile(table, &fwrt->sar_profiles[0], 542fac1f593SBjoern A. Zeeb flags & IWL_SAR_ENABLE_MSK, 543d9836fb4SBjoern A. Zeeb num_chains, num_sub_bands); 544d9836fb4SBjoern A. Zeeb out_free: 545d9836fb4SBjoern A. Zeeb kfree(data); 546d9836fb4SBjoern A. Zeeb return ret; 547d9836fb4SBjoern A. Zeeb } 548d9836fb4SBjoern A. Zeeb 549*a4128aadSBjoern A. Zeeb int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) 550d9836fb4SBjoern A. Zeeb { 551d9836fb4SBjoern A. Zeeb union acpi_object *wifi_pkg, *data; 552d9836fb4SBjoern A. Zeeb bool enabled; 553d9836fb4SBjoern A. Zeeb int i, n_profiles, tbl_rev, pos; 554d9836fb4SBjoern A. Zeeb int ret = 0; 555d9836fb4SBjoern A. Zeeb u8 num_chains, num_sub_bands; 556d9836fb4SBjoern A. Zeeb 557d9836fb4SBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); 558d9836fb4SBjoern A. Zeeb if (IS_ERR(data)) 559d9836fb4SBjoern A. Zeeb return PTR_ERR(data); 560d9836fb4SBjoern A. Zeeb 561d9836fb4SBjoern A. Zeeb /* start by trying to read revision 2 */ 562d9836fb4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 563d9836fb4SBjoern A. Zeeb ACPI_EWRD_WIFI_DATA_SIZE_REV2, 564d9836fb4SBjoern A. Zeeb &tbl_rev); 565d9836fb4SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 566d9836fb4SBjoern A. Zeeb if (tbl_rev != 2) { 567*a4128aadSBjoern A. Zeeb ret = -EINVAL; 568d9836fb4SBjoern A. Zeeb goto out_free; 569d9836fb4SBjoern A. Zeeb } 570d9836fb4SBjoern A. Zeeb 571d9836fb4SBjoern A. Zeeb num_chains = ACPI_SAR_NUM_CHAINS_REV2; 572d9836fb4SBjoern A. Zeeb num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; 573d9836fb4SBjoern A. Zeeb 574d9836fb4SBjoern A. Zeeb goto read_table; 575d9836fb4SBjoern A. Zeeb } 576d9836fb4SBjoern A. Zeeb 577d9836fb4SBjoern A. Zeeb /* then try revision 1 */ 578d9836fb4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 579d9836fb4SBjoern A. Zeeb ACPI_EWRD_WIFI_DATA_SIZE_REV1, 580d9836fb4SBjoern A. Zeeb &tbl_rev); 581d9836fb4SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 582d9836fb4SBjoern A. Zeeb if (tbl_rev != 1) { 583*a4128aadSBjoern A. Zeeb ret = -EINVAL; 584d9836fb4SBjoern A. Zeeb goto out_free; 585d9836fb4SBjoern A. Zeeb } 586d9836fb4SBjoern A. Zeeb 587d9836fb4SBjoern A. Zeeb num_chains = ACPI_SAR_NUM_CHAINS_REV1; 588d9836fb4SBjoern A. Zeeb num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; 589d9836fb4SBjoern A. Zeeb 590d9836fb4SBjoern A. Zeeb goto read_table; 591d9836fb4SBjoern A. Zeeb } 592d9836fb4SBjoern A. Zeeb 593d9836fb4SBjoern A. Zeeb /* then finally revision 0 */ 594d9836fb4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 595d9836fb4SBjoern A. Zeeb ACPI_EWRD_WIFI_DATA_SIZE_REV0, 596d9836fb4SBjoern A. Zeeb &tbl_rev); 597d9836fb4SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 598d9836fb4SBjoern A. Zeeb if (tbl_rev != 0) { 599*a4128aadSBjoern A. Zeeb ret = -EINVAL; 600d9836fb4SBjoern A. Zeeb goto out_free; 601d9836fb4SBjoern A. Zeeb } 602d9836fb4SBjoern A. Zeeb 603d9836fb4SBjoern A. Zeeb num_chains = ACPI_SAR_NUM_CHAINS_REV0; 604d9836fb4SBjoern A. Zeeb num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; 605d9836fb4SBjoern A. Zeeb 606d9836fb4SBjoern A. Zeeb goto read_table; 607d9836fb4SBjoern A. Zeeb } 608d9836fb4SBjoern A. Zeeb 609d9836fb4SBjoern A. Zeeb ret = PTR_ERR(wifi_pkg); 610d9836fb4SBjoern A. Zeeb goto out_free; 611d9836fb4SBjoern A. Zeeb 612d9836fb4SBjoern A. Zeeb read_table: 613d9836fb4SBjoern A. Zeeb if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 614d9836fb4SBjoern A. Zeeb wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { 615d9836fb4SBjoern A. Zeeb ret = -EINVAL; 616d9836fb4SBjoern A. Zeeb goto out_free; 617d9836fb4SBjoern A. Zeeb } 618d9836fb4SBjoern A. Zeeb 619d9836fb4SBjoern A. Zeeb enabled = !!(wifi_pkg->package.elements[1].integer.value); 620d9836fb4SBjoern A. Zeeb n_profiles = wifi_pkg->package.elements[2].integer.value; 621d9836fb4SBjoern A. Zeeb 622d9836fb4SBjoern A. Zeeb /* 623d9836fb4SBjoern A. Zeeb * Check the validity of n_profiles. The EWRD profiles start 624d9836fb4SBjoern A. Zeeb * from index 1, so the maximum value allowed here is 625d9836fb4SBjoern A. Zeeb * ACPI_SAR_PROFILES_NUM - 1. 626d9836fb4SBjoern A. Zeeb */ 627*a4128aadSBjoern A. Zeeb if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { 628d9836fb4SBjoern A. Zeeb ret = -EINVAL; 629d9836fb4SBjoern A. Zeeb goto out_free; 630d9836fb4SBjoern A. Zeeb } 631d9836fb4SBjoern A. Zeeb 632d9836fb4SBjoern A. Zeeb /* the tables start at element 3 */ 633d9836fb4SBjoern A. Zeeb pos = 3; 634d9836fb4SBjoern A. Zeeb 635d9836fb4SBjoern A. Zeeb for (i = 0; i < n_profiles; i++) { 636*a4128aadSBjoern A. Zeeb union acpi_object *table = &wifi_pkg->package.elements[pos]; 637d9836fb4SBjoern A. Zeeb /* The EWRD profiles officially go from 2 to 4, but we 638d9836fb4SBjoern A. Zeeb * save them in sar_profiles[1-3] (because we don't 639d9836fb4SBjoern A. Zeeb * have profile 0). So in the array we start from 1. 640d9836fb4SBjoern A. Zeeb */ 641*a4128aadSBjoern A. Zeeb ret = iwl_acpi_sar_set_profile(table, 642*a4128aadSBjoern A. Zeeb &fwrt->sar_profiles[i + 1], 643*a4128aadSBjoern A. Zeeb enabled, num_chains, 644*a4128aadSBjoern A. Zeeb num_sub_bands); 645d9836fb4SBjoern A. Zeeb if (ret < 0) 646d9836fb4SBjoern A. Zeeb break; 647d9836fb4SBjoern A. Zeeb 648d9836fb4SBjoern A. Zeeb /* go to the next table */ 649d9836fb4SBjoern A. Zeeb pos += num_chains * num_sub_bands; 650d9836fb4SBjoern A. Zeeb } 651d9836fb4SBjoern A. Zeeb 652d9836fb4SBjoern A. Zeeb out_free: 653d9836fb4SBjoern A. Zeeb kfree(data); 654d9836fb4SBjoern A. Zeeb return ret; 655d9836fb4SBjoern A. Zeeb } 656d9836fb4SBjoern A. Zeeb 657*a4128aadSBjoern A. Zeeb int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) 658d9836fb4SBjoern A. Zeeb { 659d9836fb4SBjoern A. Zeeb union acpi_object *wifi_pkg, *data; 660d9836fb4SBjoern A. Zeeb int i, j, k, ret, tbl_rev; 661d9836fb4SBjoern A. Zeeb u8 num_bands, num_profiles; 662d9836fb4SBjoern A. Zeeb static const struct { 663d9836fb4SBjoern A. Zeeb u8 revisions; 664d9836fb4SBjoern A. Zeeb u8 bands; 665d9836fb4SBjoern A. Zeeb u8 profiles; 666d9836fb4SBjoern A. Zeeb u8 min_profiles; 667d9836fb4SBjoern A. Zeeb } rev_data[] = { 668d9836fb4SBjoern A. Zeeb { 669d9836fb4SBjoern A. Zeeb .revisions = BIT(3), 670d9836fb4SBjoern A. Zeeb .bands = ACPI_GEO_NUM_BANDS_REV2, 671d9836fb4SBjoern A. Zeeb .profiles = ACPI_NUM_GEO_PROFILES_REV3, 672*a4128aadSBjoern A. Zeeb .min_profiles = BIOS_GEO_MIN_PROFILE_NUM, 673d9836fb4SBjoern A. Zeeb }, 674d9836fb4SBjoern A. Zeeb { 675d9836fb4SBjoern A. Zeeb .revisions = BIT(2), 676d9836fb4SBjoern A. Zeeb .bands = ACPI_GEO_NUM_BANDS_REV2, 677d9836fb4SBjoern A. Zeeb .profiles = ACPI_NUM_GEO_PROFILES, 678d9836fb4SBjoern A. Zeeb }, 679d9836fb4SBjoern A. Zeeb { 680d9836fb4SBjoern A. Zeeb .revisions = BIT(0) | BIT(1), 681d9836fb4SBjoern A. Zeeb .bands = ACPI_GEO_NUM_BANDS_REV0, 682d9836fb4SBjoern A. Zeeb .profiles = ACPI_NUM_GEO_PROFILES, 683d9836fb4SBjoern A. Zeeb }, 684d9836fb4SBjoern A. Zeeb }; 685d9836fb4SBjoern A. Zeeb int idx; 686d9836fb4SBjoern A. Zeeb /* start from one to skip the domain */ 687d9836fb4SBjoern A. Zeeb int entry_idx = 1; 688d9836fb4SBjoern A. Zeeb 689d9836fb4SBjoern A. Zeeb BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3); 690d9836fb4SBjoern A. Zeeb BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES); 691d9836fb4SBjoern A. Zeeb 692d9836fb4SBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); 693d9836fb4SBjoern A. Zeeb if (IS_ERR(data)) 694d9836fb4SBjoern A. Zeeb return PTR_ERR(data); 695d9836fb4SBjoern A. Zeeb 696d9836fb4SBjoern A. Zeeb /* read the highest revision we understand first */ 697d9836fb4SBjoern A. Zeeb for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) { 698d9836fb4SBjoern A. Zeeb /* min_profiles != 0 requires num_profiles header */ 699d9836fb4SBjoern A. Zeeb u32 hdr_size = 1 + !!rev_data[idx].min_profiles; 700d9836fb4SBjoern A. Zeeb u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE * 701d9836fb4SBjoern A. Zeeb rev_data[idx].bands; 702d9836fb4SBjoern A. Zeeb u32 max_size = hdr_size + profile_size * rev_data[idx].profiles; 703d9836fb4SBjoern A. Zeeb u32 min_size; 704d9836fb4SBjoern A. Zeeb 705d9836fb4SBjoern A. Zeeb if (!rev_data[idx].min_profiles) 706d9836fb4SBjoern A. Zeeb min_size = max_size; 707d9836fb4SBjoern A. Zeeb else 708d9836fb4SBjoern A. Zeeb min_size = hdr_size + 709d9836fb4SBjoern A. Zeeb profile_size * rev_data[idx].min_profiles; 710d9836fb4SBjoern A. Zeeb 711d9836fb4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data, 712d9836fb4SBjoern A. Zeeb min_size, max_size, 713d9836fb4SBjoern A. Zeeb &tbl_rev); 714d9836fb4SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 715d9836fb4SBjoern A. Zeeb if (!(BIT(tbl_rev) & rev_data[idx].revisions)) 716d9836fb4SBjoern A. Zeeb continue; 717d9836fb4SBjoern A. Zeeb 718d9836fb4SBjoern A. Zeeb num_bands = rev_data[idx].bands; 719d9836fb4SBjoern A. Zeeb num_profiles = rev_data[idx].profiles; 720d9836fb4SBjoern A. Zeeb 721d9836fb4SBjoern A. Zeeb if (rev_data[idx].min_profiles) { 722d9836fb4SBjoern A. Zeeb /* read header that says # of profiles */ 723d9836fb4SBjoern A. Zeeb union acpi_object *entry; 724d9836fb4SBjoern A. Zeeb 725d9836fb4SBjoern A. Zeeb entry = &wifi_pkg->package.elements[entry_idx]; 726d9836fb4SBjoern A. Zeeb entry_idx++; 727d9836fb4SBjoern A. Zeeb if (entry->type != ACPI_TYPE_INTEGER || 728*a4128aadSBjoern A. Zeeb entry->integer.value > num_profiles || 729*a4128aadSBjoern A. Zeeb entry->integer.value < 730*a4128aadSBjoern A. Zeeb rev_data[idx].min_profiles) { 731d9836fb4SBjoern A. Zeeb ret = -EINVAL; 732d9836fb4SBjoern A. Zeeb goto out_free; 733d9836fb4SBjoern A. Zeeb } 734d9836fb4SBjoern A. Zeeb 735d9836fb4SBjoern A. Zeeb /* 736*a4128aadSBjoern A. Zeeb * Check to see if we received package count 737*a4128aadSBjoern A. Zeeb * same as max # of profiles 738d9836fb4SBjoern A. Zeeb */ 739d9836fb4SBjoern A. Zeeb if (wifi_pkg->package.count != 740d9836fb4SBjoern A. Zeeb hdr_size + profile_size * num_profiles) { 741d9836fb4SBjoern A. Zeeb ret = -EINVAL; 742d9836fb4SBjoern A. Zeeb goto out_free; 743d9836fb4SBjoern A. Zeeb } 744*a4128aadSBjoern A. Zeeb 745*a4128aadSBjoern A. Zeeb /* Number of valid profiles */ 746*a4128aadSBjoern A. Zeeb num_profiles = entry->integer.value; 747d9836fb4SBjoern A. Zeeb } 748d9836fb4SBjoern A. Zeeb goto read_table; 749d9836fb4SBjoern A. Zeeb } 750d9836fb4SBjoern A. Zeeb } 751d9836fb4SBjoern A. Zeeb 752d9836fb4SBjoern A. Zeeb if (idx < ARRAY_SIZE(rev_data)) 753d9836fb4SBjoern A. Zeeb ret = PTR_ERR(wifi_pkg); 754d9836fb4SBjoern A. Zeeb else 755d9836fb4SBjoern A. Zeeb ret = -ENOENT; 756d9836fb4SBjoern A. Zeeb goto out_free; 757d9836fb4SBjoern A. Zeeb 758d9836fb4SBjoern A. Zeeb read_table: 759d9836fb4SBjoern A. Zeeb fwrt->geo_rev = tbl_rev; 760d9836fb4SBjoern A. Zeeb for (i = 0; i < num_profiles; i++) { 761*a4128aadSBjoern A. Zeeb for (j = 0; j < BIOS_GEO_MAX_NUM_BANDS; j++) { 762d9836fb4SBjoern A. Zeeb union acpi_object *entry; 763d9836fb4SBjoern A. Zeeb 764d9836fb4SBjoern A. Zeeb /* 765d9836fb4SBjoern A. Zeeb * num_bands is either 2 or 3, if it's only 2 then 766d9836fb4SBjoern A. Zeeb * fill the third band (6 GHz) with the values from 767d9836fb4SBjoern A. Zeeb * 5 GHz (second band) 768d9836fb4SBjoern A. Zeeb */ 769d9836fb4SBjoern A. Zeeb if (j >= num_bands) { 770d9836fb4SBjoern A. Zeeb fwrt->geo_profiles[i].bands[j].max = 771d9836fb4SBjoern A. Zeeb fwrt->geo_profiles[i].bands[1].max; 772d9836fb4SBjoern A. Zeeb } else { 773d9836fb4SBjoern A. Zeeb entry = &wifi_pkg->package.elements[entry_idx]; 774d9836fb4SBjoern A. Zeeb entry_idx++; 775d9836fb4SBjoern A. Zeeb if (entry->type != ACPI_TYPE_INTEGER || 776d9836fb4SBjoern A. Zeeb entry->integer.value > U8_MAX) { 777d9836fb4SBjoern A. Zeeb ret = -EINVAL; 778d9836fb4SBjoern A. Zeeb goto out_free; 779d9836fb4SBjoern A. Zeeb } 780d9836fb4SBjoern A. Zeeb 781d9836fb4SBjoern A. Zeeb fwrt->geo_profiles[i].bands[j].max = 782d9836fb4SBjoern A. Zeeb entry->integer.value; 783d9836fb4SBjoern A. Zeeb } 784d9836fb4SBjoern A. Zeeb 785*a4128aadSBjoern A. Zeeb for (k = 0; k < BIOS_GEO_NUM_CHAINS; k++) { 786d9836fb4SBjoern A. Zeeb /* same here as above */ 787d9836fb4SBjoern A. Zeeb if (j >= num_bands) { 788d9836fb4SBjoern A. Zeeb fwrt->geo_profiles[i].bands[j].chains[k] = 789d9836fb4SBjoern A. Zeeb fwrt->geo_profiles[i].bands[1].chains[k]; 790d9836fb4SBjoern A. Zeeb } else { 791d9836fb4SBjoern A. Zeeb entry = &wifi_pkg->package.elements[entry_idx]; 792d9836fb4SBjoern A. Zeeb entry_idx++; 793d9836fb4SBjoern A. Zeeb if (entry->type != ACPI_TYPE_INTEGER || 794d9836fb4SBjoern A. Zeeb entry->integer.value > U8_MAX) { 795d9836fb4SBjoern A. Zeeb ret = -EINVAL; 796d9836fb4SBjoern A. Zeeb goto out_free; 797d9836fb4SBjoern A. Zeeb } 798d9836fb4SBjoern A. Zeeb 799d9836fb4SBjoern A. Zeeb fwrt->geo_profiles[i].bands[j].chains[k] = 800d9836fb4SBjoern A. Zeeb entry->integer.value; 801d9836fb4SBjoern A. Zeeb } 802d9836fb4SBjoern A. Zeeb } 803d9836fb4SBjoern A. Zeeb } 804d9836fb4SBjoern A. Zeeb } 805d9836fb4SBjoern A. Zeeb 806d9836fb4SBjoern A. Zeeb fwrt->geo_num_profiles = num_profiles; 807d9836fb4SBjoern A. Zeeb fwrt->geo_enabled = true; 808d9836fb4SBjoern A. Zeeb ret = 0; 809d9836fb4SBjoern A. Zeeb out_free: 810d9836fb4SBjoern A. Zeeb kfree(data); 811d9836fb4SBjoern A. Zeeb return ret; 812d9836fb4SBjoern A. Zeeb } 813fac1f593SBjoern A. Zeeb 814fac1f593SBjoern A. Zeeb int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) 815fac1f593SBjoern A. Zeeb { 816fac1f593SBjoern A. Zeeb union acpi_object *wifi_pkg, *data, *flags; 817fac1f593SBjoern A. Zeeb int i, j, ret, tbl_rev, num_sub_bands = 0; 818fac1f593SBjoern A. Zeeb int idx = 2; 819fac1f593SBjoern A. Zeeb 820fac1f593SBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD); 821fac1f593SBjoern A. Zeeb if (IS_ERR(data)) 822fac1f593SBjoern A. Zeeb return PTR_ERR(data); 823fac1f593SBjoern A. Zeeb 824*a4128aadSBjoern A. Zeeb /* try to read ppag table rev 3, 2 or 1 (all have the same data size) */ 825fac1f593SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 826fac1f593SBjoern A. Zeeb ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev); 827fac1f593SBjoern A. Zeeb 828fac1f593SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 829*a4128aadSBjoern A. Zeeb if (tbl_rev >= 1 && tbl_rev <= 3) { 830fac1f593SBjoern A. Zeeb num_sub_bands = IWL_NUM_SUB_BANDS_V2; 831fac1f593SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, 832*a4128aadSBjoern A. Zeeb "Reading PPAG table (tbl_rev=%d)\n", 833fac1f593SBjoern A. Zeeb tbl_rev); 834fac1f593SBjoern A. Zeeb goto read_table; 835fac1f593SBjoern A. Zeeb } else { 836fac1f593SBjoern A. Zeeb ret = -EINVAL; 837fac1f593SBjoern A. Zeeb goto out_free; 838fac1f593SBjoern A. Zeeb } 839fac1f593SBjoern A. Zeeb } 840fac1f593SBjoern A. Zeeb 841fac1f593SBjoern A. Zeeb /* try to read ppag table revision 0 */ 842fac1f593SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 843fac1f593SBjoern A. Zeeb ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev); 844fac1f593SBjoern A. Zeeb 845fac1f593SBjoern A. Zeeb if (!IS_ERR(wifi_pkg)) { 846fac1f593SBjoern A. Zeeb if (tbl_rev != 0) { 847fac1f593SBjoern A. Zeeb ret = -EINVAL; 848fac1f593SBjoern A. Zeeb goto out_free; 849fac1f593SBjoern A. Zeeb } 850fac1f593SBjoern A. Zeeb num_sub_bands = IWL_NUM_SUB_BANDS_V1; 851fac1f593SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n"); 852fac1f593SBjoern A. Zeeb goto read_table; 853fac1f593SBjoern A. Zeeb } 854fac1f593SBjoern A. Zeeb 855*a4128aadSBjoern A. Zeeb ret = PTR_ERR(wifi_pkg); 856*a4128aadSBjoern A. Zeeb goto out_free; 857*a4128aadSBjoern A. Zeeb 858fac1f593SBjoern A. Zeeb read_table: 859fac1f593SBjoern A. Zeeb fwrt->ppag_ver = tbl_rev; 860fac1f593SBjoern A. Zeeb flags = &wifi_pkg->package.elements[1]; 861fac1f593SBjoern A. Zeeb 862fac1f593SBjoern A. Zeeb if (flags->type != ACPI_TYPE_INTEGER) { 863fac1f593SBjoern A. Zeeb ret = -EINVAL; 864fac1f593SBjoern A. Zeeb goto out_free; 865fac1f593SBjoern A. Zeeb } 866fac1f593SBjoern A. Zeeb 867*a4128aadSBjoern A. Zeeb fwrt->ppag_flags = iwl_bios_get_ppag_flags(flags->integer.value, 868*a4128aadSBjoern A. Zeeb fwrt->ppag_ver); 869fac1f593SBjoern A. Zeeb 870fac1f593SBjoern A. Zeeb /* 871fac1f593SBjoern A. Zeeb * read, verify gain values and save them into the PPAG table. 872fac1f593SBjoern A. Zeeb * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the 873fac1f593SBjoern A. Zeeb * following sub-bands to High-Band (5GHz). 874fac1f593SBjoern A. Zeeb */ 875fac1f593SBjoern A. Zeeb for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { 876fac1f593SBjoern A. Zeeb for (j = 0; j < num_sub_bands; j++) { 877fac1f593SBjoern A. Zeeb union acpi_object *ent; 878fac1f593SBjoern A. Zeeb 879fac1f593SBjoern A. Zeeb ent = &wifi_pkg->package.elements[idx++]; 880fac1f593SBjoern A. Zeeb if (ent->type != ACPI_TYPE_INTEGER) { 881fac1f593SBjoern A. Zeeb ret = -EINVAL; 882fac1f593SBjoern A. Zeeb goto out_free; 883fac1f593SBjoern A. Zeeb } 884fac1f593SBjoern A. Zeeb 885fac1f593SBjoern A. Zeeb fwrt->ppag_chains[i].subbands[j] = ent->integer.value; 886fac1f593SBjoern A. Zeeb } 887fac1f593SBjoern A. Zeeb } 888fac1f593SBjoern A. Zeeb 889fac1f593SBjoern A. Zeeb ret = 0; 890fac1f593SBjoern A. Zeeb 891fac1f593SBjoern A. Zeeb out_free: 892fac1f593SBjoern A. Zeeb kfree(data); 893fac1f593SBjoern A. Zeeb return ret; 894fac1f593SBjoern A. Zeeb } 8959af1bba4SBjoern A. Zeeb 8969af1bba4SBjoern A. Zeeb void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, 8979af1bba4SBjoern A. Zeeb struct iwl_phy_specific_cfg *filters) 8989af1bba4SBjoern A. Zeeb { 8999af1bba4SBjoern A. Zeeb struct iwl_phy_specific_cfg tmp = {}; 9009af1bba4SBjoern A. Zeeb union acpi_object *wifi_pkg, *data; 9019af1bba4SBjoern A. Zeeb int tbl_rev, i; 9029af1bba4SBjoern A. Zeeb 9039af1bba4SBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_WPFC_METHOD); 9049af1bba4SBjoern A. Zeeb if (IS_ERR(data)) 9059af1bba4SBjoern A. Zeeb return; 9069af1bba4SBjoern A. Zeeb 9079af1bba4SBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 9089af1bba4SBjoern A. Zeeb ACPI_WPFC_WIFI_DATA_SIZE, 9099af1bba4SBjoern A. Zeeb &tbl_rev); 9109af1bba4SBjoern A. Zeeb if (IS_ERR(wifi_pkg)) 9119af1bba4SBjoern A. Zeeb goto out_free; 9129af1bba4SBjoern A. Zeeb 9139af1bba4SBjoern A. Zeeb if (tbl_rev != 0) 9149af1bba4SBjoern A. Zeeb goto out_free; 9159af1bba4SBjoern A. Zeeb 916*a4128aadSBjoern A. Zeeb BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != 917*a4128aadSBjoern A. Zeeb ACPI_WPFC_WIFI_DATA_SIZE - 1); 9189af1bba4SBjoern A. Zeeb 9199af1bba4SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) { 920*a4128aadSBjoern A. Zeeb if (wifi_pkg->package.elements[i + 1].type != ACPI_TYPE_INTEGER) 921*a4128aadSBjoern A. Zeeb goto out_free; 9229af1bba4SBjoern A. Zeeb tmp.filter_cfg_chains[i] = 923*a4128aadSBjoern A. Zeeb cpu_to_le32(wifi_pkg->package.elements[i + 1].integer.value); 9249af1bba4SBjoern A. Zeeb } 9259af1bba4SBjoern A. Zeeb 9269af1bba4SBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n"); 9279af1bba4SBjoern A. Zeeb *filters = tmp; 9289af1bba4SBjoern A. Zeeb out_free: 9299af1bba4SBjoern A. Zeeb kfree(data); 9309af1bba4SBjoern A. Zeeb } 9319af1bba4SBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters); 932*a4128aadSBjoern A. Zeeb 933*a4128aadSBjoern A. Zeeb void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) 934*a4128aadSBjoern A. Zeeb { 935*a4128aadSBjoern A. Zeeb union acpi_object *wifi_pkg, *data; 936*a4128aadSBjoern A. Zeeb int tbl_rev; 937*a4128aadSBjoern A. Zeeb 938*a4128aadSBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_GLAI_METHOD); 939*a4128aadSBjoern A. Zeeb if (IS_ERR(data)) 940*a4128aadSBjoern A. Zeeb return; 941*a4128aadSBjoern A. Zeeb 942*a4128aadSBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 943*a4128aadSBjoern A. Zeeb ACPI_GLAI_WIFI_DATA_SIZE, 944*a4128aadSBjoern A. Zeeb &tbl_rev); 945*a4128aadSBjoern A. Zeeb if (IS_ERR(wifi_pkg)) 946*a4128aadSBjoern A. Zeeb goto out_free; 947*a4128aadSBjoern A. Zeeb 948*a4128aadSBjoern A. Zeeb if (tbl_rev != 0) { 949*a4128aadSBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "Invalid GLAI revision: %d\n", tbl_rev); 950*a4128aadSBjoern A. Zeeb goto out_free; 951*a4128aadSBjoern A. Zeeb } 952*a4128aadSBjoern A. Zeeb 953*a4128aadSBjoern A. Zeeb if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 954*a4128aadSBjoern A. Zeeb wifi_pkg->package.elements[1].integer.value > ACPI_GLAI_MAX_STATUS) 955*a4128aadSBjoern A. Zeeb goto out_free; 956*a4128aadSBjoern A. Zeeb 957*a4128aadSBjoern A. Zeeb fwrt->uefi_tables_lock_status = 958*a4128aadSBjoern A. Zeeb wifi_pkg->package.elements[1].integer.value; 959*a4128aadSBjoern A. Zeeb 960*a4128aadSBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, 961*a4128aadSBjoern A. Zeeb "Loaded UEFI WIFI GUID lock status: %d from ACPI\n", 962*a4128aadSBjoern A. Zeeb fwrt->uefi_tables_lock_status); 963*a4128aadSBjoern A. Zeeb out_free: 964*a4128aadSBjoern A. Zeeb kfree(data); 965*a4128aadSBjoern A. Zeeb } 966*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_acpi_get_guid_lock_status); 967*a4128aadSBjoern A. Zeeb 968*a4128aadSBjoern A. Zeeb int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value) 969*a4128aadSBjoern A. Zeeb { 970*a4128aadSBjoern A. Zeeb union acpi_object *wifi_pkg, *data; 971*a4128aadSBjoern A. Zeeb int ret = -ENOENT; 972*a4128aadSBjoern A. Zeeb int tbl_rev; 973*a4128aadSBjoern A. Zeeb 974*a4128aadSBjoern A. Zeeb data = iwl_acpi_get_object(fwrt->dev, ACPI_WBEM_METHOD); 975*a4128aadSBjoern A. Zeeb if (IS_ERR(data)) 976*a4128aadSBjoern A. Zeeb return ret; 977*a4128aadSBjoern A. Zeeb 978*a4128aadSBjoern A. Zeeb wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 979*a4128aadSBjoern A. Zeeb ACPI_WBEM_WIFI_DATA_SIZE, 980*a4128aadSBjoern A. Zeeb &tbl_rev); 981*a4128aadSBjoern A. Zeeb if (IS_ERR(wifi_pkg)) 982*a4128aadSBjoern A. Zeeb goto out_free; 983*a4128aadSBjoern A. Zeeb 984*a4128aadSBjoern A. Zeeb if (tbl_rev != IWL_ACPI_WBEM_REVISION) { 985*a4128aadSBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "Unsupported ACPI WBEM revision:%d\n", 986*a4128aadSBjoern A. Zeeb tbl_rev); 987*a4128aadSBjoern A. Zeeb goto out_free; 988*a4128aadSBjoern A. Zeeb } 989*a4128aadSBjoern A. Zeeb 990*a4128aadSBjoern A. Zeeb if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) 991*a4128aadSBjoern A. Zeeb goto out_free; 992*a4128aadSBjoern A. Zeeb 993*a4128aadSBjoern A. Zeeb *value = wifi_pkg->package.elements[1].integer.value & 994*a4128aadSBjoern A. Zeeb IWL_ACPI_WBEM_REV0_MASK; 995*a4128aadSBjoern A. Zeeb IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from ACPI\n"); 996*a4128aadSBjoern A. Zeeb ret = 0; 997*a4128aadSBjoern A. Zeeb out_free: 998*a4128aadSBjoern A. Zeeb kfree(data); 999*a4128aadSBjoern A. Zeeb return ret; 1000*a4128aadSBjoern A. Zeeb } 1001