tegra: soc_hwpm: t234: move chip specific files

Move chip specific code to chip specific folder. This will allow
multiple chip support in the future.
Create new specific functions
- Initialize hwpm structures
- Reserve and release PMA and RTR apertures
- Zero, update and check allowlists
- Set and get fake registers for MC aperture on simulation
- perfmon dt aperture enums

Jira THWPM-41

Change-Id: Ib80f324283c8d29b5c6f7bb6345a6df2410954e6
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2620234
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: Seema Khowala <seemaj@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Vedashree Vidwans
2021-11-04 13:26:17 -07:00
committed by mobile promotions
parent 1dd2527129
commit 3edf3f6034
23 changed files with 4137 additions and 3224 deletions

View File

@@ -4,13 +4,16 @@
GCOV_PROFILE := y
ccflags-y += -I$(srctree.nvidia)/drivers/platform/tegra/hwpm/include/regops/t234
ccflags-y += -I$(srctree.nvidia)/drivers/platform/tegra/hwpm/include/hw/t234
ccflags-y += -I$(srctree.nvidia)/drivers/platform/tegra/hwpm
ccflags-y += -I$(srctree.nvidia)/include
obj-y += tegra-soc-hwpm.o
obj-y += tegra-soc-hwpm-io.o
obj-y += tegra-soc-hwpm-ioctl.o
obj-y += tegra-soc-hwpm-log.o
obj-y += tegra-soc-hwpm-ip.o
obj-y += hal/tegra_soc_hwpm_init.o
obj-y += hal/t234/t234_soc_hwpm_init.o
obj-y += hal/t234/t234_soc_hwpm_mem_buf_utils.o
obj-y += hal/t234/t234_soc_hwpm_resource_utils.o
obj-$(CONFIG_DEBUG_FS) += tegra-soc-hwpm-debugfs.o

View File

@@ -53,8 +53,8 @@
* comparison with unshifted values appropriate for use in field <y>
* of register <x>.
*/
#ifndef TEGRA_HW_ADDR_MAP_SOC_HWPM_H
#define TEGRA_HW_ADDR_MAP_SOC_HWPM_H
#ifndef T234_ADDR_MAP_SOC_HWPM_H
#define T234_ADDR_MAP_SOC_HWPM_H
#define addr_map_rpg_pm_base_r() (0x0f100000U)
#define addr_map_rpg_pm_limit_r() (0x0f149fffU)

View File

@@ -53,8 +53,8 @@
* comparison with unshifted values appropriate for use in field <y>
* of register <x>.
*/
#ifndef TEGRA_HW_PMASYS_SOC_HWPM_H
#define TEGRA_HW_PMASYS_SOC_HWPM_H
#ifndef T234_PMASYS_SOC_HWPM_H
#define T234_PMASYS_SOC_HWPM_H
#define pmasys_cg2_r() (0x0f14a044U)
#define pmasys_cg2_slcg_f(v) (((v) & 0x1U) << 0U)

View File

@@ -53,8 +53,8 @@
* comparison with unshifted values appropriate for use in field <y>
* of register <x>.
*/
#ifndef TEGRA_HW_PMMSYS_SOC_HWPM_H
#define TEGRA_HW_PMMSYS_SOC_HWPM_H
#ifndef T234_PMMSYS_SOC_HWPM_H
#define T234_PMMSYS_SOC_HWPM_H
#define pmmsys_perdomain_offset_v() (0x00001000U)
#define pmmsys_control_r(i)\

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef T234_SOC_HWPM_INIT_H
#define T234_SOC_HWPM_INIT_H
#include <hal/tegra-soc-hwpm-structures.h>
void __iomem **t234_soc_hwpm_init_dt_apertures(void);
struct tegra_soc_hwpm_ip_ops *t234_soc_hwpm_init_ip_ops_info(void);
bool t234_soc_hwpm_is_perfmon(u32 dt_aperture);
u64 t234_soc_hwpm_get_perfmon_base(u32 dt_aperture);
bool t234_soc_hwpm_is_dt_aperture(u32 dt_aperture);
u32 t234_soc_hwpm_get_ip_aperture(struct tegra_soc_hwpm *hwpm,
u64 phys_address, u64 *ip_base_addr);
int t234_soc_hwpm_fs_info_init(struct tegra_soc_hwpm *hwpm);
int t234_soc_hwpm_disable_pma_triggers(struct tegra_soc_hwpm *hwpm);
u32 **t234_soc_hwpm_get_mc_fake_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture);
void t234_soc_hwpm_set_mc_fake_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture,
bool set_null);
int t234_soc_hwpm_pma_rtr_map(struct tegra_soc_hwpm *hwpm);
int t234_soc_hwpm_pma_rtr_unmap(struct tegra_soc_hwpm *hwpm);
int t234_soc_hwpm_disable_slcg(struct tegra_soc_hwpm *hwpm);
int t234_soc_hwpm_enable_slcg(struct tegra_soc_hwpm *hwpm);
struct hwpm_resource_aperture *t234_soc_hwpm_find_aperture(
struct tegra_soc_hwpm *hwpm, u64 phys_addr,
bool use_absolute_base, bool check_reservation,
u64 *updated_pa);
void t234_soc_hwpm_zero_alist_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture);
int t234_soc_hwpm_update_allowlist(struct tegra_soc_hwpm *hwpm,
void *ioctl_struct);
bool t234_soc_hwpm_allowlist_check(struct hwpm_resource_aperture *aperture,
u64 phys_addr, bool use_absolute_base,
u64 *updated_pa);
void t234_soc_hwpm_get_full_allowlist(struct tegra_soc_hwpm *hwpm);
int t234_soc_hwpm_update_mem_bytes(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_update_get_put *update_get_put);
int t234_soc_hwpm_clear_pipeline(struct tegra_soc_hwpm *hwpm);
int t234_soc_hwpm_stream_buf_map(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_alloc_pma_stream *alloc_pma_stream);
bool t234_soc_hwpm_is_dt_aperture_reserved(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture, u32 rsrc_id);
int t234_soc_hwpm_reserve_given_resource(
struct tegra_soc_hwpm *hwpm, u32 resource);
void t234_soc_hwpm_reset_resources(struct tegra_soc_hwpm *hwpm);
void t234_soc_hwpm_disable_perfmons(struct tegra_soc_hwpm *hwpm);
int t234_soc_hwpm_bind_resources(struct tegra_soc_hwpm *hwpm);
#endif /* T234_SOC_HWPM_INIT_H */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,343 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <soc/tegra/fuse.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/of_address.h>
#include <linux/dma-buf.h>
#include <tegra-soc-hwpm-log.h>
#include <tegra-soc-hwpm-io.h>
#include <hal/tegra-soc-hwpm-structures.h>
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
#include <hal/t234/t234_soc_hwpm_perfmon_dt.h>
#include <hal/t234/t234_soc_hwpm_init.h>
#include <hal/t234/hw/t234_addr_map_soc_hwpm.h>
int t234_soc_hwpm_update_mem_bytes(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_update_get_put *update_get_put)
{
u32 *mem_bytes_kernel_u32 = NULL;
u32 reg_val = 0U;
u32 field_val = 0U;
int ret;
/* Update SW get pointer */
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_mem_bump_r(0) - addr_map_pma_base_r(),
update_get_put->mem_bump);
/* Stream MEM_BYTES value to MEM_BYTES buffer */
if (update_get_put->b_stream_mem_bytes) {
mem_bytes_kernel_u32 = (u32 *)(hwpm->mem_bytes_kernel);
*mem_bytes_kernel_u32 = TEGRA_SOC_HWPM_MEM_BYTES_INVALID;
ret = reg_rmw(hwpm, NULL, T234_SOC_HWPM_PMA_DT,
pmasys_channel_control_user_r(0) - addr_map_pma_base_r(),
pmasys_channel_control_user_update_bytes_m(),
pmasys_channel_control_user_update_bytes_doit_f(),
false, false);
if (ret < 0) {
tegra_soc_hwpm_err("Failed to stream mem_bytes to buffer");
return -EIO;
}
}
/* Read HW put pointer */
if (update_get_put->b_read_mem_head) {
update_get_put->mem_head = hwpm_readl(hwpm,
T234_SOC_HWPM_PMA_DT,
pmasys_channel_mem_head_r(0) - addr_map_pma_base_r());
tegra_soc_hwpm_dbg("MEM_HEAD = 0x%llx",
update_get_put->mem_head);
}
/* Check overflow error status */
if (update_get_put->b_check_overflow) {
reg_val = hwpm_readl(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_status_secure_r(0) -
addr_map_pma_base_r());
field_val = pmasys_channel_status_secure_membuf_status_v(
reg_val);
update_get_put->b_overflowed = (field_val ==
pmasys_channel_status_secure_membuf_status_overflowed_v());
tegra_soc_hwpm_dbg("OVERFLOWED = %u",
update_get_put->b_overflowed);
}
return 0;
}
int t234_soc_hwpm_clear_pipeline(struct tegra_soc_hwpm *hwpm)
{
int err = 0;
int ret = 0;
bool timeout = false;
u32 *mem_bytes_kernel_u32 = NULL;
/* Stream MEM_BYTES to clear pipeline */
if (hwpm->mem_bytes_kernel) {
mem_bytes_kernel_u32 = (u32 *)(hwpm->mem_bytes_kernel);
*mem_bytes_kernel_u32 = TEGRA_SOC_HWPM_MEM_BYTES_INVALID;
err = reg_rmw(hwpm, NULL, T234_SOC_HWPM_PMA_DT,
pmasys_channel_control_user_r(0) - addr_map_pma_base_r(),
pmasys_channel_control_user_update_bytes_m(),
pmasys_channel_control_user_update_bytes_doit_f(),
false, false);
RELEASE_FAIL("Unable to stream MEM_BYTES");
timeout = HWPM_TIMEOUT(*mem_bytes_kernel_u32 !=
TEGRA_SOC_HWPM_MEM_BYTES_INVALID,
"MEM_BYTES streaming");
if (timeout && ret == 0)
ret = -EIO;
}
/* Disable PMA streaming */
err = reg_rmw(hwpm, NULL, T234_SOC_HWPM_PMA_DT,
pmasys_trigger_config_user_r(0) - addr_map_pma_base_r(),
pmasys_trigger_config_user_record_stream_m(),
pmasys_trigger_config_user_record_stream_disable_f(),
false, false);
RELEASE_FAIL("Unable to disable PMA streaming");
err = reg_rmw(hwpm, NULL, T234_SOC_HWPM_PMA_DT,
pmasys_channel_control_user_r(0) - addr_map_pma_base_r(),
pmasys_channel_control_user_stream_m(),
pmasys_channel_control_user_stream_disable_f(),
false, false);
RELEASE_FAIL("Unable to disable PMA streaming");
/* Memory Management */
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outbase_r(0) - addr_map_pma_base_r(), 0);
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outbaseupper_r(0) - addr_map_pma_base_r(), 0);
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outsize_r(0) - addr_map_pma_base_r(), 0);
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_mem_bytes_addr_r(0) - addr_map_pma_base_r(), 0);
if (hwpm->stream_sgt && (!IS_ERR(hwpm->stream_sgt))) {
dma_buf_unmap_attachment(hwpm->stream_attach,
hwpm->stream_sgt,
DMA_FROM_DEVICE);
}
hwpm->stream_sgt = NULL;
if (hwpm->stream_attach && (!IS_ERR(hwpm->stream_attach))) {
dma_buf_detach(hwpm->stream_dma_buf, hwpm->stream_attach);
}
hwpm->stream_attach = NULL;
if (hwpm->stream_dma_buf && (!IS_ERR(hwpm->stream_dma_buf))) {
dma_buf_put(hwpm->stream_dma_buf);
}
hwpm->stream_dma_buf = NULL;
if (hwpm->mem_bytes_kernel) {
dma_buf_vunmap(hwpm->mem_bytes_dma_buf,
hwpm->mem_bytes_kernel);
hwpm->mem_bytes_kernel = NULL;
}
if (hwpm->mem_bytes_sgt && (!IS_ERR(hwpm->mem_bytes_sgt))) {
dma_buf_unmap_attachment(hwpm->mem_bytes_attach,
hwpm->mem_bytes_sgt,
DMA_FROM_DEVICE);
}
hwpm->mem_bytes_sgt = NULL;
if (hwpm->mem_bytes_attach && (!IS_ERR(hwpm->mem_bytes_attach))) {
dma_buf_detach(hwpm->mem_bytes_dma_buf, hwpm->mem_bytes_attach);
}
hwpm->mem_bytes_attach = NULL;
if (hwpm->mem_bytes_dma_buf && (!IS_ERR(hwpm->mem_bytes_dma_buf))) {
dma_buf_put(hwpm->mem_bytes_dma_buf);
}
hwpm->mem_bytes_dma_buf = NULL;
return ret;
}
int t234_soc_hwpm_stream_buf_map(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_alloc_pma_stream *alloc_pma_stream)
{
int ret = 0;
u32 reg_val = 0;
u32 outbase_lo = 0;
u32 outbase_hi = 0;
u32 outsize = 0;
u32 mem_bytes_addr = 0;
/* Memory map stream buffer */
hwpm->stream_dma_buf = dma_buf_get(alloc_pma_stream->stream_buf_fd);
if (IS_ERR(hwpm->stream_dma_buf)) {
tegra_soc_hwpm_err("Unable to get stream dma_buf");
ret = PTR_ERR(hwpm->stream_dma_buf);
goto fail;
}
hwpm->stream_attach = dma_buf_attach(hwpm->stream_dma_buf, hwpm->dev);
if (IS_ERR(hwpm->stream_attach)) {
tegra_soc_hwpm_err("Unable to attach stream dma_buf");
ret = PTR_ERR(hwpm->stream_attach);
goto fail;
}
hwpm->stream_sgt = dma_buf_map_attachment(hwpm->stream_attach,
DMA_FROM_DEVICE);
if (IS_ERR(hwpm->stream_sgt)) {
tegra_soc_hwpm_err("Unable to map stream attachment");
ret = PTR_ERR(hwpm->stream_sgt);
goto fail;
}
alloc_pma_stream->stream_buf_pma_va =
sg_dma_address(hwpm->stream_sgt->sgl);
if (alloc_pma_stream->stream_buf_pma_va == 0) {
tegra_soc_hwpm_err("Invalid stream buffer SMMU IOVA");
ret = -ENXIO;
goto fail;
}
tegra_soc_hwpm_dbg("stream_buf_pma_va = 0x%llx",
alloc_pma_stream->stream_buf_pma_va);
/* Memory map mem bytes buffer */
hwpm->mem_bytes_dma_buf =
dma_buf_get(alloc_pma_stream->mem_bytes_buf_fd);
if (IS_ERR(hwpm->mem_bytes_dma_buf)) {
tegra_soc_hwpm_err("Unable to get mem bytes dma_buf");
ret = PTR_ERR(hwpm->mem_bytes_dma_buf);
goto fail;
}
hwpm->mem_bytes_attach = dma_buf_attach(hwpm->mem_bytes_dma_buf,
hwpm->dev);
if (IS_ERR(hwpm->mem_bytes_attach)) {
tegra_soc_hwpm_err("Unable to attach mem bytes dma_buf");
ret = PTR_ERR(hwpm->mem_bytes_attach);
goto fail;
}
hwpm->mem_bytes_sgt = dma_buf_map_attachment(hwpm->mem_bytes_attach,
DMA_FROM_DEVICE);
if (IS_ERR(hwpm->mem_bytes_sgt)) {
tegra_soc_hwpm_err("Unable to map mem bytes attachment");
ret = PTR_ERR(hwpm->mem_bytes_sgt);
goto fail;
}
hwpm->mem_bytes_kernel = dma_buf_vmap(hwpm->mem_bytes_dma_buf);
if (!hwpm->mem_bytes_kernel) {
tegra_soc_hwpm_err(
"Unable to map mem_bytes buffer into kernel VA space");
ret = -ENOMEM;
goto fail;
}
memset(hwpm->mem_bytes_kernel, 0, 32);
outbase_lo = alloc_pma_stream->stream_buf_pma_va &
pmasys_channel_outbase_ptr_m();
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outbase_r(0) - addr_map_pma_base_r(),
outbase_lo);
tegra_soc_hwpm_dbg("OUTBASE = 0x%x", reg_val);
outbase_hi = (alloc_pma_stream->stream_buf_pma_va >> 32) &
pmasys_channel_outbaseupper_ptr_m();
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outbaseupper_r(0) - addr_map_pma_base_r(),
outbase_hi);
tegra_soc_hwpm_dbg("OUTBASEUPPER = 0x%x", reg_val);
outsize = alloc_pma_stream->stream_buf_size &
pmasys_channel_outsize_numbytes_m();
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outsize_r(0) - addr_map_pma_base_r(),
outsize);
tegra_soc_hwpm_dbg("OUTSIZE = 0x%x", reg_val);
mem_bytes_addr = sg_dma_address(hwpm->mem_bytes_sgt->sgl) &
pmasys_channel_mem_bytes_addr_ptr_m();
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_mem_bytes_addr_r(0) - addr_map_pma_base_r(),
mem_bytes_addr);
tegra_soc_hwpm_dbg("MEM_BYTES_ADDR = 0x%x", reg_val);
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_mem_block_r(0) - addr_map_pma_base_r(),
pmasys_channel_mem_block_valid_f(
pmasys_channel_mem_block_valid_true_v()));
return 0;
fail:
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_mem_block_r(0) - addr_map_pma_base_r(),
pmasys_channel_mem_block_valid_f(
pmasys_channel_mem_block_valid_false_v()));
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outbase_r(0) - addr_map_pma_base_r(), 0);
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outbaseupper_r(0) - addr_map_pma_base_r(), 0);
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_outsize_r(0) - addr_map_pma_base_r(), 0);
hwpm_writel(hwpm, T234_SOC_HWPM_PMA_DT,
pmasys_channel_mem_bytes_addr_r(0) - addr_map_pma_base_r(), 0);
alloc_pma_stream->stream_buf_pma_va = 0;
if (hwpm->stream_sgt && (!IS_ERR(hwpm->stream_sgt))) {
dma_buf_unmap_attachment(hwpm->stream_attach,
hwpm->stream_sgt,
DMA_FROM_DEVICE);
}
hwpm->stream_sgt = NULL;
if (hwpm->stream_attach && (!IS_ERR(hwpm->stream_attach))) {
dma_buf_detach(hwpm->stream_dma_buf, hwpm->stream_attach);
}
hwpm->stream_attach = NULL;
if (hwpm->stream_dma_buf && (!IS_ERR(hwpm->stream_dma_buf))) {
dma_buf_put(hwpm->stream_dma_buf);
}
hwpm->stream_dma_buf = NULL;
if (hwpm->mem_bytes_kernel) {
dma_buf_vunmap(hwpm->mem_bytes_dma_buf,
hwpm->mem_bytes_kernel);
hwpm->mem_bytes_kernel = NULL;
}
if (hwpm->mem_bytes_sgt && (!IS_ERR(hwpm->mem_bytes_sgt))) {
dma_buf_unmap_attachment(hwpm->mem_bytes_attach,
hwpm->mem_bytes_sgt,
DMA_FROM_DEVICE);
}
hwpm->mem_bytes_sgt = NULL;
if (hwpm->mem_bytes_attach && (!IS_ERR(hwpm->mem_bytes_attach))) {
dma_buf_detach(hwpm->mem_bytes_dma_buf, hwpm->mem_bytes_attach);
}
hwpm->mem_bytes_attach = NULL;
if (hwpm->mem_bytes_dma_buf && (!IS_ERR(hwpm->mem_bytes_dma_buf))) {
dma_buf_put(hwpm->mem_bytes_dma_buf);
}
hwpm->mem_bytes_dma_buf = NULL;
return ret;
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This header contains HW aperture and register info for the Tegra SOC HWPM
* driver.
*/
#ifndef T234_SOC_HWPM_PERFMON_DT_H
#define T234_SOC_HWPM_PERFMON_DT_H
#include <linux/types.h>
#include <hal/t234/hw/t234_pmasys_soc_hwpm.h>
#include <hal/t234/hw/t234_pmmsys_soc_hwpm.h>
#include <hal/t234/hw/t234_addr_map_soc_hwpm.h>
enum t234_soc_hwpm_dt_aperture {
T234_SOC_HWPM_INVALID_DT = -1,
/* PERFMONs */
T234_SOC_HWPM_FIRST_PERFMON_DT = 0,
T234_SOC_HWPM_VI0_PERFMON_DT = T234_SOC_HWPM_FIRST_PERFMON_DT,
T234_SOC_HWPM_VI1_PERFMON_DT = T234_SOC_HWPM_FIRST_PERFMON_DT + 1,
T234_SOC_HWPM_ISP0_PERFMON_DT,
T234_SOC_HWPM_VICA0_PERFMON_DT,
T234_SOC_HWPM_OFAA0_PERFMON_DT,
T234_SOC_HWPM_PVAV0_PERFMON_DT,
T234_SOC_HWPM_PVAV1_PERFMON_DT,
T234_SOC_HWPM_PVAC0_PERFMON_DT,
T234_SOC_HWPM_NVDLAB0_PERFMON_DT,
T234_SOC_HWPM_NVDLAB1_PERFMON_DT,
T234_SOC_HWPM_NVDISPLAY0_PERFMON_DT,
T234_SOC_HWPM_SYS0_PERFMON_DT,
T234_SOC_HWPM_MGBE0_PERFMON_DT,
T234_SOC_HWPM_MGBE1_PERFMON_DT,
T234_SOC_HWPM_MGBE2_PERFMON_DT,
T234_SOC_HWPM_MGBE3_PERFMON_DT,
T234_SOC_HWPM_SCF0_PERFMON_DT,
T234_SOC_HWPM_NVDECA0_PERFMON_DT,
T234_SOC_HWPM_NVENCA0_PERFMON_DT,
T234_SOC_HWPM_MSSNVLHSH0_PERFMON_DT,
T234_SOC_HWPM_PCIE0_PERFMON_DT,
T234_SOC_HWPM_PCIE1_PERFMON_DT,
T234_SOC_HWPM_PCIE2_PERFMON_DT,
T234_SOC_HWPM_PCIE3_PERFMON_DT,
T234_SOC_HWPM_PCIE4_PERFMON_DT,
T234_SOC_HWPM_PCIE5_PERFMON_DT,
T234_SOC_HWPM_PCIE6_PERFMON_DT,
T234_SOC_HWPM_PCIE7_PERFMON_DT,
T234_SOC_HWPM_PCIE8_PERFMON_DT,
T234_SOC_HWPM_PCIE9_PERFMON_DT,
T234_SOC_HWPM_PCIE10_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTA0_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTA1_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTA2_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTA3_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTB0_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTB1_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTB2_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTB3_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTC0_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTC1_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTC2_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTC3_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTD0_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTD1_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTD2_PERFMON_DT,
T234_SOC_HWPM_MSSCHANNELPARTD3_PERFMON_DT,
T234_SOC_HWPM_MSSHUB0_PERFMON_DT,
T234_SOC_HWPM_MSSHUB1_PERFMON_DT,
T234_SOC_HWPM_MSSMCFCLIENT0_PERFMON_DT,
T234_SOC_HWPM_MSSMCFMEM0_PERFMON_DT,
T234_SOC_HWPM_MSSMCFMEM1_PERFMON_DT,
T234_SOC_HWPM_LAST_PERFMON_DT = T234_SOC_HWPM_MSSMCFMEM1_PERFMON_DT,
T234_SOC_HWPM_PMA_DT = T234_SOC_HWPM_LAST_PERFMON_DT + 1,
T234_SOC_HWPM_RTR_DT,
T234_SOC_HWPM_NUM_DT_APERTURES
};
#define IS_PERFMON(idx) (((idx) >= T234_SOC_HWPM_FIRST_PERFMON_DT) && \
((idx) <= T234_SOC_HWPM_LAST_PERFMON_DT))
/* RPG_PM Aperture */
#define PERFMON_BASE(ip_idx) (addr_map_rpg_pm_base_r() + \
((u32)(ip_idx)) * pmmsys_perdomain_offset_v())
#define PERFMON_LIMIT(ip_idx) (PERFMON_BASE((ip_idx) + 1) - 1)
#endif /* T234_SOC_HWPM_PERFMON_DT_H */

View File

@@ -22,15 +22,15 @@
* This file is autogenerated. Do not edit.
*/
#ifndef SOC_HWPM_REGOPS_ALLOWLIST_H
#define SOC_HWPM_REGOPS_ALLOWLIST_H
#ifndef T234_SOC_HWPM_REGOPS_ALLOWLIST_H
#define T234_SOC_HWPM_REGOPS_ALLOWLIST_H
struct allowlist {
u64 reg_offset;
bool zero_at_init;
};
struct allowlist perfmon_alist[] = {
struct allowlist t234_perfmon_alist[] = {
{0x00000000, true},
{0x00000004, true},
{0x00000008, true},
@@ -100,7 +100,7 @@ struct allowlist perfmon_alist[] = {
{0x00000130, true},
};
struct allowlist pma_res_cmd_slice_rtr_alist[] = {
struct allowlist t234_pma_res_cmd_slice_rtr_alist[] = {
{0x00000000, false},
{0x00000008, false},
{0x0000000c, false},
@@ -189,11 +189,11 @@ struct allowlist pma_res_cmd_slice_rtr_alist[] = {
{0x0000075c, false},
};
struct allowlist pma_res_pma_alist[] = {
struct allowlist t234_pma_res_pma_alist[] = {
{0x00000628, true},
};
struct allowlist rtr_alist[] = {
struct allowlist t234_rtr_alist[] = {
{0x00000000, false},
{0x00000008, false},
{0x0000000c, false},
@@ -204,7 +204,7 @@ struct allowlist rtr_alist[] = {
{0x00000154, false},
};
struct allowlist vi_thi_alist[] = {
struct allowlist t234_vi_thi_alist[] = {
{0x0000e800, false},
{0x0000e804, false},
{0x0000e808, true},
@@ -214,7 +214,7 @@ struct allowlist vi_thi_alist[] = {
{0x0000e818, true},
};
struct allowlist isp_thi_alist[] = {
struct allowlist t234_isp_thi_alist[] = {
{0x000091c0, false},
{0x000091c4, false},
{0x000091c8, true},
@@ -224,7 +224,7 @@ struct allowlist isp_thi_alist[] = {
{0x000091d8, true},
};
struct allowlist vic_alist[] = {
struct allowlist t234_vic_alist[] = {
{0x00001088, false},
{0x000010a8, false},
{0x00001c00, true},
@@ -236,7 +236,7 @@ struct allowlist vic_alist[] = {
{0x00001c18, false},
};
struct allowlist ofa_alist[] = {
struct allowlist t234_ofa_alist[] = {
{0x00001088, false},
{0x000010a8, false},
{0x00003308, true},
@@ -247,7 +247,7 @@ struct allowlist ofa_alist[] = {
{0x0000331c, false},
};
struct allowlist pva0_pm_alist[] = {
struct allowlist t234_pva0_pm_alist[] = {
{0x00008000, false},
{0x00008004, false},
{0x00008008, false},
@@ -259,7 +259,7 @@ struct allowlist pva0_pm_alist[] = {
{0x00008020, true},
};
struct allowlist nvdla_alist[] = {
struct allowlist t234_nvdla_alist[] = {
{0x00001088, false},
{0x000010a8, false},
{0x0001a000, false},
@@ -296,12 +296,12 @@ struct allowlist nvdla_alist[] = {
{0x0001a07c, true},
};
struct allowlist mgbe_alist[] = {
struct allowlist t234_mgbe_alist[] = {
{0x00008020, true},
{0x00008024, false},
};
struct allowlist nvdec_alist[] = {
struct allowlist t234_nvdec_alist[] = {
{0x00001088, false},
{0x000010a8, false},
{0x00001b48, false},
@@ -312,7 +312,7 @@ struct allowlist nvdec_alist[] = {
{0x00001b5c, true},
};
struct allowlist nvenc_alist[] = {
struct allowlist t234_nvenc_alist[] = {
{0x00001088, false},
{0x000010a8, false},
{0x00002134, true},
@@ -324,50 +324,50 @@ struct allowlist nvenc_alist[] = {
{0x00002130, false},
};
struct allowlist pcie_ctl_alist[] = {
struct allowlist t234_pcie_ctl_alist[] = {
{0x00000174, true},
{0x00000178, false},
};
struct allowlist disp_alist[] = {
struct allowlist t234_disp_alist[] = {
{0x0001e118, true},
{0x0001e120, true},
{0x0001e124, false},
};
struct allowlist mss_channel_alist[] = {
struct allowlist t234_mss_channel_alist[] = {
{0x00000814, true},
{0x0000082c, true},
};
struct allowlist mss_nvlink_alist[] = {
struct allowlist t234_mss_nvlink_alist[] = {
{0x00000a30, true},
};
struct allowlist mc0to7_res_mss_iso_niso_hub_alist[] = {
struct allowlist t234_mc0to7_res_mss_iso_niso_hub_alist[] = {
{0x00000818, true},
{0x0000081c, true},
};
struct allowlist mc8_res_mss_iso_niso_hub_alist[] = {
struct allowlist t234_mc8_res_mss_iso_niso_hub_alist[] = {
{0x00000828, true},
};
struct allowlist mcb_mss_mcf_alist[] = {
struct allowlist t234_mcb_mss_mcf_alist[] = {
{0x00000800, true},
{0x00000820, true},
{0x0000080c, true},
{0x00000824, true},
};
struct allowlist mc0to1_mss_mcf_alist[] = {
struct allowlist t234_mc0to1_mss_mcf_alist[] = {
{0x00000808, true},
{0x00000804, true},
{0x00000810, true},
};
struct allowlist mc2to7_mss_mcf_alist[] = {
struct allowlist t234_mc2to7_mss_mcf_alist[] = {
{0x00000810, true},
};
#endif /* SOC_HWPM_REGOPS_ALLOWLIST_H */
#endif /* T234_SOC_HWPM_REGOPS_ALLOWLIST_H */

View File

@@ -0,0 +1,531 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <soc/tegra/fuse.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/of_address.h>
#include <linux/dma-buf.h>
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
#include <tegra-soc-hwpm-log.h>
#include <tegra-soc-hwpm-io.h>
#include <hal/tegra-soc-hwpm-structures.h>
#include <hal/t234/t234_soc_hwpm_perfmon_dt.h>
#include <hal/t234/t234_soc_hwpm_init.h>
#include <hal/t234/hw/t234_addr_map_soc_hwpm.h>
/*
* Normally there is a 1-to-1 mapping between an MMIO aperture and a
* hwpm_resource_aperture struct. But MC MMIO apertures are used in multiple
* hwpm_resource_aperture structs. Therefore, we have to share the fake register
* arrays between these hwpm_resource_aperture structs. This is why we have to
* define the fake register arrays globally. For all other 1-to-1 mapping
* apertures the fake register arrays are directly embedded inside the
* hwpm_resource_aperture structs.
*/
u32 *t234_mc_fake_regs[16] = {NULL};
bool t234_soc_hwpm_is_dt_aperture_reserved(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture, u32 rsrc_id)
{
return ((aperture->dt_aperture == T234_SOC_HWPM_PMA_DT) ||
(aperture->dt_aperture == T234_SOC_HWPM_RTR_DT) ||
(aperture->dt_aperture == T234_SOC_HWPM_SYS0_PERFMON_DT) ||
((aperture->index_mask & hwpm->ip_fs_info[rsrc_id]) != 0));
}
u32 **t234_soc_hwpm_get_mc_fake_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture)
{
if (!hwpm->fake_registers_enabled)
return NULL;
if (!aperture) {
tegra_soc_hwpm_err("aperture is NULL");
return NULL;
}
switch (aperture->start_pa) {
case addr_map_mc0_base_r():
return &t234_mc_fake_regs[0];
case addr_map_mc1_base_r():
return &t234_mc_fake_regs[1];
case addr_map_mc2_base_r():
return &t234_mc_fake_regs[2];
case addr_map_mc3_base_r():
return &t234_mc_fake_regs[3];
case addr_map_mc4_base_r():
return &t234_mc_fake_regs[4];
case addr_map_mc5_base_r():
return &t234_mc_fake_regs[5];
case addr_map_mc6_base_r():
return &t234_mc_fake_regs[6];
case addr_map_mc7_base_r():
return &t234_mc_fake_regs[7];
case addr_map_mc8_base_r():
return &t234_mc_fake_regs[8];
case addr_map_mc9_base_r():
return &t234_mc_fake_regs[9];
case addr_map_mc10_base_r():
return &t234_mc_fake_regs[10];
case addr_map_mc11_base_r():
return &t234_mc_fake_regs[11];
case addr_map_mc12_base_r():
return &t234_mc_fake_regs[12];
case addr_map_mc13_base_r():
return &t234_mc_fake_regs[13];
case addr_map_mc14_base_r():
return &t234_mc_fake_regs[14];
case addr_map_mc15_base_r():
return &t234_mc_fake_regs[15];
default:
return NULL;
}
}
void t234_soc_hwpm_set_mc_fake_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture,
bool set_null)
{
u32 *fake_regs = NULL;
/* Get pointer to array of MSS channel apertures */
struct hwpm_resource_aperture *l_mss_channel_map =
hwpm->hwpm_resources[TEGRA_SOC_HWPM_RESOURCE_MSS_CHANNEL].map;
/* Get pointer to array of MSS ISO/NISO hub apertures */
struct hwpm_resource_aperture *l_mss_iso_niso_map =
hwpm->hwpm_resources[TEGRA_SOC_HWPM_RESOURCE_MSS_ISO_NISO_HUBS].map;
/* Get pointer to array of MSS MCF apertures */
struct hwpm_resource_aperture *l_mss_mcf_map =
hwpm->hwpm_resources[TEGRA_SOC_HWPM_RESOURCE_MSS_MCF].map;
if (!aperture) {
tegra_soc_hwpm_err("aperture is NULL");
return;
}
switch (aperture->start_pa) {
case addr_map_mc0_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[0];
l_mss_channel_map[0].fake_registers = fake_regs;
l_mss_iso_niso_map[0].fake_registers = fake_regs;
l_mss_mcf_map[0].fake_registers = fake_regs;
break;
case addr_map_mc1_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[1];
l_mss_channel_map[1].fake_registers = fake_regs;
l_mss_iso_niso_map[1].fake_registers = fake_regs;
l_mss_mcf_map[1].fake_registers = fake_regs;
break;
case addr_map_mc2_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[2];
l_mss_channel_map[2].fake_registers = fake_regs;
l_mss_iso_niso_map[2].fake_registers = fake_regs;
l_mss_mcf_map[2].fake_registers = fake_regs;
break;
case addr_map_mc3_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[3];
l_mss_channel_map[3].fake_registers = fake_regs;
l_mss_iso_niso_map[3].fake_registers = fake_regs;
l_mss_mcf_map[3].fake_registers = fake_regs;
break;
case addr_map_mc4_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[4];
l_mss_channel_map[4].fake_registers = fake_regs;
l_mss_iso_niso_map[4].fake_registers = fake_regs;
l_mss_mcf_map[4].fake_registers = fake_regs;
break;
case addr_map_mc5_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[5];
l_mss_channel_map[5].fake_registers = fake_regs;
l_mss_iso_niso_map[5].fake_registers = fake_regs;
l_mss_mcf_map[5].fake_registers = fake_regs;
break;
case addr_map_mc6_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[6];
l_mss_channel_map[6].fake_registers = fake_regs;
l_mss_iso_niso_map[6].fake_registers = fake_regs;
l_mss_mcf_map[6].fake_registers = fake_regs;
break;
case addr_map_mc7_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[7];
l_mss_channel_map[7].fake_registers = fake_regs;
l_mss_iso_niso_map[7].fake_registers = fake_regs;
l_mss_mcf_map[7].fake_registers = fake_regs;
break;
case addr_map_mc8_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[8];
l_mss_channel_map[8].fake_registers = fake_regs;
l_mss_iso_niso_map[8].fake_registers = fake_regs;
break;
case addr_map_mc9_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[9];
l_mss_channel_map[9].fake_registers = fake_regs;
break;
case addr_map_mc10_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[10];
l_mss_channel_map[10].fake_registers = fake_regs;
break;
case addr_map_mc11_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[11];
l_mss_channel_map[11].fake_registers = fake_regs;
break;
case addr_map_mc12_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[12];
l_mss_channel_map[12].fake_registers = fake_regs;
break;
case addr_map_mc13_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[13];
l_mss_channel_map[13].fake_registers = fake_regs;
break;
case addr_map_mc14_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[14];
l_mss_channel_map[14].fake_registers = fake_regs;
break;
case addr_map_mc15_base_r():
fake_regs = (!hwpm->fake_registers_enabled || set_null) ?
NULL : t234_mc_fake_regs[15];
l_mss_channel_map[15].fake_registers = fake_regs;
break;
default:
break;
}
}
int t234_soc_hwpm_reserve_given_resource(struct tegra_soc_hwpm *hwpm, u32 resource)
{
struct hwpm_resource_aperture *aperture = NULL;
int aprt_idx = 0;
int ret = 0, err;
struct tegra_soc_hwpm_ip_ops *ip_ops;
/* Map reserved apertures and allocate fake register arrays if needed */
for (aprt_idx = 0;
aprt_idx < hwpm->hwpm_resources[resource].map_size;
aprt_idx++) {
aperture = &(hwpm->hwpm_resources[resource].map[aprt_idx]);
if ((aperture->dt_aperture == T234_SOC_HWPM_PMA_DT) ||
(aperture->dt_aperture == T234_SOC_HWPM_RTR_DT)) {
/* PMA and RTR apertures are handled in open(fd) */
continue;
} else if (t234_soc_hwpm_is_dt_aperture_reserved(hwpm,
aperture, resource)) {
if (t234_soc_hwpm_is_perfmon(aperture->dt_aperture)) {
struct resource *res = NULL;
u64 num_regs = 0;
tegra_soc_hwpm_dbg("Found PERFMON(0x%llx - 0x%llx)",
aperture->start_pa, aperture->end_pa);
ip_ops = &hwpm->ip_info[aperture->dt_aperture];
if (ip_ops && (*ip_ops->hwpm_ip_pm)) {
err = (*ip_ops->hwpm_ip_pm)
(ip_ops->ip_dev, true);
if (err) {
tegra_soc_hwpm_err(
"Disable Runtime PM(%d) Failed",
aperture->dt_aperture);
}
} else {
tegra_soc_hwpm_dbg(
"No Runtime PM(%d) for IP",
aperture->dt_aperture);
}
hwpm->dt_apertures[aperture->dt_aperture] =
of_iomap(hwpm->np, aperture->dt_aperture);
if (!hwpm->dt_apertures[aperture->dt_aperture]) {
tegra_soc_hwpm_err("Couldn't map PERFMON(%d)",
aperture->dt_aperture);
ret = -ENOMEM;
goto fail;
}
res = platform_get_resource(hwpm->pdev,
IORESOURCE_MEM,
aperture->dt_aperture);
if ((!res) || (res->start == 0) || (res->end == 0)) {
tegra_soc_hwpm_err("Invalid resource for PERFMON(%d)",
aperture->dt_aperture);
ret = -ENOMEM;
goto fail;
}
aperture->start_pa = res->start;
aperture->end_pa = res->end;
if (hwpm->fake_registers_enabled) {
num_regs = (aperture->end_pa + 1 - aperture->start_pa) /
sizeof(*aperture->fake_registers);
aperture->fake_registers =
(u32 *)kzalloc(sizeof(*aperture->fake_registers) *
num_regs,
GFP_KERNEL);
if (!aperture->fake_registers) {
tegra_soc_hwpm_err("Aperture(0x%llx - 0x%llx):"
" Couldn't allocate memory for fake"
" registers",
aperture->start_pa,
aperture->end_pa);
ret = -ENOMEM;
goto fail;
}
}
} else { /* IP apertures */
if (hwpm->fake_registers_enabled) {
u64 num_regs = 0;
u32 **fake_regs =
t234_soc_hwpm_get_mc_fake_regs(hwpm, aperture);
if (!fake_regs)
fake_regs = &aperture->fake_registers;
num_regs = (aperture->end_pa + 1 - aperture->start_pa) /
sizeof(*(*fake_regs));
*fake_regs =
(u32 *)kzalloc(sizeof(*(*fake_regs)) * num_regs,
GFP_KERNEL);
if (!(*fake_regs)) {
tegra_soc_hwpm_err("Aperture(0x%llx - 0x%llx):"
" Couldn't allocate memory for fake"
" registers",
aperture->start_pa,
aperture->end_pa);
ret = -ENOMEM;
goto fail;
}
t234_soc_hwpm_set_mc_fake_regs(hwpm, aperture, false);
}
}
} else {
tegra_soc_hwpm_dbg("resource %d index_mask %d not available",
resource, aperture->index_mask);
}
}
hwpm->hwpm_resources[resource].reserved = true;
goto success;
fail:
for (aprt_idx = 0;
aprt_idx < hwpm->hwpm_resources[resource].map_size;
aprt_idx++) {
aperture = &(hwpm->hwpm_resources[resource].map[aprt_idx]);
if ((aperture->dt_aperture == T234_SOC_HWPM_PMA_DT) ||
(aperture->dt_aperture == T234_SOC_HWPM_RTR_DT)) {
/* PMA and RTR apertures are handled in open(fd) */
continue;
} else if (t234_soc_hwpm_is_dt_aperture_reserved(hwpm,
aperture, resource)) {
if (t234_soc_hwpm_is_perfmon(aperture->dt_aperture)) {
if (hwpm->dt_apertures[aperture->dt_aperture]) {
iounmap(hwpm->dt_apertures[aperture->dt_aperture]);
hwpm->dt_apertures[aperture->dt_aperture] = NULL;
}
aperture->start_pa = 0;
aperture->end_pa = 0;
if (aperture->fake_registers) {
kfree(aperture->fake_registers);
aperture->fake_registers = NULL;
}
} else { /* IP apertures */
if (aperture->fake_registers) {
kfree(aperture->fake_registers);
aperture->fake_registers = NULL;
t234_soc_hwpm_set_mc_fake_regs(hwpm, aperture, true);
}
}
}
}
hwpm->hwpm_resources[resource].reserved = false;
success:
return ret;
}
void t234_soc_hwpm_reset_resources(struct tegra_soc_hwpm *hwpm)
{
int res_idx = 0;
int aprt_idx = 0;
struct hwpm_resource_aperture *aperture = NULL;
/* Reset resource and aperture state */
for (res_idx = 0; res_idx < TERGA_SOC_HWPM_NUM_RESOURCES; res_idx++) {
if (!hwpm->hwpm_resources[res_idx].reserved)
continue;
hwpm->hwpm_resources[res_idx].reserved = false;
for (aprt_idx = 0;
aprt_idx < hwpm->hwpm_resources[res_idx].map_size;
aprt_idx++) {
aperture = &(hwpm->hwpm_resources[res_idx].map[aprt_idx]);
if ((aperture->dt_aperture == T234_SOC_HWPM_PMA_DT) ||
(aperture->dt_aperture == T234_SOC_HWPM_RTR_DT)) {
/* PMA and RTR apertures are handled separately */
continue;
} else if (t234_soc_hwpm_is_perfmon(aperture->dt_aperture)) {
if (hwpm->dt_apertures[aperture->dt_aperture]) {
iounmap(hwpm->dt_apertures[aperture->dt_aperture]);
hwpm->dt_apertures[aperture->dt_aperture] = NULL;
}
aperture->start_pa = 0;
aperture->end_pa = 0;
if (aperture->fake_registers) {
kfree(aperture->fake_registers);
aperture->fake_registers = NULL;
}
} else { /* IP apertures */
if (aperture->fake_registers) {
kfree(aperture->fake_registers);
aperture->fake_registers = NULL;
t234_soc_hwpm_set_mc_fake_regs(hwpm, aperture, true);
}
}
}
}
}
void t234_soc_hwpm_disable_perfmons(struct tegra_soc_hwpm *hwpm)
{
int res_idx = 0;
int aprt_idx = 0;
struct hwpm_resource_aperture *aperture = NULL;
struct tegra_soc_hwpm_ip_ops *ip_ops;
int err, ret = 0;
for (res_idx = 0; res_idx < TERGA_SOC_HWPM_NUM_RESOURCES; res_idx++) {
if (!hwpm->hwpm_resources[res_idx].reserved)
continue;
tegra_soc_hwpm_dbg("Found reserved IP(%d)", res_idx);
for (aprt_idx = 0;
aprt_idx < hwpm->hwpm_resources[res_idx].map_size;
aprt_idx++) {
aperture = &(hwpm->hwpm_resources[res_idx].map[aprt_idx]);
if (t234_soc_hwpm_is_perfmon(aperture->dt_aperture)) {
if (t234_soc_hwpm_is_dt_aperture_reserved(hwpm,
aperture, res_idx)) {
tegra_soc_hwpm_dbg("Found PERFMON(0x%llx - 0x%llx)",
aperture->start_pa,
aperture->end_pa);
err = reg_rmw(hwpm, NULL, aperture->dt_aperture,
pmmsys_control_r(0) - addr_map_rpg_pm_base_r(),
pmmsys_control_mode_m(),
pmmsys_control_mode_disable_f(),
false, false);
RELEASE_FAIL("Unable to disable PERFMON(0x%llx - 0x%llx)",
aperture->start_pa,
aperture->end_pa);
ip_ops = &hwpm->ip_info[aperture->dt_aperture];
if (ip_ops && (*ip_ops->hwpm_ip_pm)) {
err = (*ip_ops->hwpm_ip_pm)
(ip_ops->ip_dev, false);
if (err) {
tegra_soc_hwpm_err(
"Enable Runtime PM(%d) Failed",
aperture->dt_aperture);
}
} else {
tegra_soc_hwpm_dbg(
"No Runtime PM(%d) for IP",
aperture->dt_aperture);
}
}
}
}
}
}
int t234_soc_hwpm_bind_resources(struct tegra_soc_hwpm *hwpm)
{
int ret = 0;
int res_idx = 0;
int aprt_idx = 0;
struct hwpm_resource_aperture *aperture = NULL;
for (res_idx = 0; res_idx < TERGA_SOC_HWPM_NUM_RESOURCES; res_idx++) {
if (!hwpm->hwpm_resources[res_idx].reserved)
continue;
tegra_soc_hwpm_dbg("Found reserved IP(%d)", res_idx);
for (aprt_idx = 0;
aprt_idx < hwpm->hwpm_resources[res_idx].map_size;
aprt_idx++) {
aperture = &(hwpm->hwpm_resources[res_idx].map[aprt_idx]);
if (t234_soc_hwpm_is_dt_aperture_reserved(hwpm,
aperture, res_idx)) {
/* Zero out necessary registers */
if (aperture->alist) {
t234_soc_hwpm_zero_alist_regs(hwpm, aperture);
} else {
tegra_soc_hwpm_err(
"NULL allowlist in aperture(0x%llx - 0x%llx)",
aperture->start_pa, aperture->end_pa);
}
/*
* Enable reporting of PERFMON status to
* NV_PERF_PMMSYS_SYS0ROUTER_PERFMONSTATUS_MERGED
*/
if (t234_soc_hwpm_is_perfmon(aperture->dt_aperture)) {
tegra_soc_hwpm_dbg("Found PERFMON(0x%llx - 0x%llx)",
aperture->start_pa,
aperture->end_pa);
ret = reg_rmw(hwpm, NULL, aperture->dt_aperture,
pmmsys_sys0_enginestatus_r(0) -
addr_map_rpg_pm_base_r(),
pmmsys_sys0_enginestatus_enable_m(),
pmmsys_sys0_enginestatus_enable_out_f(),
false, false);
if (ret < 0) {
tegra_soc_hwpm_err(
"Unable to set PMM ENGINESTATUS_ENABLE"
" for PERFMON(0x%llx - 0x%llx)",
aperture->start_pa,
aperture->end_pa);
return -EIO;
}
}
}
}
}
return 0;
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TEGRA_SOC_HWPM_STRUCTURES_H
#define TEGRA_SOC_HWPM_STRUCTURES_H
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
#define TEGRA_SOC_HWPM_DT_APERTURE_INVALID 100U
#define RELEASE_FAIL(msg, ...) \
do { \
if (err < 0) { \
tegra_soc_hwpm_err(msg, ##__VA_ARGS__); \
if (ret == 0) \
ret = err; \
} \
} while (0)
/* FIXME: Default timeout is 1 sec. Is this sufficient for pre-si? */
#define HWPM_TIMEOUT(timeout_check, expiry_msg) ({ \
bool timeout_expired = false; \
s32 timeout_msecs = 1000; \
u32 sleep_msecs = 100; \
while (!(timeout_check)) { \
msleep(sleep_msecs); \
timeout_msecs -= sleep_msecs; \
if (timeout_msecs <= 0) { \
tegra_soc_hwpm_err("Timeout expired for %s!", \
expiry_msg); \
timeout_expired = true; \
break; \
} \
} \
timeout_expired; \
})
struct allowlist;
extern struct platform_device *tegra_soc_hwpm_pdev;
extern const struct file_operations tegra_soc_hwpm_ops;
/* Driver struct */
struct tegra_soc_hwpm {
/* Device */
struct platform_device *pdev;
struct device *dev;
struct device_node *np;
struct class class;
dev_t dev_t;
struct cdev cdev;
struct hwpm_resource *hwpm_resources;
/* IP floorsweep info */
u64 ip_fs_info[TERGA_SOC_HWPM_NUM_IPS];
/* MMIO apertures in device tree */
void __iomem **dt_apertures;
/* Clocks and resets */
struct clk *la_clk;
struct clk *la_parent_clk;
struct reset_control *la_rst;
struct reset_control *hwpm_rst;
struct tegra_soc_hwpm_ip_ops *ip_info;
/* Memory Management */
struct dma_buf *stream_dma_buf;
struct dma_buf_attachment *stream_attach;
struct sg_table *stream_sgt;
struct dma_buf *mem_bytes_dma_buf;
struct dma_buf_attachment *mem_bytes_attach;
struct sg_table *mem_bytes_sgt;
void *mem_bytes_kernel;
/* SW State */
bool bind_completed;
s32 full_alist_size;
/* Debugging */
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
#endif
bool fake_registers_enabled;
};
struct hwpm_resource_aperture {
/*
* If false, this is a HWPM aperture (PERFRMON, PMA or RTR). Else this
* is a non-HWPM aperture (ex: VIC).
*/
bool is_ip;
/*
* If is_ip == false, specify dt_aperture for readl/writel operations.
* If is_ip == true, dt_aperture == TEGRA_SOC_HWPM_INVALID_DT.
*/
u32 dt_aperture;
/* Physical aperture */
u64 start_abs_pa;
u64 end_abs_pa;
u64 start_pa;
u64 end_pa;
/* Allowlist */
struct allowlist *alist;
u64 alist_size;
/*
* Currently, perfmons and perfmuxes for all instances of an IP
* are listed in a single aperture mask. It is possible that
* some instances are disable. In this case, accessing corresponding
* registers will result in kernel panic.
* Bit set in the index_mask value will indicate the instance index
* within that IP (or resource).
*/
u32 index_mask;
/* Fake registers for VDK which doesn't have a SOC HWPM fmodel */
u32 *fake_registers;
};
struct hwpm_resource {
bool reserved;
u32 map_size;
struct hwpm_resource_aperture *map;
};
#endif /* TEGRA_SOC_HWPM_STRUCTURES_H */

171
hal/tegra_soc_hwpm_init.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <tegra-soc-hwpm.h>
#include <hal/tegra_soc_hwpm_init.h>
#include <hal/t234/t234_soc_hwpm_init.h>
void __iomem **tegra_soc_hwpm_init_dt_apertures(void)
{
return t234_soc_hwpm_init_dt_apertures();
}
struct tegra_soc_hwpm_ip_ops *tegra_soc_hwpm_init_ip_ops_info(void)
{
return t234_soc_hwpm_init_ip_ops_info();
}
bool tegra_soc_hwpm_is_perfmon(u32 dt_aperture)
{
return t234_soc_hwpm_is_perfmon(dt_aperture);
}
u64 tegra_soc_hwpm_get_perfmon_base(u32 dt_aperture)
{
return t234_soc_hwpm_get_perfmon_base(dt_aperture);
}
bool tegra_soc_hwpm_is_dt_aperture(u32 dt_aperture)
{
return t234_soc_hwpm_is_dt_aperture(dt_aperture);
}
bool tegra_soc_hwpm_is_dt_aperture_reserved(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture, u32 rsrc_id)
{
return t234_soc_hwpm_is_dt_aperture_reserved(hwpm, aperture, rsrc_id);
}
u32 tegra_soc_hwpm_get_ip_aperture(struct tegra_soc_hwpm *hwpm,
u64 phys_address, u64 *ip_base_addr)
{
return t234_soc_hwpm_get_ip_aperture(hwpm, phys_address, ip_base_addr);
}
struct hwpm_resource_aperture *tegra_soc_hwpm_find_aperture(
struct tegra_soc_hwpm *hwpm, u64 phys_addr,
bool use_absolute_base, bool check_reservation,
u64 *updated_pa)
{
return t234_soc_hwpm_find_aperture(hwpm, phys_addr,
use_absolute_base, check_reservation, updated_pa);
}
int tegra_soc_hwpm_fs_info_init(struct tegra_soc_hwpm *hwpm)
{
return t234_soc_hwpm_fs_info_init(hwpm);
}
int tegra_soc_hwpm_disable_pma_triggers(struct tegra_soc_hwpm *hwpm)
{
return t234_soc_hwpm_disable_pma_triggers(hwpm);
}
u32 **tegra_soc_hwpm_get_mc_fake_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture)
{
return t234_soc_hwpm_get_mc_fake_regs(hwpm, aperture);
}
void tegra_soc_hwpm_set_mc_fake_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture,
bool set_null)
{
t234_soc_hwpm_set_mc_fake_regs(hwpm, aperture, set_null);
}
int tegra_soc_hwpm_disable_slcg(struct tegra_soc_hwpm *hwpm)
{
return t234_soc_hwpm_disable_slcg(hwpm);
}
int tegra_soc_hwpm_enable_slcg(struct tegra_soc_hwpm *hwpm)
{
return t234_soc_hwpm_enable_slcg(hwpm);
}
void tegra_soc_hwpm_zero_alist_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture)
{
t234_soc_hwpm_zero_alist_regs(hwpm, aperture);
}
int tegra_soc_hwpm_update_allowlist(struct tegra_soc_hwpm *hwpm,
void *ioctl_struct)
{
return t234_soc_hwpm_update_allowlist(hwpm, ioctl_struct);
}
bool tegra_soc_hwpm_allowlist_check(struct hwpm_resource_aperture *aperture,
u64 phys_addr, bool use_absolute_base,
u64 *updated_pa)
{
return t234_soc_hwpm_allowlist_check(aperture, phys_addr,
use_absolute_base, updated_pa);
}
void tegra_soc_hwpm_get_full_allowlist(struct tegra_soc_hwpm *hwpm)
{
t234_soc_hwpm_get_full_allowlist(hwpm);
}
int tegra_soc_hwpm_update_mem_bytes(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_update_get_put *update_get_put)
{
return t234_soc_hwpm_update_mem_bytes(hwpm, update_get_put);
}
int tegra_soc_hwpm_clear_pipeline(struct tegra_soc_hwpm *hwpm)
{
return t234_soc_hwpm_clear_pipeline(hwpm);
}
int tegra_soc_hwpm_stream_buf_map(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_alloc_pma_stream *alloc_pma_stream)
{
return t234_soc_hwpm_stream_buf_map(hwpm, alloc_pma_stream);
}
int tegra_soc_hwpm_pma_rtr_map(struct tegra_soc_hwpm *hwpm)
{
return t234_soc_hwpm_pma_rtr_map(hwpm);
}
int tegra_soc_hwpm_pma_rtr_unmap(struct tegra_soc_hwpm *hwpm)
{
return t234_soc_hwpm_pma_rtr_unmap(hwpm);
}
int tegra_soc_hwpm_reserve_given_resource(struct tegra_soc_hwpm *hwpm, u32 resource)
{
return t234_soc_hwpm_reserve_given_resource(hwpm, resource);
}
void tegra_soc_hwpm_reset_resources(struct tegra_soc_hwpm *hwpm)
{
t234_soc_hwpm_reset_resources(hwpm);
}
void tegra_soc_hwpm_disable_perfmons(struct tegra_soc_hwpm *hwpm)
{
t234_soc_hwpm_disable_perfmons(hwpm);
}
int tegra_soc_hwpm_bind_resources(struct tegra_soc_hwpm *hwpm)
{
return t234_soc_hwpm_bind_resources(hwpm);
}

68
hal/tegra_soc_hwpm_init.h Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This header contains interfaces to soc specific functions.
*/
#ifndef TEGRA_SOC_HWPM_INIT_H
#define TEGRA_SOC_HWPM_INIT_H
#include <hal/tegra-soc-hwpm-structures.h>
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
void __iomem **tegra_soc_hwpm_init_dt_apertures(void);
struct tegra_soc_hwpm_ip_ops *tegra_soc_hwpm_init_ip_ops_info(void);
bool tegra_soc_hwpm_is_perfmon(u32 dt_aperture);
u64 tegra_soc_hwpm_get_perfmon_base(u32 dt_aperture);
bool tegra_soc_hwpm_is_dt_aperture(u32 dt_aperture);
bool tegra_soc_hwpm_is_dt_aperture_reserved(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture, u32 rsrc_id);
u32 tegra_soc_hwpm_get_ip_aperture(struct tegra_soc_hwpm *hwpm,
u64 phys_address, u64 *ip_base_addr);
struct hwpm_resource_aperture *tegra_soc_hwpm_find_aperture(
struct tegra_soc_hwpm *hwpm, u64 phys_addr,
bool use_absolute_base, bool check_reservation,
u64 *updated_pa);
int tegra_soc_hwpm_fs_info_init(struct tegra_soc_hwpm *hwpm);
int tegra_soc_hwpm_disable_pma_triggers(struct tegra_soc_hwpm *hwpm);
u32 **tegra_soc_hwpm_get_mc_fake_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture);
void tegra_soc_hwpm_set_mc_fake_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture,
bool set_null);
int tegra_soc_hwpm_disable_slcg(struct tegra_soc_hwpm *hwpm);
int tegra_soc_hwpm_enable_slcg(struct tegra_soc_hwpm *hwpm);
void tegra_soc_hwpm_zero_alist_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture);
int tegra_soc_hwpm_update_allowlist(struct tegra_soc_hwpm *hwpm,
void *ioctl_struct);
bool tegra_soc_hwpm_allowlist_check(struct hwpm_resource_aperture *aperture,
u64 phys_addr, bool use_absolute_base,
u64 *updated_pa);
void tegra_soc_hwpm_get_full_allowlist(struct tegra_soc_hwpm *hwpm);
int tegra_soc_hwpm_update_mem_bytes(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_update_get_put *update_get_put);
int tegra_soc_hwpm_clear_pipeline(struct tegra_soc_hwpm *hwpm);
int tegra_soc_hwpm_stream_buf_map(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_alloc_pma_stream *alloc_pma_stream);
int tegra_soc_hwpm_pma_rtr_map(struct tegra_soc_hwpm *hwpm);
int tegra_soc_hwpm_pma_rtr_unmap(struct tegra_soc_hwpm *hwpm);
int tegra_soc_hwpm_reserve_given_resource(
struct tegra_soc_hwpm *hwpm, u32 resource);
void tegra_soc_hwpm_reset_resources(struct tegra_soc_hwpm *hwpm);
void tegra_soc_hwpm_disable_perfmons(struct tegra_soc_hwpm *hwpm);
int tegra_soc_hwpm_bind_resources(struct tegra_soc_hwpm *hwpm);
#endif /* TEGRA_SOC_HWPM_INIT_H */

View File

@@ -17,6 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <linux/debugfs.h>
#include <hal/tegra-soc-hwpm-structures.h>
#include "tegra-soc-hwpm-log.h"
#include "tegra-soc-hwpm.h"
/* FIXME: This is a placeholder for now. We can add debugfs nodes as needed. */

View File

@@ -1,106 +0,0 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* tegra-soc-hwpm-hw.h:
* This header contains HW aperture and register info for the Tegra SOC HWPM
* driver.
*/
#ifndef TEGRA_SOC_HWPM_HW_H
#define TEGRA_SOC_HWPM_HW_H
#include <linux/types.h>
#include "include/hw/t234/hw_addr_map_soc_hwpm.h"
#include "include/hw/t234/hw_pmasys_soc_hwpm.h"
#include "include/hw/t234/hw_pmmsys_soc_hwpm.h"
/* FIXME: Move enum to DT include file? */
enum tegra_soc_hwpm_dt_aperture {
TEGRA_SOC_HWPM_INVALID_DT = -1,
/* PERFMONs */
TEGRA_SOC_HWPM_FIRST_PERFMON_DT = 0,
TEGRA_SOC_HWPM_VI0_PERFMON_DT = TEGRA_SOC_HWPM_FIRST_PERFMON_DT,
TEGRA_SOC_HWPM_VI1_PERFMON_DT = TEGRA_SOC_HWPM_FIRST_PERFMON_DT + 1,
TEGRA_SOC_HWPM_ISP0_PERFMON_DT,
TEGRA_SOC_HWPM_VICA0_PERFMON_DT,
TEGRA_SOC_HWPM_OFAA0_PERFMON_DT,
TEGRA_SOC_HWPM_PVAV0_PERFMON_DT,
TEGRA_SOC_HWPM_PVAV1_PERFMON_DT,
TEGRA_SOC_HWPM_PVAC0_PERFMON_DT,
TEGRA_SOC_HWPM_NVDLAB0_PERFMON_DT,
TEGRA_SOC_HWPM_NVDLAB1_PERFMON_DT,
TEGRA_SOC_HWPM_NVDISPLAY0_PERFMON_DT,
TEGRA_SOC_HWPM_SYS0_PERFMON_DT,
TEGRA_SOC_HWPM_MGBE0_PERFMON_DT,
TEGRA_SOC_HWPM_MGBE1_PERFMON_DT,
TEGRA_SOC_HWPM_MGBE2_PERFMON_DT,
TEGRA_SOC_HWPM_MGBE3_PERFMON_DT,
TEGRA_SOC_HWPM_SCF0_PERFMON_DT,
TEGRA_SOC_HWPM_NVDECA0_PERFMON_DT,
TEGRA_SOC_HWPM_NVENCA0_PERFMON_DT,
TEGRA_SOC_HWPM_MSSNVLHSH0_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE0_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE1_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE2_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE3_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE4_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE5_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE6_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE7_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE8_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE9_PERFMON_DT,
TEGRA_SOC_HWPM_PCIE10_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTA0_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTA1_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTA2_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTA3_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTB0_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTB1_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTB2_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTB3_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTC0_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTC1_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTC2_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTC3_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTD0_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTD1_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTD2_PERFMON_DT,
TEGRA_SOC_HWPM_MSSCHANNELPARTD3_PERFMON_DT,
TEGRA_SOC_HWPM_MSSHUB0_PERFMON_DT,
TEGRA_SOC_HWPM_MSSHUB1_PERFMON_DT,
TEGRA_SOC_HWPM_MSSMCFCLIENT0_PERFMON_DT,
TEGRA_SOC_HWPM_MSSMCFMEM0_PERFMON_DT,
TEGRA_SOC_HWPM_MSSMCFMEM1_PERFMON_DT,
TEGRA_SOC_HWPM_LAST_PERFMON_DT = TEGRA_SOC_HWPM_MSSMCFMEM1_PERFMON_DT,
/* PMA */
TEGRA_SOC_HWPM_PMA_DT = TEGRA_SOC_HWPM_LAST_PERFMON_DT + 1,
/* RTR */
TEGRA_SOC_HWPM_RTR_DT,
TEGRA_SOC_HWPM_NUM_DT_APERTURES
};
#define IS_PERFMON(idx) (((idx) >= TEGRA_SOC_HWPM_FIRST_PERFMON_DT) && \
((idx) <= TEGRA_SOC_HWPM_LAST_PERFMON_DT))
/* RPG_PM Aperture */
#define PERFMON_BASE(ip_idx) (addr_map_rpg_pm_base_r() + \
((u32)(ip_idx)) * pmmsys_perdomain_offset_v())
#define PERFMON_LIMIT(ip_idx) (PERFMON_BASE((ip_idx) + 1) - 1)
#endif /* TEGRA_SOC_HWPM_HW_H */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -20,77 +20,19 @@
#ifndef TEGRA_SOC_HWPM_IO_H
#define TEGRA_SOC_HWPM_IO_H
#include "tegra-soc-hwpm.h"
struct tegra_soc_hwpm;
struct hwpm_resource_aperture;
struct allowlist;
struct hwpm_resource_aperture {
/*
* If false, this is a HWPM aperture (PERFRMON, PMA or RTR). Else this
* is a non-HWPM aperture (ex: VIC).
*/
bool is_ip;
/*
* If is_ip == false, specify dt_aperture for readl/writel operations.
* If is_ip == true, dt_aperture == TEGRA_SOC_HWPM_INVALID_DT.
*/
enum tegra_soc_hwpm_dt_aperture dt_aperture;
/* Physical aperture */
u64 start_abs_pa;
u64 end_abs_pa;
u64 start_pa;
u64 end_pa;
/* Allowlist */
struct allowlist *alist;
u64 alist_size;
/*
* Currently, perfmons and perfmuxes for all instances of an IP
* are listed in a single aperture mask. It is possible that
* some instances are disable. In this case, accessing corresponding
* registers will result in kernel panic.
* Bit set in the index_mask value will indicate the instance index
* within that IP (or resource).
*/
u32 index_mask;
/* Fake registers for VDK which doesn't have a SOC HWPM fmodel */
u32 *fake_registers;
};
struct hwpm_resource {
bool reserved;
u32 map_size;
struct hwpm_resource_aperture *map;
};
/* Externs */
extern struct hwpm_resource hwpm_resources[TERGA_SOC_HWPM_NUM_RESOURCES];
extern u32 *mc_fake_regs[16];
extern struct hwpm_resource_aperture t234_mss_channel_map[];
extern struct hwpm_resource_aperture t234_mss_gpu_hub_map[];
extern struct hwpm_resource_aperture t234_mss_iso_niso_hub_map[];
extern struct hwpm_resource_aperture t234_mss_mcf_map[];
extern struct hwpm_resource_aperture t234_pma_map[];
extern struct hwpm_resource_aperture t234_cmd_slice_rtr_map[];
void tegra_soc_hwpm_zero_alist_regs(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture);
int tegra_soc_hwpm_update_allowlist(struct tegra_soc_hwpm *hwpm,
void *ioctl_struct);
struct hwpm_resource_aperture *find_hwpm_aperture(struct tegra_soc_hwpm *hwpm,
u64 phys_addr,
bool use_absolute_base,
bool check_reservation,
u64 *updated_pa);
u32 hwpm_readl(struct tegra_soc_hwpm *hwpm,
enum tegra_soc_hwpm_dt_aperture dt_aperture,
u32 dt_aperture,
u32 reg_offset);
void hwpm_writel(struct tegra_soc_hwpm *hwpm,
enum tegra_soc_hwpm_dt_aperture dt_aperture,
u32 dt_aperture,
u32 reg_offset, u32 val);
u32 ip_readl(struct tegra_soc_hwpm *hwpm, u64 phys_addr);
void ip_writel(struct tegra_soc_hwpm *hwpm, u64 phys_addr, u32 val);
@@ -103,7 +45,7 @@ void ioctl_writel(struct tegra_soc_hwpm *hwpm,
u32 val);
int reg_rmw(struct tegra_soc_hwpm *hwpm,
struct hwpm_resource_aperture *aperture,
enum tegra_soc_hwpm_dt_aperture dt_aperture,
u32 dt_aperture,
u64 addr,
u32 field_mask,
u32 field_val,

View File

File diff suppressed because it is too large Load Diff

View File

@@ -17,34 +17,18 @@
* This file contains functions for SOC HWPM <-> IPC communication.
*/
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
#include <hal/tegra-soc-hwpm-structures.h>
#include <hal/tegra_soc_hwpm_init.h>
#include "tegra-soc-hwpm-log.h"
#include "tegra-soc-hwpm.h"
struct platform_device *tegra_soc_hwpm_pdev;
static enum tegra_soc_hwpm_dt_aperture tegra_soc_hwpm_get_apeture(
struct tegra_soc_hwpm *hwpm, u64 ip_base_address)
{
enum tegra_soc_hwpm_dt_aperture aperture =
TEGRA_SOC_HWPM_NUM_DT_APERTURES;
/* TODO chip speciifc implementation for finding aperture */
if (ip_base_address == addr_map_vic_base_r()) {
aperture = TEGRA_SOC_HWPM_VICA0_PERFMON_DT;
} else if (ip_base_address == addr_map_nvenc_base_r()) {
aperture = TEGRA_SOC_HWPM_NVENCA0_PERFMON_DT;
} else if (ip_base_address == addr_map_ofa_base_r()) {
aperture = TEGRA_SOC_HWPM_OFAA0_PERFMON_DT;
}
return aperture;
}
void tegra_soc_hwpm_ip_register(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
{
struct tegra_soc_hwpm *hwpm = NULL;
enum tegra_soc_hwpm_dt_aperture dt_aperture;
u32 dt_aperture;
tegra_soc_hwpm_dbg("HWPM Registered IP 0x%llx",
hwpm_ip_ops->ip_base_address);
@@ -59,9 +43,9 @@ void tegra_soc_hwpm_ip_register(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
return;
}
hwpm = platform_get_drvdata(tegra_soc_hwpm_pdev);
dt_aperture = tegra_soc_hwpm_get_apeture(hwpm,
hwpm_ip_ops->ip_base_address);
if (dt_aperture != TEGRA_SOC_HWPM_NUM_DT_APERTURES) {
dt_aperture = tegra_soc_hwpm_get_ip_aperture(hwpm,
hwpm_ip_ops->ip_base_address, NULL);
if (dt_aperture != TEGRA_SOC_HWPM_DT_APERTURE_INVALID) {
memcpy(&hwpm->ip_info[dt_aperture], hwpm_ip_ops,
sizeof(struct tegra_soc_hwpm_ip_ops));
} else {
@@ -76,7 +60,7 @@ void tegra_soc_hwpm_ip_register(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
void tegra_soc_hwpm_ip_unregister(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
{
struct tegra_soc_hwpm *hwpm = NULL;
enum tegra_soc_hwpm_dt_aperture dt_aperture;
u32 dt_aperture;
if (tegra_soc_hwpm_pdev == NULL) {
tegra_soc_hwpm_dbg("IP unregister before SOC HWPM 0x%llx",
@@ -87,9 +71,9 @@ void tegra_soc_hwpm_ip_unregister(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
return;
}
hwpm = platform_get_drvdata(tegra_soc_hwpm_pdev);
dt_aperture = tegra_soc_hwpm_get_apeture(hwpm,
hwpm_ip_ops->ip_base_address);
if (dt_aperture != TEGRA_SOC_HWPM_NUM_DT_APERTURES) {
dt_aperture = tegra_soc_hwpm_get_ip_aperture(hwpm,
hwpm_ip_ops->ip_base_address, NULL);
if (dt_aperture != TEGRA_SOC_HWPM_DT_APERTURE_INVALID) {
memset(&hwpm->ip_info[dt_aperture], 0,
sizeof(struct tegra_soc_hwpm_ip_ops));
}

View File

@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include "tegra-soc-hwpm.h"
#include "tegra-soc-hwpm-log.h"
#define LOG_BUF_SIZE 160

View File

@@ -22,10 +22,17 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/reset.h>
#include <linux/clk.h>
#include <linux/dma-buf.h>
#include <linux/debugfs.h>
#include <soc/tegra/fuse.h>
#include "tegra-soc-hwpm.h"
#include "tegra-soc-hwpm-log.h"
#include <hal/tegra_soc_hwpm_init.h>
#include <hal/tegra-soc-hwpm-structures.h>
static const struct of_device_id tegra_soc_hwpm_of_match[] = {
{
@@ -125,6 +132,8 @@ static int tegra_soc_hwpm_probe(struct platform_device *pdev)
}
tegra_soc_hwpm_debugfs_init(hwpm);
hwpm->dt_apertures = tegra_soc_hwpm_init_dt_apertures();
hwpm->ip_info = tegra_soc_hwpm_init_ip_ops_info();
/*
* Currently VDK doesn't have a fmodel for SOC HWPM. Therefore, we

View File

@@ -20,84 +20,15 @@
#ifndef TEGRA_SOC_HWPM_H
#define TEGRA_SOC_HWPM_H
#include <linux/reset.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/dma-buf.h>
#include <linux/scatterlist.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/delay.h>
//
//
// #include <linux/scatterlist.h>
//
#include "tegra-soc-hwpm-log.h"
#include "tegra-soc-hwpm-hw.h"
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
// #include "tegra-soc-hwpm-log.h"
//
/* FIXME: Default timeout is 1 sec. Is this sufficient for pre-si? */
#define HWPM_TIMEOUT(timeout_check, expiry_msg) ({ \
bool timeout_expired = false; \
s32 timeout_msecs = 1000; \
u32 sleep_msecs = 100; \
while(!(timeout_check)) { \
msleep(sleep_msecs); \
timeout_msecs -= sleep_msecs; \
if (timeout_msecs <= 0) { \
tegra_soc_hwpm_err("Timeout expired for %s!", \
expiry_msg); \
timeout_expired = true; \
break; \
} \
} \
timeout_expired; \
})
/* Driver struct */
struct tegra_soc_hwpm {
/* Device */
struct platform_device *pdev;
struct device *dev;
struct device_node *np;
struct class class;
dev_t dev_t;
struct cdev cdev;
/* IP floorsweep info */
u64 ip_fs_info[TERGA_SOC_HWPM_NUM_IPS];
/* MMIO apertures in device tree */
void __iomem *dt_apertures[TEGRA_SOC_HWPM_NUM_DT_APERTURES];
/* Clocks and resets */
struct clk *la_clk;
struct clk *la_parent_clk;
struct reset_control *la_rst;
struct reset_control *hwpm_rst;
struct tegra_soc_hwpm_ip_ops ip_info[TEGRA_SOC_HWPM_NUM_DT_APERTURES];
/* Memory Management */
struct dma_buf *stream_dma_buf;
struct dma_buf_attachment *stream_attach;
struct sg_table *stream_sgt;
struct dma_buf *mem_bytes_dma_buf;
struct dma_buf_attachment *mem_bytes_attach;
struct sg_table *mem_bytes_sgt;
void *mem_bytes_kernel;
/* SW State */
bool bind_completed;
s32 full_alist_size;
/* Debugging */
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
#endif
bool fake_registers_enabled;
};
extern struct platform_device *tegra_soc_hwpm_pdev;
extern const struct file_operations tegra_soc_hwpm_ops;
struct tegra_soc_hwpm;
#ifdef CONFIG_DEBUG_FS
void tegra_soc_hwpm_debugfs_init(struct tegra_soc_hwpm *hwpm);