From 842bf32431d4c04d037e23e443eb5d7b6d3e36c7 Mon Sep 17 00:00:00 2001 From: vasukis Date: Thu, 3 Aug 2023 15:02:48 +0000 Subject: [PATCH] tegra: hwpm: Add HWPM registration in Virt_engine - HWPM driver to profile OFA, VIC and NVENC IPs. Hence add the IP-HWPM registration mechanism. - Power management is not implemented as IPs are expected to stay powered on as long as Guest-OS-0 stays powered on. - Register operations for Read, Write to be handled by exposing IP Perfmuxes within the hypervisor. Bug 4170733 DOS-SHR-7601 Change-Id: I2936e9cc5539b7a5c93993694fbd1d866e2f6877 Signed-off-by: vasukis Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2948008 Reviewed-by: Mikko Perttunen GVS: Gerrit_Virtual_Submit --- drivers/gpu/drm/tegra/Makefile | 1 + drivers/gpu/drm/tegra/virt.c | 132 ++++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index d0f54928..dbc97d3a 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -3,6 +3,7 @@ ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG ccflags-y += -I$(srctree.nvidia-oot)/drivers/gpu/drm/tegra/include +ccflags-y += -I$(srctree.hwpm)/include tegra-drm-next-y := \ drm.o \ diff --git a/drivers/gpu/drm/tegra/virt.c b/drivers/gpu/drm/tegra/virt.c index 03e88636..6a67a9b9 100644 --- a/drivers/gpu/drm/tegra/virt.c +++ b/drivers/gpu/drm/tegra/virt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022, NVIDIA Corporation. + * Copyright (c) 2023, NVIDIA Corporation. */ #include @@ -19,6 +19,10 @@ #include "drm.h" +#ifndef CONFIG_TEGRA_SYSTEM_TYPE_ACK +#include +#endif + #define TEGRA_VHOST_CMD_CONNECT 0 #define TEGRA_VHOST_CMD_DISCONNECT 1 #define TEGRA_VHOST_CMD_SUSPEND 2 @@ -327,12 +331,107 @@ static const struct of_device_id tegra_virt_engine_of_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_virt_engine_of_match); +#ifndef CONFIG_TEGRA_SYSTEM_TYPE_ACK +static u32 virt_engine_get_ip_index(const char *name) +{ + if (strstr(name, "vic")) { + return (u32)TEGRA_SOC_HWPM_RESOURCE_VIC; + } else if (strstr(name, "nvenc")) { + return (u32)TEGRA_SOC_HWPM_RESOURCE_NVENC; + } else if (strstr(name, "ofa")) { + return (u32)TEGRA_SOC_HWPM_RESOURCE_OFA; + } + return (u32)TERGA_SOC_HWPM_NUM_IPS; +} + +static u32 virt_engine_extract_base_addr(struct platform_device *pdev) +{ + u32 hwpm_ip_index; + u32 base_address; + + hwpm_ip_index = virt_engine_get_ip_index(pdev->name); + if (hwpm_ip_index == TEGRA_SOC_HWPM_RESOURCE_VIC) { + base_address = 0x15340000; + } else if (hwpm_ip_index == TEGRA_SOC_HWPM_RESOURCE_NVENC) { + base_address = 0x154c0000; + } else if (hwpm_ip_index == TEGRA_SOC_HWPM_RESOURCE_OFA) { + base_address = 0x15a50000; + } else { + dev_err(&pdev->dev, "IP Base address not found"); + return -ENOMEM; + } + + return base_address; +} + +static int virt_engine_ip_pm(void *ip_dev, bool disable) +{ + int err = 0; + struct platform_device *pdev = (struct platform_device *)ip_dev; + + if (disable) { + dev_warn(&pdev->dev, "Power Mgmt not impleted in vhost_engine." + "IP expected to be ON"); + } else { + dev_warn(&pdev->dev, "Power Mgmt not impleted in vhost_engine." + "IP expected to be ON"); + } + + return err; +} + +static int virt_engine_ip_reg_op(void *ip_dev, + enum tegra_soc_hwpm_ip_reg_op reg_op, + u32 inst_element_index, u64 reg_offset, u32 *reg_data) +{ + struct platform_device *pdev = (struct platform_device *)ip_dev; + u32 base_address; + + base_address = virt_engine_extract_base_addr(pdev); + if (base_address <= 0) { + dev_err(&pdev->dev, "IP Base address not found. HWPM Reg_OP failed"); + return -ENOMEM; + } + + if (reg_op == TEGRA_SOC_HWPM_IP_REG_OP_READ) { + void __iomem *ptr = NULL; + + reg_offset = reg_offset + base_address; + ptr = ioremap(reg_offset, 0x4); + if (!ptr) { + dev_err(&pdev->dev, "Failed to map IP Perfmux register (0x%llx)", + reg_offset); + } + *reg_data = __raw_readl(ptr); + iounmap(ptr); + } else if (reg_op == TEGRA_SOC_HWPM_IP_REG_OP_WRITE) { + void __iomem *ptr = NULL; + + reg_offset = reg_offset + base_address; + + ptr = ioremap(reg_offset, 0x4); + if (!ptr) { + dev_err(&pdev->dev, "Failed to map IP Perfmux register (0x%llx)", + reg_offset); + } + __raw_writel(*reg_data, ptr); + iounmap(ptr); + } + + return 0; +} +#endif + static int virt_engine_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; u32 module_id, class; struct virt_engine *virt; int err; +#ifndef CONFIG_TEGRA_SYSTEM_TYPE_ACK + struct tegra_soc_hwpm_ip_ops hwpm_ip_ops; + u32 hwpm_ip_index; +#endif err = of_property_read_u32(pdev->dev.of_node, "nvidia,module-id", &module_id); if (err < 0) { @@ -399,6 +498,22 @@ static int virt_engine_probe(struct platform_device *pdev) virt_engine_setup_actmon_debugfs(virt); +#ifndef CONFIG_TEGRA_SYSTEM_TYPE_ACK + hwpm_ip_index = virt_engine_get_ip_index(pdev->name); + if (hwpm_ip_index != TERGA_SOC_HWPM_NUM_IPS) { + hwpm_ip_ops.ip_dev = (void *)pdev; + hwpm_ip_ops.ip_base_address = virt_engine_extract_base_addr(pdev); + if (hwpm_ip_ops.ip_base_address <= 0) { + dev_err(&pdev->dev, + "IP Base address not found. HWPM-IP registration failed"); + return 0; + } + hwpm_ip_ops.resource_enum = hwpm_ip_index; + hwpm_ip_ops.hwpm_ip_pm = &virt_engine_ip_pm; + hwpm_ip_ops.hwpm_ip_reg_op = &virt_engine_ip_reg_op; + tegra_soc_hwpm_ip_register(&hwpm_ip_ops); + } +#endif return 0; cleanup_ivc: @@ -413,7 +528,22 @@ static int virt_engine_remove(struct platform_device *pdev) { struct virt_engine *virt_engine = platform_get_drvdata(pdev); int err; +#ifndef CONFIG_TEGRA_SYSTEM_TYPE_ACK + struct tegra_soc_hwpm_ip_ops hwpm_ip_ops; + u32 hwpm_ip_index = virt_engine_get_ip_index(pdev->name); + if (hwpm_ip_index != TERGA_SOC_HWPM_NUM_IPS) { + hwpm_ip_ops.ip_dev = (void *)pdev; + hwpm_ip_ops.ip_base_address = virt_engine_extract_base_addr(pdev); + if (hwpm_ip_ops.ip_base_address <= 0) { + dev_err(&pdev->dev, + "IP Base address not found. HWPM-IP Un-register failed"); + return 0; + } + hwpm_ip_ops.resource_enum = hwpm_ip_index; + tegra_soc_hwpm_ip_unregister(&hwpm_ip_ops); + } +#endif virt_engine_cleanup_actmon_debugfs(virt_engine); virt_engine_cleanup();