ret = iwl_acpi_get_handle(dev, method, &handle); if (ret) return ERR_PTR(-ENOENT);
/* Call the method with no arguments */
status = acpi_evaluate_object(handle, NULL, NULL, &buf); if (ACPI_FAILURE(status)) {
IWL_DEBUG_DEV_RADIO(dev, "ACPI: %s method invocation failed (status: 0x%x)\n",
method, status); return ERR_PTR(-ENOENT);
} return buf.pointer;
}
/* * Generic function for evaluating a method defined in the device specific * method (DSM) interface. The returned acpi object must be freed by calling * function.
*/ union acpi_object *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func, union acpi_object *args, const guid_t *guid)
{ union acpi_object *obj;
/* * Generic function to evaluate a DSM with no arguments * and an integer return value, * (as an integer object or inside a buffer object), * verify and assign the value in the "value" parameter. * return 0 in success and the appropriate errno otherwise.
*/ staticint iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func, const guid_t *guid, u64 *value,
size_t expected_size)
{ union acpi_object *obj; int ret;
obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid); if (IS_ERR(obj)) {
IWL_DEBUG_DEV_RADIO(dev, "Failed to get DSM object. func= %d\n",
func); return -ENOENT;
}
if (WARN_ON_ONCE(expected_size > sizeof(le_value))) {
ret = -EINVAL; goto out;
}
/* if the buffer size doesn't match the expected size */ if (obj->buffer.length != expected_size)
IWL_DEBUG_DEV_RADIO(dev, "ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
obj->buffer.length);
/* assuming LE from Intel BIOS spec */
memcpy(&le_value, obj->buffer.pointer,
min_t(size_t, expected_size, (size_t)obj->buffer.length));
*value = le64_to_cpu(le_value);
} else {
IWL_DEBUG_DEV_RADIO(dev, "ACPI: DSM method did not return a valid object, type=%d\n",
obj->type);
ret = -EINVAL; goto out;
}
/* * This function receives a DSM function number, calculates its expected size * according to Intel BIOS spec, and fills in the value in a 32-bit field. * In case the expected size is smaller than 32-bit, padding will be added.
*/ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value)
{
size_t expected_size;
u64 tmp; int ret;
if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) {
IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n",
func); return -ENODATA;
}
ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func,
&iwl_guid, &tmp, expected_size); if (ret) return ret;
if ((expected_size == sizeof(u8) && tmp != (u8)tmp) ||
(expected_size == sizeof(u32) && tmp != (u32)tmp))
IWL_DEBUG_RADIO(fwrt, "DSM value overflows the expected size, truncating\n");
*value = (u32)tmp;
return 0;
}
staticunion acpi_object *
iwl_acpi_get_wifi_pkg_range(struct device *dev, union acpi_object *data, int min_data_size, int max_data_size, int *tbl_rev)
{ int i; union acpi_object *wifi_pkg;
/* * We need at least one entry in the wifi package that * describes the domain, and one more entry, otherwise there's * no point in reading it.
*/ if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size)) return ERR_PTR(-EINVAL);
/* * We need at least two packages, one for the revision and one * for the data itself. Also check that the revision is valid * (i.e. it is an integer (each caller has to check by itself * if the returned revision is supported)).
*/ if (data->type != ACPI_TYPE_PACKAGE ||
data->package.count < 2 ||
data->package.elements[0].type != ACPI_TYPE_INTEGER) {
IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n"); return ERR_PTR(-EINVAL);
}
/* loop through all the packages to find the one for WiFi */ for (i = 1; i < data->package.count; i++) { union acpi_object *domain;
wifi_pkg = &data->package.elements[i];
/* skip entries that are not a package with the right size */ if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
wifi_pkg->package.count < min_data_size ||
wifi_pkg->package.count > max_data_size) continue;
country = wifi_pkg->package.elements[3 + i].integer.value;
tas_data->block_list_array[i] = country;
IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country);
}
ret = enabled;
out_free:
kfree(data); return ret;
}
int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
{ union acpi_object *wifi_pkg, *data;
u32 mcc_val; int ret, tbl_rev;
data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDD_METHOD); if (IS_ERR(data)) return PTR_ERR(data);
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
ACPI_WRDD_WIFI_DATA_SIZE,
&tbl_rev); if (IS_ERR(wifi_pkg)) {
ret = PTR_ERR(wifi_pkg); goto out_free;
}
if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
tbl_rev != 0) {
ret = -EINVAL; goto out_free;
}
mcc_val = wifi_pkg->package.elements[1].integer.value; if (mcc_val != BIOS_MCC_CHINA) {
ret = -EINVAL;
IWL_DEBUG_RADIO(fwrt, "ACPI WRDD is supported only for CN\n"); goto out_free;
}
/* position of the actual table */
table = &wifi_pkg->package.elements[2];
/* The profile from WRDS is officially profile 1, but goes * into sar_profiles[0] (because we don't have a profile 0).
*/
ret = iwl_acpi_parse_chains_table(table, fwrt->sar_profiles[0].chains,
num_chains, num_sub_bands); if (!ret && flags & IWL_SAR_ENABLE_MSK)
fwrt->sar_profiles[0].enabled = true;
out_free:
kfree(data); return ret;
}
int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
{ union acpi_object *wifi_pkg, *data; bool enabled; int i, n_profiles, tbl_rev, pos; int ret = 0;
u8 num_sub_bands;
data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); if (IS_ERR(data)) return PTR_ERR(data);
/* start by trying to read revision 2 */
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
ACPI_EWRD_WIFI_DATA_SIZE_REV2,
&tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 2) {
ret = -EINVAL; goto out_free;
}
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
goto read_table;
}
/* then try revision 1 */
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
ACPI_EWRD_WIFI_DATA_SIZE_REV1,
&tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 1) {
ret = -EINVAL; goto out_free;
}
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
goto read_table;
}
/* then finally revision 0 */
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
ACPI_EWRD_WIFI_DATA_SIZE_REV0,
&tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 0) {
ret = -EINVAL; goto out_free;
}
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
goto read_table;
}
ret = PTR_ERR(wifi_pkg); goto out_free;
read_table: if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) {
ret = -EINVAL; goto out_free;
}
/* * Check the validity of n_profiles. The EWRD profiles start * from index 1, so the maximum value allowed here is * ACPI_SAR_PROFILES_NUM - 1.
*/ if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {
ret = -EINVAL; goto out_free;
}
/* parse non-cdb chains for all profiles */ for (i = 0; i < n_profiles; i++) { union acpi_object *table = &wifi_pkg->package.elements[pos];
/* The EWRD profiles officially go from 2 to 4, but we * save them in sar_profiles[1-3] (because we don't * have profile 0). So in the array we start from 1.
*/
ret = iwl_acpi_parse_chains_table(table,
fwrt->sar_profiles[i + 1].chains,
ACPI_SAR_NUM_CHAINS_REV0,
num_sub_bands); if (ret < 0) goto out_free;
/* go to the next table */
pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
}
/* * Check to see if we received package count * same as max # of profiles
*/ if (wifi_pkg->package.count !=
hdr_size + profile_size * num_profiles) {
ret = -EINVAL; goto out_free;
}
/* Number of valid profiles */
num_profiles = entry->integer.value;
} goto read_table;
}
}
if (idx < ARRAY_SIZE(rev_data))
ret = PTR_ERR(wifi_pkg); else
ret = -ENOENT; goto out_free;
read_table:
fwrt->geo_rev = tbl_rev; for (i = 0; i < num_profiles; i++) { for (j = 0; j < BIOS_GEO_MAX_NUM_BANDS; j++) { union acpi_object *entry;
/* * num_bands is either 2 or 3, if it's only 2 then * fill the third band (6 GHz) with the values from * 5 GHz (second band)
*/ if (j >= num_bands) {
fwrt->geo_profiles[i].bands[j].max =
fwrt->geo_profiles[i].bands[1].max;
} else {
entry = &wifi_pkg->package.elements[entry_idx];
entry_idx++; if (entry->type != ACPI_TYPE_INTEGER ||
entry->integer.value > U8_MAX) {
ret = -EINVAL; goto out_free;
}
int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
{ union acpi_object *wifi_pkg, *data, *flags; int i, j, ret, tbl_rev, num_sub_bands = 0; int idx = 2;
data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD); if (IS_ERR(data)) return PTR_ERR(data);
/* try to read ppag table rev 1 to 4 (all have the same data size) */
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
/* * read, verify gain values and save them into the PPAG table. * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the * following sub-bands to High-Band (5GHz).
*/ for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { for (j = 0; j < num_sub_bands; j++) { union acpi_object *ent;
ent = &wifi_pkg->package.elements[idx++]; if (ent->type != ACPI_TYPE_INTEGER) {
ret = -EINVAL; goto out_free;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.