diff --git a/drivers/tegra/hwpm/common/aperture.c b/drivers/tegra/hwpm/common/aperture.c index 634d32e..f979390 100644 --- a/drivers/tegra/hwpm/common/aperture.c +++ b/drivers/tegra/hwpm/common/aperture.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT /* - * SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -219,6 +219,18 @@ static int tegra_hwpm_alloc_dynamic_inst_element_array( inst_a_info->inst_slots = tegra_hwpm_safe_cast_u64_to_u32( ip_element_range / inst_a_info->inst_stride); + if (inst_a_info->inst_slots > TEGRA_HWPM_APERTURE_SLOTS_LIMIT) { + tegra_hwpm_dbg(hwpm, hwpm_dbg_driver_init, + "IP inst range(0x%llx-0x%llx) a_type = %d inst_slots %d" + "over limit, skip allocating dynamic array", + (unsigned long long)inst_a_info->range_start, + (unsigned long long)inst_a_info->range_end, + a_type, inst_a_info->inst_slots); + inst_a_info->islots_overlimit = true; + /* This is a valid case */ + return 0; + } + inst_a_info->inst_arr = tegra_hwpm_kcalloc( hwpm, inst_a_info->inst_slots, sizeof(struct hwpm_ip_inst *)); if (inst_a_info->inst_arr == NULL) { @@ -268,14 +280,14 @@ fail: static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, struct tegra_hwpm_func_args *func_args, enum tegra_hwpm_funcs iia_func, u32 ip_idx, struct hwpm_ip *chip_ip, - u32 static_inst_idx, u32 a_type, u32 static_aperture_idx) + u32 s_inst_idx, u32 a_type, u32 s_element_idx) { int err = 0, ret = 0; struct hwpm_ip_inst *ip_inst = - &chip_ip->ip_inst_static_array[static_inst_idx]; + &chip_ip->ip_inst_static_array[s_inst_idx]; struct hwpm_ip_element_info *e_info = &ip_inst->element_info[a_type]; struct hwpm_ip_aperture *element = - &e_info->element_static_array[static_aperture_idx]; + &e_info->element_static_array[s_element_idx]; u64 element_offset = 0ULL; u32 idx = 0U; u32 reg_val = 0U; @@ -284,6 +296,14 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, switch (iia_func) { case TEGRA_HWPM_INIT_IP_STRUCTURES: + if (e_info->eslots_overlimit) { + tegra_hwpm_dbg(hwpm, hwpm_dbg_driver_init, + "IP %d s_inst_idx %d a_type %u s_element_idx %u" + "Skip using dynamic element array", + ip_idx, s_inst_idx, a_type, s_element_idx); + break; + } + /* Compute element offset from element range start */ element_offset = tegra_hwpm_safe_sub_u64( element->start_abs_pa, e_info->range_start); @@ -295,9 +315,10 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_dbg(hwpm, hwpm_dbg_driver_init, "IP %d inst %d a_type %d element type %d" " start_addr 0x%llx static idx %d == dynamic idx %d", - ip_idx, static_inst_idx, a_type, - element->element_type, (unsigned long long)element->start_abs_pa, - static_aperture_idx, idx); + ip_idx, s_inst_idx, a_type, + element->element_type, + (unsigned long long)element->start_abs_pa, + s_element_idx, idx); /* Set element slot pointer */ e_info->element_arr[idx] = element; @@ -363,7 +384,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_dbg(hwpm, hwpm_dbg_allowlist, "IP %d inst %d a_type %d element type %d" " start_addr 0x%llx not reserved", - ip_idx, static_inst_idx, a_type, + ip_idx, s_inst_idx, a_type, element->element_type, (unsigned long long)element->start_abs_pa); return 0; @@ -376,7 +397,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, } else { tegra_hwpm_err(hwpm, "IP %d" " element type %d static_idx %d NULL alist", - ip_idx, a_type, static_aperture_idx); + ip_idx, a_type, s_element_idx); } break; case TEGRA_HWPM_COMBINE_ALIST: @@ -385,7 +406,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_dbg(hwpm, hwpm_dbg_allowlist, "IP %d inst %d a_type %d element type %d" " start_addr 0x%llx not reserved", - ip_idx, static_inst_idx, a_type, + ip_idx, s_inst_idx, a_type, element->element_type, (unsigned long long)element->start_abs_pa); return 0; @@ -396,7 +417,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_err(hwpm, "IP %d element type %d static_idx %d" " alist copy failed", - ip_idx, a_type, static_aperture_idx); + ip_idx, a_type, s_element_idx); return err; } break; @@ -406,7 +427,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_dbg(hwpm, hwpm_dbg_reserve_resource, "IP %d inst %d a_type %d element type %d" " start_addr 0x%llx not reservable", - ip_idx, static_inst_idx, a_type, + ip_idx, s_inst_idx, a_type, element->element_type, (unsigned long long)element->start_abs_pa); return 0; @@ -415,7 +436,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, if (err != 0) { tegra_hwpm_err(hwpm, "IP %d element" " type %d static_idx %d reserve failed", - ip_idx, a_type, static_aperture_idx); + ip_idx, a_type, s_element_idx); goto fail; } break; @@ -426,7 +447,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_dbg(hwpm, hwpm_dbg_release_resource, "IP %d inst %d a_type %d element type %d" " start_addr 0x%llx not reserved", - ip_idx, static_inst_idx, a_type, + ip_idx, s_inst_idx, a_type, element->element_type, (unsigned long long)element->start_abs_pa); return 0; @@ -435,7 +456,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, if (ret != 0) { tegra_hwpm_err(hwpm, "IP %d element" " type %d idx %d release failed", - ip_idx, a_type, static_aperture_idx); + ip_idx, a_type, s_element_idx); } break; case TEGRA_HWPM_BIND_RESOURCES: @@ -444,7 +465,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_dbg(hwpm, hwpm_dbg_bind, "IP %d inst %d a_type %d element type %d" " start_addr 0x%llx not reserved", - ip_idx, static_inst_idx, a_type, + ip_idx, s_inst_idx, a_type, element->element_type, (unsigned long long)element->start_abs_pa); return 0; @@ -454,7 +475,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, if (err != 0) { tegra_hwpm_err(hwpm, "IP %d element" " type %d idx %d zero regs failed", - ip_idx, a_type, static_aperture_idx); + ip_idx, a_type, s_element_idx); goto fail; } @@ -462,7 +483,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, if (err != 0) { tegra_hwpm_err(hwpm, "IP %d element" " type %d idx %d enable failed", - ip_idx, a_type, static_aperture_idx); + ip_idx, a_type, s_element_idx); goto fail; } break; @@ -472,7 +493,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_dbg(hwpm, hwpm_dbg_bind, "IP %d inst %d a_type %d element type %d" " start_addr 0x%llx not reserved", - ip_idx, static_inst_idx, a_type, + ip_idx, s_inst_idx, a_type, element->element_type, (unsigned long long)element->start_abs_pa); return 0; @@ -481,8 +502,8 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, err = tegra_hwpm_element_disable(hwpm, element); if (err != 0) { tegra_hwpm_err(hwpm, "IP %d element" - " type %d idx %d enable failed", - ip_idx, a_type, static_aperture_idx); + " type %d idx %d disable failed", + ip_idx, a_type, s_element_idx); goto fail; } @@ -491,7 +512,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, if (err != 0) { tegra_hwpm_err(hwpm, "IP %d element" " type %d idx %d zero regs failed", - ip_idx, a_type, static_aperture_idx); + ip_idx, a_type, s_element_idx); goto fail; } break; @@ -501,7 +522,7 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, tegra_hwpm_dbg(hwpm, hwpm_dbg_driver_release, "IP %d inst %d a_type %d element type %d" " start_addr 0x%llx not reserved", - ip_idx, static_inst_idx, a_type, + ip_idx, s_inst_idx, a_type, element->element_type, (unsigned long long)element->start_abs_pa); return 0; @@ -521,13 +542,13 @@ fail: static int tegra_hwpm_func_all_elements_of_type(struct tegra_soc_hwpm *hwpm, struct tegra_hwpm_func_args *func_args, enum tegra_hwpm_funcs iia_func, u32 ip_idx, struct hwpm_ip *chip_ip, - u32 static_inst_idx, u32 a_type) + u32 s_inst_idx, u32 a_type) { u32 static_idx = 0U, idx = 0U; u64 inst_element_range = 0ULL; int err = 0; struct hwpm_ip_inst *ip_inst = - &chip_ip->ip_inst_static_array[static_inst_idx]; + &chip_ip->ip_inst_static_array[s_inst_idx]; struct hwpm_ip_element_info *e_info = &ip_inst->element_info[a_type]; tegra_hwpm_fn(hwpm, " "); @@ -537,7 +558,7 @@ static int tegra_hwpm_func_all_elements_of_type(struct tegra_soc_hwpm *hwpm, /* no a_type elements in this IP */ tegra_hwpm_dbg(hwpm, hwpm_dbg_driver_init, "No a_type = %d elements in IP %d stat inst %d", - a_type, ip_idx, static_inst_idx); + a_type, ip_idx, s_inst_idx); return 0; } @@ -547,6 +568,20 @@ static int tegra_hwpm_func_all_elements_of_type(struct tegra_soc_hwpm *hwpm, e_info->element_slots = tegra_hwpm_safe_cast_u64_to_u32( inst_element_range / e_info->element_stride); + if (e_info->element_slots > TEGRA_HWPM_APERTURE_SLOTS_LIMIT) { + tegra_hwpm_dbg(hwpm, hwpm_dbg_driver_init, + "iia_func %d IP %d static inst %d a_type %d" + " element range(0x%llx-0x%llx) element_slots %d " + "over limit, skip allocating dynamic array", + iia_func, ip_idx, s_inst_idx, a_type, + (unsigned long long)e_info->range_start, + (unsigned long long)e_info->range_end, + e_info->element_slots); + e_info->eslots_overlimit = true; + /* This is a valid case */ + return 0; + } + e_info->element_arr = tegra_hwpm_kcalloc( hwpm, e_info->element_slots, sizeof(struct hwpm_ip_aperture *)); @@ -564,7 +599,7 @@ static int tegra_hwpm_func_all_elements_of_type(struct tegra_soc_hwpm *hwpm, "iia_func %d IP %d static inst %d a_type %d" " element range(0x%llx-0x%llx) element_slots %d " "num_element_per_inst %d", - iia_func, ip_idx, static_inst_idx, a_type, + iia_func, ip_idx, s_inst_idx, a_type, (unsigned long long)e_info->range_start, (unsigned long long)e_info->range_end, e_info->element_slots, e_info->num_element_per_inst); @@ -581,11 +616,11 @@ static int tegra_hwpm_func_all_elements_of_type(struct tegra_soc_hwpm *hwpm, static_idx++) { err = tegra_hwpm_func_single_element( hwpm, func_args, iia_func, ip_idx, - chip_ip, static_inst_idx, a_type, static_idx); + chip_ip, s_inst_idx, a_type, static_idx); if (err != 0) { tegra_hwpm_err(hwpm, "IP %d inst %d a_type %d idx %d func %d failed", - ip_idx, static_inst_idx, a_type, + ip_idx, s_inst_idx, a_type, static_idx, iia_func); goto fail; } @@ -605,7 +640,7 @@ fail: static int tegra_hwpm_func_all_elements(struct tegra_soc_hwpm *hwpm, struct tegra_hwpm_func_args *func_args, enum tegra_hwpm_funcs iia_func, u32 ip_idx, struct hwpm_ip *chip_ip, - u32 static_inst_idx) + u32 s_inst_idx) { u32 a_type; int err = 0; @@ -614,11 +649,11 @@ static int tegra_hwpm_func_all_elements(struct tegra_soc_hwpm *hwpm, for (a_type = 0U; a_type < TEGRA_HWPM_APERTURE_TYPE_MAX; a_type++) { err = tegra_hwpm_func_all_elements_of_type(hwpm, func_args, - iia_func, ip_idx, chip_ip, static_inst_idx, a_type); + iia_func, ip_idx, chip_ip, s_inst_idx, a_type); if (err != 0) { tegra_hwpm_err(hwpm, "IP %d inst %d a_type %d func %d failed", - ip_idx, static_inst_idx, a_type, iia_func); + ip_idx, s_inst_idx, a_type, iia_func); goto fail; } } @@ -631,13 +666,13 @@ fail: static int tegra_hwpm_func_single_inst(struct tegra_soc_hwpm *hwpm, struct tegra_hwpm_func_args *func_args, enum tegra_hwpm_funcs iia_func, u32 ip_idx, struct hwpm_ip *chip_ip, - u32 static_inst_idx) + u32 s_inst_idx) { int err = 0; u32 a_type, idx = 0U; u64 inst_offset = 0ULL; struct hwpm_ip_inst *ip_inst = - &chip_ip->ip_inst_static_array[static_inst_idx]; + &chip_ip->ip_inst_static_array[s_inst_idx]; struct hwpm_ip_inst_per_aperture_info *inst_a_info = NULL; struct hwpm_ip_element_info *e_info = NULL; @@ -651,8 +686,15 @@ static int tegra_hwpm_func_single_inst(struct tegra_soc_hwpm *hwpm, if (inst_a_info->range_end == 0ULL) { tegra_hwpm_dbg(hwpm, hwpm_dbg_driver_init, - "No a_type = %d elements in IP %d", - a_type, ip_idx); + "No a_type = %d elements in IP %d", + a_type, ip_idx); + continue; + } + + if (inst_a_info->islots_overlimit) { + tegra_hwpm_dbg(hwpm, hwpm_dbg_driver_init, + "IP %d s_inst_idx %d Skip using dynamic instance array", + ip_idx, s_inst_idx); continue; } @@ -668,8 +710,10 @@ static int tegra_hwpm_func_single_inst(struct tegra_soc_hwpm *hwpm, "IP %d a_type %d inst range start 0x%llx" "element range start 0x%llx" " static inst idx %d == dynamic idx %d", - ip_idx, a_type, (unsigned long long)inst_a_info->range_start, - (unsigned long long)e_info->range_start, static_inst_idx, idx); + ip_idx, a_type, + (unsigned long long)inst_a_info->range_start, + (unsigned long long)e_info->range_start, + s_inst_idx, idx); /* Set perfmux slot pointer */ inst_a_info->inst_arr[idx] = ip_inst; @@ -688,17 +732,17 @@ static int tegra_hwpm_func_single_inst(struct tegra_soc_hwpm *hwpm, if (err != 0) { tegra_hwpm_err(hwpm, "IP %d inst %d power mgmt disable failed", - ip_idx, static_inst_idx); + ip_idx, s_inst_idx); goto fail; } } /* Continue functionality for all apertures */ err = tegra_hwpm_func_all_elements(hwpm, func_args, iia_func, - ip_idx, chip_ip, static_inst_idx); + ip_idx, chip_ip, s_inst_idx); if (err != 0) { tegra_hwpm_err(hwpm, "IP %d inst %d func 0x%x failed", - ip_idx, static_inst_idx, iia_func); + ip_idx, s_inst_idx, iia_func); goto fail; } @@ -721,7 +765,7 @@ static int tegra_hwpm_func_single_inst(struct tegra_soc_hwpm *hwpm, if (err != 0) { tegra_hwpm_err(hwpm, "IP %d inst %d power mgmt enable failed", - ip_idx, static_inst_idx); + ip_idx, s_inst_idx); goto fail; } } @@ -735,22 +779,22 @@ static int tegra_hwpm_func_all_inst(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, u32 ip_idx, struct hwpm_ip *chip_ip) { int err = 0, ret = 0; - u32 inst_idx = 0U; + u32 s_inst_idx = 0U; unsigned long reserved_insts = 0UL, idx = 0UL; tegra_hwpm_fn(hwpm, " "); - for (inst_idx = 0U; inst_idx < chip_ip->num_instances; inst_idx++) { + for (s_inst_idx = 0U; s_inst_idx < chip_ip->num_instances; s_inst_idx++) { err = tegra_hwpm_func_single_inst(hwpm, func_args, iia_func, - ip_idx, chip_ip, inst_idx); + ip_idx, chip_ip, s_inst_idx); if (err != 0) { tegra_hwpm_err(hwpm, "IP %d inst %d func 0x%x failed", - ip_idx, inst_idx, iia_func); + ip_idx, s_inst_idx, iia_func); goto fail; } if (iia_func == TEGRA_HWPM_RESERVE_GIVEN_RESOURCE) { - reserved_insts |= BIT(inst_idx); + reserved_insts |= BIT(s_inst_idx); } } diff --git a/drivers/tegra/hwpm/common/ip.c b/drivers/tegra/hwpm/common/ip.c index 399ad7d..54e8ddf 100644 --- a/drivers/tegra/hwpm/common/ip.c +++ b/drivers/tegra/hwpm/common/ip.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT /* - * SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ #include #include #include +#include #include int tegra_hwpm_ip_handle_power_mgmt(struct tegra_soc_hwpm *hwpm, @@ -56,13 +57,12 @@ int tegra_hwpm_ip_handle_power_mgmt(struct tegra_soc_hwpm *hwpm, } int tegra_hwpm_update_ip_inst_fs_mask(struct tegra_soc_hwpm *hwpm, - u32 ip_idx, u32 a_type, u32 inst_idx, bool available) + u32 ip_idx, u32 a_type, u32 s_inst_idx, bool available) { struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; struct hwpm_ip *chip_ip = active_chip->chip_ips[ip_idx]; - struct hwpm_ip_inst_per_aperture_info *inst_a_info = - &chip_ip->inst_aperture_info[a_type]; - struct hwpm_ip_inst *ip_inst = inst_a_info->inst_arr[inst_idx]; + struct hwpm_ip_inst *ip_inst = + &chip_ip->ip_inst_static_array[s_inst_idx]; int ret = 0; tegra_hwpm_fn(hwpm, " "); @@ -100,13 +100,12 @@ int tegra_hwpm_update_ip_inst_fs_mask(struct tegra_soc_hwpm *hwpm, static int tegra_hwpm_update_ip_ops_info(struct tegra_soc_hwpm *hwpm, struct tegra_hwpm_ip_ops *ip_ops, - u32 ip_idx, u32 a_type, u32 inst_idx, bool available) + u32 ip_idx, u32 a_type, u32 s_inst_idx, bool available) { struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; struct hwpm_ip *chip_ip = active_chip->chip_ips[ip_idx]; - struct hwpm_ip_inst_per_aperture_info *inst_a_info = - &chip_ip->inst_aperture_info[a_type]; - struct hwpm_ip_inst *ip_inst = inst_a_info->inst_arr[inst_idx]; + struct hwpm_ip_inst *ip_inst = + &chip_ip->ip_inst_static_array[s_inst_idx]; /* Update IP ops info for the instance */ struct tegra_hwpm_ip_ops *ops = &ip_inst->ip_ops; @@ -135,7 +134,7 @@ int tegra_hwpm_set_fs_info_ip_ops(struct tegra_soc_hwpm *hwpm, int ret = 0; bool found = false; u32 idx = ip_idx; - u32 inst_idx = 0U, element_idx = 0U; + u32 s_inst_idx = 0U, s_element_idx = 0U; u32 a_type = 0U; enum tegra_hwpm_element_type element_type = HWPM_ELEMENT_INVALID; @@ -144,7 +143,7 @@ int tegra_hwpm_set_fs_info_ip_ops(struct tegra_soc_hwpm *hwpm, /* Find IP aperture containing phys_addr in allowlist */ found = tegra_hwpm_aperture_for_address(hwpm, TEGRA_HWPM_MATCH_BASE_ADDRESS, base_address, - &idx, &inst_idx, &element_idx, &element_type); + &idx, &s_inst_idx, &s_element_idx, &element_type); if (!found) { tegra_hwpm_err(hwpm, "Base addr 0x%llx not in IP %d", (unsigned long long)base_address, idx); @@ -152,9 +151,10 @@ int tegra_hwpm_set_fs_info_ip_ops(struct tegra_soc_hwpm *hwpm, } tegra_hwpm_dbg(hwpm, hwpm_dbg_ip_register, - "Found addr 0x%llx IP %d inst_idx %d element_idx %d e_type %d", - (unsigned long long)base_address, idx, inst_idx, - element_idx, element_type); + "Found addr 0x%llx IP %d s_inst_idx %d " + "s_element_idx %d e_type %d", + (unsigned long long)base_address, idx, s_inst_idx, + s_element_idx, element_type); switch (element_type) { case HWPM_ELEMENT_PERFMON: @@ -175,21 +175,21 @@ int tegra_hwpm_set_fs_info_ip_ops(struct tegra_soc_hwpm *hwpm, if (ip_ops != NULL) { /* Update IP ops */ ret = tegra_hwpm_update_ip_ops_info(hwpm, ip_ops, - ip_idx, a_type, inst_idx, available); + ip_idx, a_type, s_inst_idx, available); if (ret != 0) { tegra_hwpm_err(hwpm, - "IP %d inst_idx %d: Failed to update ip_ops", - ip_idx, inst_idx); + "IP %d s_inst_idx %d: Failed to update ip_ops", + ip_idx, s_inst_idx); goto fail; } } ret = tegra_hwpm_update_ip_inst_fs_mask(hwpm, ip_idx, a_type, - inst_idx, available); + s_inst_idx, available); if (ret != 0) { tegra_hwpm_err(hwpm, - "IP %d inst_idx %d: Failed to update fs_info", - ip_idx, inst_idx); + "IP %d s_inst_idx %d: Failed to update fs_info", + ip_idx, s_inst_idx); goto fail; } @@ -200,7 +200,7 @@ fail: int tegra_hwpm_get_fs_info(struct tegra_soc_hwpm *hwpm, u32 ip_enum, u64 *fs_mask, u8 *ip_status) { - u32 ip_idx = 0U, inst_idx = 0U, element_mask_shift = 0U; + u32 ip_idx = 0U, s_inst_idx = 0U, element_mask_shift = 0U; u64 floorsweep = 0ULL; struct tegra_soc_hwpm_chip *active_chip = NULL; struct hwpm_ip *chip_ip = NULL; @@ -213,11 +213,12 @@ int tegra_hwpm_get_fs_info(struct tegra_soc_hwpm *hwpm, active_chip = hwpm->active_chip; chip_ip = active_chip->chip_ips[ip_idx]; if (!(chip_ip->override_enable) && chip_ip->inst_fs_mask) { - for (inst_idx = 0U; inst_idx < chip_ip->num_instances; - inst_idx++) { + for (s_inst_idx = 0U; + s_inst_idx < chip_ip->num_instances; + s_inst_idx++) { ip_inst = &chip_ip->ip_inst_static_array[ - inst_idx]; - element_mask_shift = (inst_idx == 0U ? 0U : + s_inst_idx]; + element_mask_shift = (s_inst_idx == 0U ? 0U : ip_inst->num_core_elements_per_inst); if (ip_inst->hw_inst_mask & @@ -230,6 +231,9 @@ int tegra_hwpm_get_fs_info(struct tegra_soc_hwpm *hwpm, *fs_mask = floorsweep; *ip_status = TEGRA_HWPM_IP_STATUS_VALID; + tegra_hwpm_dbg(hwpm, hwpm_dbg_floorsweep_info, + "SOC hwpm IP %d is available", ip_enum); + return 0; } } @@ -259,12 +263,17 @@ int tegra_hwpm_get_resource_info(struct tegra_soc_hwpm *hwpm, if (!(chip_ip->override_enable)) { *status = tegra_hwpm_safe_cast_u32_to_u8( chip_ip->resource_status); + tegra_hwpm_dbg(hwpm, hwpm_dbg_floorsweep_info, + "SOC hwpm Resource %d is %d", + resource_enum, chip_ip->resource_status); return 0; } } *status = tegra_hwpm_safe_cast_u32_to_u8( TEGRA_HWPM_RESOURCE_STATUS_INVALID); + tegra_hwpm_dbg(hwpm, hwpm_dbg_floorsweep_info, + "SOC hwpm Resource %d is unavailable", resource_enum); return 0; } @@ -305,23 +314,25 @@ int tegra_hwpm_finalize_chip_info(struct tegra_soc_hwpm *hwpm) static bool tegra_hwpm_addr_in_single_element(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, - u64 find_addr, u32 *ip_idx, u32 *inst_idx, u32 *element_idx, + u64 find_addr, u32 *ip_idx, u32 *s_inst_idx, u32 *s_element_idx, enum tegra_hwpm_element_type *element_type, u32 a_type) { struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; struct hwpm_ip *chip_ip = active_chip->chip_ips[*ip_idx]; - struct hwpm_ip_inst_per_aperture_info *inst_a_info = - &chip_ip->inst_aperture_info[a_type]; - struct hwpm_ip_inst *ip_inst = inst_a_info->inst_arr[*inst_idx]; + struct hwpm_ip_inst *ip_inst = + &chip_ip->ip_inst_static_array[*s_inst_idx]; struct hwpm_ip_element_info *e_info = &ip_inst->element_info[a_type]; - struct hwpm_ip_aperture *element = e_info->element_arr[*element_idx]; + struct hwpm_ip_aperture *element = + &e_info->element_static_array[*s_element_idx]; + + tegra_hwpm_fn(hwpm, " "); if (element == NULL) { tegra_hwpm_dbg(hwpm, hwpm_verbose, - "IP %d addr 0x%llx inst_idx %d " - "a_type %d: element_idx %d not populated", - *ip_idx, (unsigned long long)find_addr, *inst_idx, - a_type, *element_idx); + "IP %d addr 0x%llx s_inst_idx %d " + "a_type %d: s_element_idx %d not populated", + *ip_idx, (unsigned long long)find_addr, *s_inst_idx, + a_type, *s_element_idx); return false; } @@ -330,20 +341,21 @@ static bool tegra_hwpm_addr_in_single_element(struct tegra_soc_hwpm *hwpm, if ((element->element_index_mask & ip_inst->element_fs_mask) == 0U) { tegra_hwpm_dbg(hwpm, hwpm_dbg_regops, - "IP %d addr 0x%llx inst_idx %d " - "a_type %d: element_idx %d: not available", + "IP %d addr 0x%llx s_inst_idx %d " + "a_type %d: s_element_idx %d: not available", *ip_idx, (unsigned long long)find_addr, - *inst_idx, a_type, *element_idx); + *s_inst_idx, a_type, *s_element_idx); return false; } /* Make sure phys addr belongs to this element */ if ((find_addr < element->start_abs_pa) || (find_addr > element->end_abs_pa)) { - tegra_hwpm_err(hwpm, "IP %d addr 0x%llx inst_idx %d " - "a_type %d element_idx %d: out of bounds", - *ip_idx, (unsigned long long)find_addr, *inst_idx, - a_type, *element_idx); + tegra_hwpm_dbg(hwpm, hwpm_dbg_regops, + "IP %d addr 0x%llx s_inst_idx %d " + "a_type %d s_element_idx %d: out of bounds", + *ip_idx, (unsigned long long)find_addr, + *s_inst_idx, a_type, *s_element_idx); return false; } @@ -353,10 +365,10 @@ static bool tegra_hwpm_addr_in_single_element(struct tegra_soc_hwpm *hwpm, } tegra_hwpm_dbg(hwpm, hwpm_dbg_regops, - "IP %d addr 0x%llx inst_idx %d " - "a_type %d element_idx %d address not in alist", + "IP %d addr 0x%llx s_inst_idx %d " + "a_type %d s_element_idx %d address not in alist", *ip_idx, (unsigned long long)find_addr, - *inst_idx, a_type, *element_idx); + *s_inst_idx, a_type, *s_element_idx); return false; } @@ -364,10 +376,10 @@ static bool tegra_hwpm_addr_in_single_element(struct tegra_soc_hwpm *hwpm, /* Confirm that given addr is base address of this element */ if (find_addr != element->start_abs_pa) { tegra_hwpm_dbg(hwpm, hwpm_dbg_ip_register, - "IP %d addr 0x%llx inst_idx %d " - "a_type %d element_idx %d: addr != start addr", - *ip_idx, (unsigned long long)find_addr, *inst_idx, - a_type, *element_idx); + "IP %d addr 0x%llx s_inst_idx %d " + "a_type %d s_element_idx %d addr != start addr", + *ip_idx, (unsigned long long)find_addr, + *s_inst_idx, a_type, *s_element_idx); return false; } *element_type = element->element_type; @@ -380,73 +392,118 @@ static bool tegra_hwpm_addr_in_single_element(struct tegra_soc_hwpm *hwpm, static bool tegra_hwpm_addr_in_all_elements(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, - u64 find_addr, u32 *ip_idx, u32 *inst_idx, u32 *element_idx, + u64 find_addr, u32 *ip_idx, u32 *s_inst_idx, u32 *s_element_idx, enum tegra_hwpm_element_type *element_type, u32 a_type) { struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; struct hwpm_ip *chip_ip = active_chip->chip_ips[*ip_idx]; - struct hwpm_ip_inst_per_aperture_info *inst_a_info = - &chip_ip->inst_aperture_info[a_type]; - struct hwpm_ip_inst *ip_inst = inst_a_info->inst_arr[*inst_idx]; + struct hwpm_ip_inst *ip_inst = + &chip_ip->ip_inst_static_array[*s_inst_idx]; struct hwpm_ip_element_info *e_info = &ip_inst->element_info[a_type]; + struct hwpm_ip_aperture *element = NULL; u64 element_offset = 0ULL; - u32 idx; + u32 idx = 0U; + u32 dyn_idx = 0U; + + tegra_hwpm_fn(hwpm, " "); /* Make sure address falls in elements of a_type */ if (e_info->num_element_per_inst == 0U) { tegra_hwpm_dbg(hwpm, hwpm_verbose, - "IP %d addr 0x%llx: inst_idx %d no type %d elements", - *ip_idx, (unsigned long long)find_addr, *inst_idx, a_type); + "IP %d addr 0x%llx: s_inst_idx %d no type %d elements", + *ip_idx, (unsigned long long)find_addr, + *s_inst_idx, a_type); return false; } if ((find_addr < e_info->range_start) || (find_addr > e_info->range_end)) { /* Address not in this instance corresponding to a_type */ - tegra_hwpm_dbg(hwpm, hwpm_verbose, "IP %d inst_idx %d: " + tegra_hwpm_dbg(hwpm, hwpm_verbose, "IP %d s_inst_idx %d: " "addr 0x%llx not in type %d elements", - *ip_idx, *inst_idx, (unsigned long long)find_addr, a_type); + *ip_idx, *s_inst_idx, + (unsigned long long)find_addr, a_type); return false; } - /* Find element index to which address belongs to */ - element_offset = tegra_hwpm_safe_sub_u64( - find_addr, e_info->range_start); - idx = tegra_hwpm_safe_cast_u64_to_u32( - element_offset / e_info->element_stride); + if (e_info->eslots_overlimit) { + /* Use brute force approach to find element index */ + for (idx = 0U; idx < e_info->num_element_per_inst; idx++) { + element = &e_info->element_static_array[idx]; + if ((find_addr >= element->start_abs_pa) && + (find_addr <= element->end_abs_pa)) { + /* Found element with given address */ + break; + } + } - /* Make sure element index is valid */ - if (idx >= e_info->element_slots) { - tegra_hwpm_err(hwpm, "IP %d addr 0x%llx inst_idx %d a_type %d: " - "element_idx %d out of bounds", - *ip_idx, (unsigned long long)find_addr, *inst_idx, a_type, idx); - return false; + /* Make sure element index is valid */ + if (idx >= e_info->num_element_per_inst) { + tegra_hwpm_dbg(hwpm, hwpm_verbose, + "IP %d addr 0x%llx s_inst_idx %d a_type %d: " + "s_element_idx %d out of bounds", + *ip_idx, (unsigned long long)find_addr, + *s_inst_idx, a_type, idx); + return false; + } + } else { + /* Find element index to which address belongs to */ + element_offset = tegra_hwpm_safe_sub_u64( + find_addr, e_info->range_start); + dyn_idx = tegra_hwpm_safe_cast_u64_to_u32( + element_offset / e_info->element_stride); + + /* Make sure element index is valid */ + if (dyn_idx >= e_info->element_slots) { + tegra_hwpm_dbg(hwpm, hwpm_verbose, + "IP %d addr 0x%llx s_inst_idx %d a_type %d: " + "dynamic element_idx %d out of bounds", + *ip_idx, (unsigned long long)find_addr, + *s_inst_idx, a_type, dyn_idx); + return false; + } + + /* Convert dynamic index to static index */ + element = e_info->element_arr[dyn_idx]; + if (element == NULL) { + tegra_hwpm_dbg(hwpm, hwpm_verbose, + "IP %d addr 0x%llx s_inst_idx %d a_type %d: " + "dynamic element_idx %d not populated", + *ip_idx, (unsigned long long)find_addr, + *s_inst_idx, a_type, dyn_idx); + return false; + } + idx = element->aperture_index; + tegra_hwpm_dbg(hwpm, hwpm_dbg_ip_register, + "find_addr 0x%llx element dyn_idx %u static idx %u", + find_addr, dyn_idx, idx); } - *element_idx = idx; + *s_element_idx = idx; /* Process further and return */ return tegra_hwpm_addr_in_single_element(hwpm, iia_func, - find_addr, ip_idx, inst_idx, element_idx, element_type, a_type); + find_addr, ip_idx, s_inst_idx, s_element_idx, + element_type, a_type); } static bool tegra_hwpm_addr_in_single_instance(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, - u64 find_addr, u32 *ip_idx, u32 *inst_idx, u32 *element_idx, + u64 find_addr, u32 *ip_idx, u32 *s_inst_idx, u32 *s_element_idx, enum tegra_hwpm_element_type *element_type, u32 a_type) { struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; struct hwpm_ip *chip_ip = active_chip->chip_ips[*ip_idx]; - struct hwpm_ip_inst_per_aperture_info *inst_a_info = - &chip_ip->inst_aperture_info[a_type]; - struct hwpm_ip_inst *ip_inst = inst_a_info->inst_arr[*inst_idx]; + struct hwpm_ip_inst *ip_inst = + &chip_ip->ip_inst_static_array[*s_inst_idx]; tegra_hwpm_fn(hwpm, " "); if (ip_inst == NULL) { tegra_hwpm_dbg(hwpm, hwpm_verbose, "IP %d addr 0x%llx: " - "a_type %d inst_idx %d not populated", - *ip_idx, (unsigned long long)find_addr, a_type, *inst_idx); + "a_type %d s_inst_idx %d not populated", + *ip_idx, (unsigned long long)find_addr, + a_type, *s_inst_idx); return false; } @@ -455,56 +512,103 @@ static bool tegra_hwpm_addr_in_single_instance(struct tegra_soc_hwpm *hwpm, if ((chip_ip->inst_fs_mask & ip_inst->hw_inst_mask) == 0U) { tegra_hwpm_dbg(hwpm, hwpm_dbg_regops, "IP %d addr 0x%llx: " - "a_type %d inst_idx %d not available", - *ip_idx, (unsigned long long)find_addr, a_type, *inst_idx); + "a_type %d s_inst_idx %d not available", + *ip_idx, (unsigned long long)find_addr, + a_type, *s_inst_idx); return false; } } /* Process further and return */ return tegra_hwpm_addr_in_all_elements(hwpm, iia_func, - find_addr, ip_idx, inst_idx, element_idx, element_type, a_type); + find_addr, ip_idx, s_inst_idx, s_element_idx, + element_type, a_type); } static bool tegra_hwpm_addr_in_all_instances(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, - u64 find_addr, u32 *ip_idx, u32 *inst_idx, u32 *element_idx, + u64 find_addr, u32 *ip_idx, u32 *s_inst_idx, u32 *s_element_idx, enum tegra_hwpm_element_type *element_type, u32 a_type) { struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; struct hwpm_ip *chip_ip = active_chip->chip_ips[*ip_idx]; struct hwpm_ip_inst_per_aperture_info *inst_a_info = &chip_ip->inst_aperture_info[a_type]; + struct hwpm_ip_inst *ip_inst = NULL; + struct hwpm_ip_element_info *e_info = NULL; + bool found = false; u64 inst_offset = 0ULL; u32 idx = 0U; + u32 dyn_idx = 0U; tegra_hwpm_fn(hwpm, " "); - /* Find instance to which address belongs to */ - inst_offset = tegra_hwpm_safe_sub_u64( - find_addr, inst_a_info->range_start); - idx = tegra_hwpm_safe_cast_u64_to_u32( - inst_offset / inst_a_info->inst_stride); + if (inst_a_info->islots_overlimit) { + /* Use brute force approach to find instance index */ + for (idx = 0U; idx < chip_ip->num_instances; idx++) { + ip_inst = &chip_ip->ip_inst_static_array[idx]; + e_info = &ip_inst->element_info[a_type]; + if ((find_addr >= e_info->range_start) && + (find_addr <= e_info->range_end)) { + *s_inst_idx = idx; + /* Found element with given address */ + found = tegra_hwpm_addr_in_single_instance( + hwpm, iia_func, find_addr, ip_idx, + s_inst_idx, s_element_idx, + element_type, a_type); + if (found) { + return found; + } + } + } - /* Make sure instance index is valid */ - if (idx >= inst_a_info->inst_slots) { - tegra_hwpm_err(hwpm, "IP %d addr 0x%llx a_type %d: " - "inst_idx %d out of bounds", - *ip_idx, (unsigned long long)find_addr, a_type, idx); - return false; + /* Make sure instance index is valid */ + if (idx >= chip_ip->num_instances) { + tegra_hwpm_dbg(hwpm, hwpm_verbose, + "Addr 0x%llx not in IP %d a_type %d", + (unsigned long long)find_addr, *ip_idx, a_type); + return false; + } + } else { + /* Find instance to which address belongs to */ + inst_offset = tegra_hwpm_safe_sub_u64( + find_addr, inst_a_info->range_start); + dyn_idx = tegra_hwpm_safe_cast_u64_to_u32( + inst_offset / inst_a_info->inst_stride); + + /* Make sure instance index is valid */ + if (dyn_idx >= inst_a_info->inst_slots) { + tegra_hwpm_dbg(hwpm, hwpm_verbose, + "IP %d addr 0x%llx a_type %d: " + "dynamic inst_idx %d out of bounds", + *ip_idx, (unsigned long long)find_addr, + a_type, dyn_idx); + return false; + } + + /* Convert dynamic inst index to static inst index */ + ip_inst = inst_a_info->inst_arr[dyn_idx]; + idx = tegra_hwpm_ffs(hwpm, ip_inst->hw_inst_mask); + tegra_hwpm_dbg(hwpm, hwpm_dbg_ip_register, + "IP %d find_addr 0x%llx inst dyn_idx %u static idx %u", + *ip_idx, find_addr, dyn_idx, idx); + + *s_inst_idx = idx; + + /* Process further and return */ + return tegra_hwpm_addr_in_single_instance(hwpm, iia_func, + find_addr, ip_idx, s_inst_idx, s_element_idx, + element_type, a_type); } - *inst_idx = idx; - - /* Process further and return */ - return tegra_hwpm_addr_in_single_instance(hwpm, iia_func, - find_addr, ip_idx, inst_idx, element_idx, - element_type, a_type); + /* Execution shouldn't reach here */ + tegra_hwpm_err(hwpm, "Execution shouldn't reach here"); + return false; } static bool tegra_hwpm_addr_in_single_ip(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, - u64 find_addr, u32 *ip_idx, u32 *inst_idx, u32 *element_idx, + u64 find_addr, u32 *ip_idx, u32 *s_inst_idx, u32 *s_element_idx, enum tegra_hwpm_element_type *element_type) { struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; @@ -515,7 +619,8 @@ static bool tegra_hwpm_addr_in_single_ip(struct tegra_soc_hwpm *hwpm, tegra_hwpm_fn(hwpm, " "); if (chip_ip == NULL) { - tegra_hwpm_err(hwpm, "IP %d not populated as expected", *ip_idx); + tegra_hwpm_err(hwpm, + "IP %d not populated as expected", *ip_idx); return false; } @@ -549,6 +654,7 @@ static bool tegra_hwpm_addr_in_single_ip(struct tegra_soc_hwpm *hwpm, if ((find_addr < inst_a_info->range_start) || (find_addr > inst_a_info->range_end)) { + /* Address not in this IP for this a_type */ tegra_hwpm_dbg(hwpm, hwpm_verbose, "IP %d addr 0x%llx not in a_type %d elements", @@ -558,7 +664,7 @@ static bool tegra_hwpm_addr_in_single_ip(struct tegra_soc_hwpm *hwpm, /* Process further and return */ found = tegra_hwpm_addr_in_all_instances(hwpm, iia_func, - find_addr, ip_idx, inst_idx, element_idx, + find_addr, ip_idx, s_inst_idx, s_element_idx, element_type, a_type); if (found) { break; @@ -576,7 +682,7 @@ static bool tegra_hwpm_addr_in_single_ip(struct tegra_soc_hwpm *hwpm, static bool tegra_hwpm_addr_in_all_ip(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, - u64 find_addr, u32 *ip_idx, u32 *inst_idx, u32 *element_idx, + u64 find_addr, u32 *ip_idx, u32 *s_inst_idx, u32 *s_element_idx, enum tegra_hwpm_element_type *element_type) { u32 idx; @@ -601,7 +707,7 @@ static bool tegra_hwpm_addr_in_all_ip(struct tegra_soc_hwpm *hwpm, } found = tegra_hwpm_addr_in_single_ip(hwpm, iia_func, find_addr, - &idx, inst_idx, element_idx, element_type); + &idx, s_inst_idx, s_element_idx, element_type); if (found) { *ip_idx = idx; return true; @@ -613,15 +719,15 @@ static bool tegra_hwpm_addr_in_all_ip(struct tegra_soc_hwpm *hwpm, bool tegra_hwpm_aperture_for_address(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, - u64 find_addr, u32 *ip_idx, u32 *inst_idx, u32 *element_idx, + u64 find_addr, u32 *ip_idx, u32 *s_inst_idx, u32 *s_element_idx, enum tegra_hwpm_element_type *element_type) { bool found = false; tegra_hwpm_fn(hwpm, " "); - if ((ip_idx == NULL) || (inst_idx == NULL) || - (element_idx == NULL) || (element_type == NULL)) { + if ((ip_idx == NULL) || (s_inst_idx == NULL) || + (s_element_idx == NULL) || (element_type == NULL)) { tegra_hwpm_err(hwpm, "NULL index pointer"); return false; } @@ -629,7 +735,7 @@ bool tegra_hwpm_aperture_for_address(struct tegra_soc_hwpm *hwpm, if (iia_func == TEGRA_HWPM_FIND_GIVEN_ADDRESS) { /* IP index is not known, search in all IPs */ found = tegra_hwpm_addr_in_all_ip(hwpm, iia_func, find_addr, - ip_idx, inst_idx, element_idx, element_type); + ip_idx, s_inst_idx, s_element_idx, element_type); if (!found) { tegra_hwpm_err(hwpm, "Address 0x%llx not in any IP", @@ -640,7 +746,7 @@ bool tegra_hwpm_aperture_for_address(struct tegra_soc_hwpm *hwpm, if (iia_func == TEGRA_HWPM_MATCH_BASE_ADDRESS) { found = tegra_hwpm_addr_in_single_ip(hwpm, iia_func, find_addr, - ip_idx, inst_idx, element_idx, element_type); + ip_idx, s_inst_idx, s_element_idx, element_type); if (!found) { tegra_hwpm_err(hwpm, "Address 0x%llx not in IP %d", (unsigned long long)find_addr, *ip_idx); diff --git a/drivers/tegra/hwpm/common/resource.c b/drivers/tegra/hwpm/common/resource.c index a092cb0..a6e8c9d 100644 --- a/drivers/tegra/hwpm/common/resource.c +++ b/drivers/tegra/hwpm/common/resource.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT /* - * SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -79,7 +79,7 @@ int tegra_hwpm_reserve_resource(struct tegra_soc_hwpm *hwpm, u32 resource) tegra_hwpm_fn(hwpm, " "); - tegra_hwpm_dbg(hwpm, hwpm_info, + tegra_hwpm_dbg(hwpm, hwpm_info | hwpm_dbg_reserve_resource, "User requesting to reserve resource %d", resource); /* Translate resource to ip_idx */ diff --git a/drivers/tegra/hwpm/hal/t234/t234_ip.c b/drivers/tegra/hwpm/hal/t234/t234_ip.c index 8a66190..9e13c5c 100644 --- a/drivers/tegra/hwpm/hal/t234/t234_ip.c +++ b/drivers/tegra/hwpm/hal/t234/t234_ip.c @@ -206,7 +206,7 @@ static int t234_hwpm_validate_emc_config(struct tegra_soc_hwpm *hwpm) defined(CONFIG_T234_HWPM_IP_MSS_MCF) struct hwpm_ip *chip_ip = NULL; struct hwpm_ip_inst *ip_inst = NULL; - u32 inst_idx = 0U; + u32 s_inst_idx = 0U; u32 element_mask_max = 0U; #endif u32 emc_disable_fuse_val = 0U; @@ -260,10 +260,11 @@ static int t234_hwpm_validate_emc_config(struct tegra_soc_hwpm *hwpm) defined(CONFIG_T234_HWPM_IP_MSS_ISO_NISO_HUBS) || \ defined(CONFIG_T234_HWPM_IP_MSS_MCF) chip_ip = active_chip->chip_ips[idx]; - for (inst_idx = 0U; inst_idx < chip_ip->num_instances; - inst_idx++) { + for (s_inst_idx = 0U; + s_inst_idx < chip_ip->num_instances; + s_inst_idx++) { ip_inst = &chip_ip->ip_inst_static_array[ - inst_idx]; + s_inst_idx]; /* * Hence use max element mask to get correct diff --git a/drivers/tegra/hwpm/hal/th500/th500_ip.c b/drivers/tegra/hwpm/hal/th500/th500_ip.c index 87d7395..3903f10 100644 --- a/drivers/tegra/hwpm/hal/th500/th500_ip.c +++ b/drivers/tegra/hwpm/hal/th500/th500_ip.c @@ -351,7 +351,7 @@ static int th500_hwpm_validate_emc_config(struct tegra_soc_hwpm *hwpm) struct hwpm_ip *chip_ip = NULL; struct hwpm_ip_inst *ip_inst = NULL; u32 element_mask_max = 0U; - u32 inst_idx = 0U; + u32 s_inst_idx = 0U; #endif u32 emc_disable_fuse_val = 0U; u32 emc_disable_fuse_val_mask = 0xFU; @@ -396,10 +396,11 @@ static int th500_hwpm_validate_emc_config(struct tegra_soc_hwpm *hwpm) #endif # if defined(CONFIG_TH500_HWPM_IP_MSS_CHANNEL) chip_ip = active_chip->chip_ips[idx]; - for (inst_idx = 0U; inst_idx < chip_ip->num_instances; - inst_idx++) { + for (s_inst_idx = 0U; + s_inst_idx < chip_ip->num_instances; + s_inst_idx++) { ip_inst = &chip_ip->ip_inst_static_array[ - inst_idx]; + s_inst_idx]; /* * Hence use max element mask to get correct diff --git a/drivers/tegra/hwpm/include/tegra_hwpm.h b/drivers/tegra/hwpm/include/tegra_hwpm.h index f8d7611..6b7fd20 100644 --- a/drivers/tegra/hwpm/include/tegra_hwpm.h +++ b/drivers/tegra/hwpm/include/tegra_hwpm.h @@ -45,6 +45,9 @@ #define TEGRA_HWPM_IP_DEBUG_FD_INVALID -1 #define TEGRA_HWPM_IP_DEBUG_FD_VALID 1U +/* Indicate max dynamic aperture slots accepted for binary search */ +#define TEGRA_HWPM_APERTURE_SLOTS_LIMIT 64U + #ifdef __KERNEL__ struct tegra_hwpm_os_linux; #else @@ -246,9 +249,16 @@ struct hwpm_ip_aperture { */ enum tegra_hwpm_element_type element_type; + /* + * Index of the aperture within the instance. + * Static structure for this element can be retrieved using this index. + */ + u32 aperture_index; + /* * Element index : Index of this aperture within the instance * This will be used to update element_fs_mask to indicate availability. + * This mask also indicates corresponding core element. */ u32 element_index_mask; @@ -339,6 +349,17 @@ struct hwpm_ip_element_info { */ u32 element_slots; + /* + * Flag that indicates if number of slots computed is over limit + * If yes, usually, number of valid static slots will be small as + * compared to computed dynamic slots. That means allocating huge + * memory to store NULL pointers equal to computed element slots + * will fail and/or be impractical. Hence, if this flag is set, + * driver logic should fallback to brute force approach to match + * regops address. + */ + bool eslots_overlimit; + /* * Dynamic elements array corresponding to this element * Array size: element_slots pointers @@ -414,6 +435,17 @@ struct hwpm_ip_inst_per_aperture_info { */ u32 inst_slots; + /* + * Flag that indicates if number of slots computed is over limit + * If yes, usually, number of valid static slots will be small as + * compared to computed dynamic slots. That means allocating huge + * memory to store NULL pointers equal to computed insyance slots + * will fail and/or be impractical. Hence, if this flag is set, + * driver logic should fallback to brute force approach to match + * regops address. + */ + bool islots_overlimit; + /* IP inst aperture array */ struct hwpm_ip_inst **inst_arr; }; diff --git a/drivers/tegra/hwpm/include/tegra_hwpm_aperture.h b/drivers/tegra/hwpm/include/tegra_hwpm_aperture.h index a9314d6..1a9f522 100644 --- a/drivers/tegra/hwpm/include/tegra_hwpm_aperture.h +++ b/drivers/tegra/hwpm/include/tegra_hwpm_aperture.h @@ -1,6 +1,6 @@ -/* SPDX-License-Identifier: MIT */ /* - * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,6 +30,9 @@ #include #endif +#define tegra_hwpm_ffs(hwpm, number) \ + tegra_hwpm_ffs_impl(hwpm, number) + #define tegra_hwpm_perfmon_reserve(hwpm, ip_inst, perfmon) \ tegra_hwpm_perfmon_reserve_impl(hwpm, ip_inst, perfmon) #define tegra_hwpm_perfmux_reserve(hwpm, ip_inst, perfmux) \ diff --git a/drivers/tegra/hwpm/include/tegra_hwpm_common.h b/drivers/tegra/hwpm/include/tegra_hwpm_common.h index 5379f7b..c6d6d0a 100644 --- a/drivers/tegra/hwpm/include/tegra_hwpm_common.h +++ b/drivers/tegra/hwpm/include/tegra_hwpm_common.h @@ -1,6 +1,6 @@ -/* SPDX-License-Identifier: MIT */ /* - * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -48,7 +48,7 @@ int tegra_hwpm_func_single_ip(struct tegra_soc_hwpm *hwpm, bool tegra_hwpm_aperture_for_address(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_funcs iia_func, - u64 find_addr, u32 *ip_idx, u32 *inst_idx, u32 *element_idx, + u64 find_addr, u32 *ip_idx, u32 *s_inst_idx, u32 *s_element_idx, enum tegra_hwpm_element_type *element_type); int tegra_hwpm_perfmux_disable(struct tegra_soc_hwpm *hwpm, @@ -90,6 +90,6 @@ int tegra_hwpm_check_status(struct tegra_soc_hwpm *hwpm); int tegra_hwpm_release_hw(struct tegra_soc_hwpm *hwpm); void tegra_hwpm_release_sw_setup(struct tegra_soc_hwpm *hwpm); int tegra_hwpm_update_ip_inst_fs_mask(struct tegra_soc_hwpm *hwpm, - u32 ip_idx, u32 a_type, u32 inst_idx, bool available); + u32 ip_idx, u32 a_type, u32 s_inst_idx, bool available); #endif /* TEGRA_HWPM_COMMON_H */ diff --git a/drivers/tegra/hwpm/os/linux/aperture_utils.c b/drivers/tegra/hwpm/os/linux/aperture_utils.c index 7d4f4f6..43da77f 100644 --- a/drivers/tegra/hwpm/os/linux/aperture_utils.c +++ b/drivers/tegra/hwpm/os/linux/aperture_utils.c @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: GPL-2.0-only * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -25,6 +26,15 @@ #include #include +u32 tegra_hwpm_ffs_impl(struct tegra_soc_hwpm *hwpm, u64 number) +{ + if (number == 0) { + return 0; + } + + return __ffs(number); +} + int tegra_hwpm_perfmon_reserve_impl(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst, struct hwpm_ip_aperture *perfmon) { diff --git a/drivers/tegra/hwpm/os/linux/aperture_utils.h b/drivers/tegra/hwpm/os/linux/aperture_utils.h index 1c63d6d..7fb9f8c 100644 --- a/drivers/tegra/hwpm/os/linux/aperture_utils.h +++ b/drivers/tegra/hwpm/os/linux/aperture_utils.h @@ -1,6 +1,6 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: GPL-2.0-only * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,8 @@ struct tegra_soc_hwpm; struct hwpm_ip_inst; struct hwpm_ip_aperture; +u32 tegra_hwpm_ffs_impl(struct tegra_soc_hwpm *hwpm, u64 number); + int tegra_hwpm_perfmon_reserve_impl(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst, struct hwpm_ip_aperture *perfmon); int tegra_hwpm_perfmux_reserve_impl(struct tegra_soc_hwpm *hwpm, diff --git a/drivers/tegra/hwpm/os/linux/regops_utils.c b/drivers/tegra/hwpm/os/linux/regops_utils.c index f6c4eab..8599ae4 100644 --- a/drivers/tegra/hwpm/os/linux/regops_utils.c +++ b/drivers/tegra/hwpm/os/linux/regops_utils.c @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: GPL-2.0-only * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -28,7 +28,7 @@ static int tegra_hwpm_exec_reg_ops(struct tegra_soc_hwpm *hwpm, { bool found = false; u32 ip_idx = TEGRA_HWPM_IP_INACTIVE; - u32 inst_idx = 0U, element_idx = 0U; + u32 s_inst_idx = 0U, s_element_idx = 0U; u32 a_type = 0U; u32 reg_val = 0U; u64 addr_hi = 0ULL; @@ -36,7 +36,6 @@ static int tegra_hwpm_exec_reg_ops(struct tegra_soc_hwpm *hwpm, enum tegra_hwpm_element_type element_type = HWPM_ELEMENT_INVALID; struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; struct hwpm_ip *chip_ip = NULL; - struct hwpm_ip_inst_per_aperture_info *inst_a_info = NULL; struct hwpm_ip_inst *ip_inst = NULL; struct hwpm_ip_element_info *e_info = NULL; struct hwpm_ip_aperture *element = NULL; @@ -46,7 +45,7 @@ static int tegra_hwpm_exec_reg_ops(struct tegra_soc_hwpm *hwpm, /* Find IP aperture containing phys_addr in allowlist */ found = tegra_hwpm_aperture_for_address(hwpm, TEGRA_HWPM_FIND_GIVEN_ADDRESS, reg_op->phys_addr, - &ip_idx, &inst_idx, &element_idx, &element_type); + &ip_idx, &s_inst_idx, &s_element_idx, &element_type); if (!found) { /* Silent failure as regops can continue on error */ tegra_hwpm_dbg(hwpm, hwpm_dbg_regops, @@ -57,8 +56,10 @@ static int tegra_hwpm_exec_reg_ops(struct tegra_soc_hwpm *hwpm, } tegra_hwpm_dbg(hwpm, hwpm_dbg_regops, - "Found addr 0x%llx IP %d inst_idx %d element_idx %d e_type %d", - reg_op->phys_addr, ip_idx, inst_idx, element_idx, element_type); + "Found addr 0x%llx IP %d s_inst_idx %d " + "s_element_idx %d e_type %d", + reg_op->phys_addr, ip_idx, s_inst_idx, + s_element_idx, element_type); switch (element_type) { case HWPM_ELEMENT_PERFMON: @@ -78,10 +79,9 @@ static int tegra_hwpm_exec_reg_ops(struct tegra_soc_hwpm *hwpm, } chip_ip = active_chip->chip_ips[ip_idx]; - inst_a_info = &chip_ip->inst_aperture_info[a_type]; - ip_inst = inst_a_info->inst_arr[inst_idx]; + ip_inst = &chip_ip->ip_inst_static_array[s_inst_idx]; e_info = &ip_inst->element_info[a_type]; - element = e_info->element_arr[element_idx]; + element = &e_info->element_static_array[s_element_idx]; switch (reg_op->cmd) { case TEGRA_SOC_HWPM_REG_OP_CMD_RD32: @@ -218,7 +218,6 @@ int tegra_hwpm_exec_regops(struct tegra_soc_hwpm *hwpm, ret = tegra_hwpm_exec_reg_ops(hwpm, reg_op); if (ret < 0) { - tegra_hwpm_err(hwpm, "exec_reg_ops %d failed", op_idx); exec_reg_ops->b_all_reg_ops_passed = false; if (exec_reg_ops->mode == TEGRA_SOC_HWPM_REG_OP_MODE_FAIL_ON_FIRST) {