tegra: hwpm: return error from read/write function

Currently, read/write functions validate aperture and mmio address
pointers. However, the error cannot be returned to the parent resulting
into undetected errors.
Modify all read write functions to return error on failure. This will
also allow HWPM driver to know about unavailable IP perfmuxes.

Jira THWPM-41

Change-Id: I6cc4ba7a831d5058657d4f2536b1ce3ab20b30c6
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2707446
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: Vasuki Shankar <vasukis@nvidia.com>
Reviewed-by: Seema Khowala <seemaj@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Vedashree Vidwans
2022-05-04 16:28:56 -07:00
committed by mobile promotions
parent 8e27814e39
commit c220f9f46f
8 changed files with 417 additions and 172 deletions

View File

@@ -23,59 +23,57 @@
#include <tegra_hwpm_log.h>
#include <tegra_hwpm_static_analysis.h>
static u32 fake_readl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 offset)
static int fake_readl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 offset, u32 *val)
{
u32 reg_val = 0;
if (!hwpm->fake_registers_enabled) {
tegra_hwpm_err(hwpm, "Fake registers are disabled!");
return 0;
return -ENODEV;
}
reg_val = aperture->fake_registers[offset];
return reg_val;
*val = aperture->fake_registers[offset];
return 0;
}
static void fake_writel(struct tegra_soc_hwpm *hwpm,
static int fake_writel(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 offset, u32 val)
{
if (!hwpm->fake_registers_enabled) {
tegra_hwpm_err(hwpm, "Fake registers are disabled!");
return;
return -ENODEV;
}
aperture->fake_registers[offset] = val;
return 0;
}
/*
* Read IP domain registers
* IP(except PMA and RTR) perfmux fall in this category
*/
static u32 ip_readl(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
struct hwpm_ip_aperture *aperture, u64 offset)
static int ip_readl(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
struct hwpm_ip_aperture *aperture, u64 offset, u32 *val)
{
tegra_hwpm_dbg(hwpm, hwpm_register,
"Aperture (0x%llx-0x%llx) offset(0x%llx)",
aperture->start_abs_pa, aperture->end_abs_pa, offset);
if (hwpm->fake_registers_enabled) {
return fake_readl(hwpm, aperture, offset);
return fake_readl(hwpm, aperture, offset, val);
} else {
u32 reg_val = 0U;
struct tegra_hwpm_ip_ops *ip_ops_ptr = &ip_inst->ip_ops;
if (ip_ops_ptr->hwpm_ip_reg_op != NULL) {
int err = 0;
err = (*ip_ops_ptr->hwpm_ip_reg_op)(ip_ops_ptr->ip_dev,
TEGRA_SOC_HWPM_IP_REG_OP_READ,
offset, &reg_val);
offset, val);
if (err < 0) {
tegra_hwpm_err(hwpm, "Aperture (0x%llx-0x%llx) "
"read offset(0x%llx) failed",
aperture->start_abs_pa,
aperture->end_abs_pa, offset);
return 0U;
return err;
}
} else {
/* Fall back to un-registered IP method */
@@ -86,7 +84,7 @@ static u32 ip_readl(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
if (is_tegra_hypervisor_mode()) {
tegra_hwpm_err(hwpm,
"Fallback method not implemented on hypervisor config");
return 0U;
return -EINVAL;
}
ptr = ioremap(reg_addr, 0x4);
@@ -94,20 +92,20 @@ static u32 ip_readl(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
tegra_hwpm_err(hwpm,
"Failed to map register(0x%llx)",
reg_addr);
return 0U;
return -ENODEV;
}
reg_val = __raw_readl(ptr);
*val = __raw_readl(ptr);
iounmap(ptr);
}
return reg_val;
}
return 0;
}
/*
* Write to IP domain registers
* IP(except PMA and RTR) perfmux fall in this category
*/
static void ip_writel(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
static int ip_writel(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
struct hwpm_ip_aperture *aperture, u64 offset, u32 val)
{
tegra_hwpm_dbg(hwpm, hwpm_register,
@@ -115,7 +113,7 @@ static void ip_writel(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
aperture->start_abs_pa, aperture->end_abs_pa, offset, val);
if (hwpm->fake_registers_enabled) {
fake_writel(hwpm, aperture, offset, val);
return fake_writel(hwpm, aperture, offset, val);
} else {
struct tegra_hwpm_ip_ops *ip_ops_ptr = &ip_inst->ip_ops;
if (ip_ops_ptr->hwpm_ip_reg_op != NULL) {
@@ -129,7 +127,7 @@ static void ip_writel(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
"write offset(0x%llx) val 0x%x failed",
aperture->start_abs_pa,
aperture->end_abs_pa, offset, val);
return;
return err;
}
} else {
/* Fall back to un-registered IP method */
@@ -140,7 +138,7 @@ static void ip_writel(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
if (is_tegra_hypervisor_mode()) {
tegra_hwpm_err(hwpm,
"Fallback method not implemented on hypervisor config");
return;
return -EINVAL;
}
ptr = ioremap(reg_addr, 0x4);
@@ -148,20 +146,21 @@ static void ip_writel(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst,
tegra_hwpm_err(hwpm,
"Failed to map register(0x%llx)",
reg_addr);
return;
return -ENODEV;
}
__raw_writel(val, ptr);
iounmap(ptr);
}
}
return 0;
}
/*
* Read HWPM domain registers
* PERFMONs, PMA and RTR registers fall in this category
*/
static u32 hwpm_readl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 offset)
static int hwpm_readl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 offset, u32 *val)
{
tegra_hwpm_dbg(hwpm, hwpm_register,
"Aperture (0x%llx-0x%llx) offset(0x%llx)",
@@ -169,51 +168,55 @@ static u32 hwpm_readl(struct tegra_soc_hwpm *hwpm,
if (aperture->dt_mmio == NULL) {
tegra_hwpm_err(hwpm, "aperture is not iomapped as expected");
return 0U;
return -ENODEV;
}
if (hwpm->fake_registers_enabled) {
return fake_readl(hwpm, aperture, offset);
return fake_readl(hwpm, aperture, offset, val);
} else {
return readl(aperture->dt_mmio + offset);
*val = readl(aperture->dt_mmio + offset);
}
return 0;
}
/*
* Write to HWPM domain registers
* PERFMONs, PMA and RTR registers fall in this category
*/
static void hwpm_writel(struct tegra_soc_hwpm *hwpm,
static int hwpm_writel(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 offset, u32 val)
{
int err = 0;
tegra_hwpm_dbg(hwpm, hwpm_register,
"Aperture (0x%llx-0x%llx) offset(0x%llx) val(0x%x)",
aperture->start_abs_pa, aperture->end_abs_pa, offset, val);
if (aperture->dt_mmio == NULL) {
tegra_hwpm_err(hwpm, "aperture is not iomapped as expected");
return;
return -ENODEV;
}
if (hwpm->fake_registers_enabled) {
fake_writel(hwpm, aperture, offset, val);
err = fake_writel(hwpm, aperture, offset, val);
} else {
writel(val, aperture->dt_mmio + offset);
}
return err;
}
/*
* Read a HWPM domain register. It is assumed that valid aperture
* is passed to the function.
*/
u32 tegra_hwpm_readl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 addr)
int tegra_hwpm_readl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 addr, u32 *val)
{
u32 reg_val = 0;
if (!aperture) {
tegra_hwpm_err(hwpm, "aperture is NULL");
return 0;
return -ENODEV;
}
if ((aperture->element_type == HWPM_ELEMENT_PERFMON) ||
@@ -221,24 +224,24 @@ u32 tegra_hwpm_readl(struct tegra_soc_hwpm *hwpm,
u64 reg_offset = tegra_hwpm_safe_sub_u64(
addr, aperture->base_pa);
/* HWPM domain registers */
reg_val = hwpm_readl(hwpm, aperture, reg_offset);
return hwpm_readl(hwpm, aperture, reg_offset, val);
} else {
tegra_hwpm_err(hwpm, "IP aperture read is not expected");
return 0;
return -EINVAL;
}
return reg_val;
return 0;
}
/*
* Write to a HWPM domain register. It is assumed that valid aperture
* is passed to the function.
*/
void tegra_hwpm_writel(struct tegra_soc_hwpm *hwpm,
int tegra_hwpm_writel(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 addr, u32 val)
{
if (!aperture) {
tegra_hwpm_err(hwpm, "aperture is NULL");
return;
return -ENODEV;
}
if ((aperture->element_type == HWPM_ELEMENT_PERFMON) ||
@@ -246,61 +249,64 @@ void tegra_hwpm_writel(struct tegra_soc_hwpm *hwpm,
u64 reg_offset = tegra_hwpm_safe_sub_u64(
addr, aperture->base_pa);
/* HWPM domain internal registers */
hwpm_writel(hwpm, aperture, reg_offset, val);
return hwpm_writel(hwpm, aperture, reg_offset, val);
} else {
tegra_hwpm_err(hwpm, "IP aperture write is not expected");
return;
return -EINVAL;
}
return 0;
}
/*
* Read a register from the EXEC_REG_OPS IOCTL. It is assumed that the allowlist
* check has been done before calling this function.
*/
u32 tegra_hwpm_regops_readl(struct tegra_soc_hwpm *hwpm,
u64 addr, struct hwpm_ip_inst *ip_inst,
struct hwpm_ip_aperture *aperture)
int tegra_hwpm_regops_readl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_inst *ip_inst, struct hwpm_ip_aperture *aperture,
u64 addr, u32 *val)
{
u32 reg_val = 0;
u64 reg_offset = 0ULL;
int err = 0;
if (!aperture) {
tegra_hwpm_err(hwpm, "aperture is NULL");
return 0;
return -ENODEV;
}
reg_offset = tegra_hwpm_safe_sub_u64(addr, aperture->start_abs_pa);
if ((aperture->element_type == HWPM_ELEMENT_PERFMON) ||
(aperture->element_type == HWPM_ELEMENT_PERFMUX)) {
reg_val = hwpm_readl(hwpm, aperture, reg_offset);
err = hwpm_readl(hwpm, aperture, reg_offset, val);
} else {
reg_val = ip_readl(hwpm, ip_inst, aperture, reg_offset);
err = ip_readl(hwpm, ip_inst, aperture, reg_offset, val);
}
return reg_val;
return err;
}
/*
* Write a register from the EXEC_REG_OPS IOCTL. It is assumed that the
* allowlist check has been done before calling this function.
*/
void tegra_hwpm_regops_writel(struct tegra_soc_hwpm *hwpm,
u64 addr, u32 val, struct hwpm_ip_inst *ip_inst,
struct hwpm_ip_aperture *aperture)
int tegra_hwpm_regops_writel(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_inst *ip_inst, struct hwpm_ip_aperture *aperture,
u64 addr, u32 val)
{
u64 reg_offset = 0ULL;
int err = 0;
if (!aperture) {
tegra_hwpm_err(hwpm, "aperture is NULL");
return;
return -ENODEV;
}
reg_offset = tegra_hwpm_safe_sub_u64(addr, aperture->start_abs_pa);
if ((aperture->element_type == HWPM_ELEMENT_PERFMON) ||
(aperture->element_type == HWPM_ELEMENT_PERFMUX)) {
hwpm_writel(hwpm, aperture, reg_offset, val);
err = hwpm_writel(hwpm, aperture, reg_offset, val);
} else {
ip_writel(hwpm, ip_inst, aperture, reg_offset, val);
err = ip_writel(hwpm, ip_inst, aperture, reg_offset, val);
}
return err;
}