From 48e85a9c07ee8f8ed0b427bb23b62d5151d36074 Mon Sep 17 00:00:00 2001 From: Vedashree Vidwans Date: Wed, 21 Aug 2024 10:31:11 -0700 Subject: [PATCH] tegra: hwpm: update logic to use static indexes HWPM driver uses nested structures and arrays of structures. The IP structure setup logic allocates pointer arrays based on dynamic list of IPs and aperture addresses. This dynamic list is required to search given regops address in less amount of time. However, there is a chance that the number of pointers computed dynamically is huge. And huge amount of memory will be required for the dynamic pointers array, which is impractical. This, this patch modifies ip structure setup and address to aperture conversion logic to use static indexes if the pointer array size is huge. This patch modifies relevant functions to always use static arrays to access instance and aperture structures. If dynamic pointers array is allocated, the patch adds logic to translate dynamic index to static index using inst_index_mask for instances and new added aperture_index for element level structures. Add/update few log message to improve relayed information. Bug 4707244 Change-Id: Ib4847e6575f82b628a3ce838ad69196a4bc08fed Signed-off-by: Vedashree Vidwans Reviewed-on: https://git-master.nvidia.com/r/c/linux-hwpm/+/3186843 Reviewed-by: Vasuki Shankar Reviewed-by: Seema Khowala GVS: buildbot_gerritrpt --- drivers/tegra/hwpm/common/aperture.c | 138 +++++--- drivers/tegra/hwpm/common/ip.c | 320 ++++++++++++------ drivers/tegra/hwpm/common/resource.c | 4 +- drivers/tegra/hwpm/hal/t234/t234_ip.c | 9 +- drivers/tegra/hwpm/hal/th500/th500_ip.c | 9 +- drivers/tegra/hwpm/include/tegra_hwpm.h | 32 ++ .../tegra/hwpm/include/tegra_hwpm_aperture.h | 7 +- .../tegra/hwpm/include/tegra_hwpm_common.h | 8 +- drivers/tegra/hwpm/os/linux/aperture_utils.c | 14 +- drivers/tegra/hwpm/os/linux/aperture_utils.h | 6 +- drivers/tegra/hwpm/os/linux/regops_utils.c | 21 +- 11 files changed, 383 insertions(+), 185 deletions(-) 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) {