}
/*
- * 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.
+ * This function loads all the DSM functions, it checks the size and populates
+ * the cache with the values 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)
+static int iwl_acpi_load_dsm_values(struct iwl_fw_runtime *fwrt)
{
- size_t expected_size;
- u64 tmp;
+ u64 query_func_val;
int ret;
BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS);
- if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size) || !func))
- return -EINVAL;
+ ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV,
+ DSM_FUNC_QUERY,
+ &iwl_guid, &query_func_val,
+ acpi_dsm_size[DSM_FUNC_QUERY]);
- expected_size = acpi_dsm_size[func];
+ if (ret) {
+ IWL_DEBUG_RADIO(fwrt, "ACPI QUERY FUNC not valid: %d\n", ret);
+ return ret;
+ }
- /* Currently all ACPI DSMs are either 8-bit or 32-bit */
- if (expected_size != sizeof(u8) && expected_size != sizeof(u32))
- return -EOPNOTSUPP;
+ IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n",
+ (u32)query_func_val);
- if (!fwrt->acpi_dsm_funcs_valid) {
- ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV,
- DSM_FUNC_QUERY,
- &iwl_guid, &tmp,
- acpi_dsm_size[DSM_FUNC_QUERY]);
- if (ret) {
- /* always indicate BIT(0) to avoid re-reading */
- fwrt->acpi_dsm_funcs_valid = BIT(0);
- return ret;
+ /* DSM_FUNC_QUERY is 0, start from 1 */
+ for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
+ size_t expected_size = acpi_dsm_size[func];
+ u64 tmp;
+
+ if (!(query_func_val & BIT(func))) {
+ IWL_DEBUG_RADIO(fwrt,
+ "ACPI DSM %d not indicated as valid\n",
+ func);
+ continue;
}
- IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n",
- (u32)tmp);
- /* always indicate BIT(0) to avoid re-reading */
- fwrt->acpi_dsm_funcs_valid = tmp | BIT(0);
+ /* This is an invalid function (5 for example) */
+ if (!expected_size)
+ continue;
+
+ /* Currently all ACPI DSMs are either 8-bit or 32-bit */
+ if (expected_size != sizeof(u8) && expected_size != sizeof(u32))
+ continue;
+
+ ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func,
+ &iwl_guid, &tmp, expected_size);
+ if (ret)
+ continue;
+
+ 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");
+ fwrt->dsm_values[func] = (u32)tmp;
+ fwrt->dsm_funcs_valid |= BIT(func);
}
- if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) {
+ return 0;
+}
+
+/*
+ * 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)
+{
+ if (!fwrt->dsm_funcs_valid) {
+ int ret = iwl_acpi_load_dsm_values(fwrt);
+
+ /*
+ * Always set the valid bit for DSM_FUNC_QUERY so that even if
+ * DSM_FUNC_QUERY returns 0 (no DSM function is valid), we will
+ * still consider the cache as valid.
+ */
+ fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY);
+
+ if (ret)
+ return ret;
+ }
+
+ BUILD_BUG_ON(ARRAY_SIZE(fwrt->dsm_values) != DSM_FUNC_NUM_FUNCS);
+ BUILD_BUG_ON(BITS_PER_TYPE(fwrt->dsm_funcs_valid) < DSM_FUNC_NUM_FUNCS);
+
+ if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values) || !func))
+ return -EINVAL;
+
+ if (!(fwrt->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;
+ *value = fwrt->dsm_values[func];
return 0;
}
* @phy_filters: specific phy filters as read from WPFC BIOS table
* @ppag_bios_rev: PPAG BIOS revision
* @ppag_bios_source: see &enum bios_source
- * @acpi_dsm_funcs_valid: bitmap indicating which DSM values are valid,
+ * @dsm_funcs_valid: bitmap indicating which DSM values are valid,
* zero (default initialization) means it hasn't been read yet,
* and BIT(0) is set when it has since function 0 also has this
- * bitmap and is always supported
+ * bitmap and is always supported.
+ * If the bit is set for a specific function, then the corresponding
+ * entry in &dsm_values is valid.
+ * @dsm_values: cache of the DSM values. The validity of each entry is
+ * determined by &dsm_funcs_valid.
* @geo_enabled: WGDS table is present
* @geo_num_profiles: number of geo profiles
* @geo_rev: geo profiles table revision
struct iwl_phy_specific_cfg phy_filters;
#ifdef CONFIG_ACPI
- u32 acpi_dsm_funcs_valid;
+ u32 dsm_funcs_valid;
+ u32 dsm_values[DSM_FUNC_NUM_FUNCS];
#endif
};