From 738361e0e23a31665ca43270ba8d73a16cca39b3 Mon Sep 17 00:00:00 2001 From: Vedashree Vidwans Date: Wed, 15 Jun 2022 23:41:07 -0700 Subject: [PATCH] tegra: hwpm: add wrapper linux os structure Currently, HWPM parent structure contains linux specific device variables. In an effort to make HWPM driver OS agnostic, create Linux specific wrapper HWPM structure tegra_hwpm_os_linux. Move linux specific variables from tegra_soc_hwpm structure to tegra_hwpm_os_linux structure. Jira THWPM-60 Change-Id: I189cde92c5b83b327ccb467c72dee5756f16481d Signed-off-by: Vedashree Vidwans Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2729700 Reviewed-by: Seema Khowala GVS: Gerrit_Virtual_Submit --- common/init.c | 37 +++--- hal/t234/t234_interface.c | 7 -- include/tegra_hwpm.h | 42 +------ include/tegra_hwpm_common.h | 4 +- include/tegra_hwpm_static_analysis.h | 3 +- include/tegra_hwpm_types.h | 3 + os/linux/aperture_utils.c | 26 ++++- os/linux/debugfs.c | 31 ++--- os/linux/debugfs.h | 11 +- os/linux/driver.c | 164 +++++++++++++++------------ os/linux/driver.h | 58 ++++++++++ os/linux/ioctl.c | 93 ++++++++------- os/linux/ip_utils.c | 3 +- os/linux/mem_mgmt_utils.c | 22 +++- 14 files changed, 292 insertions(+), 212 deletions(-) diff --git a/common/init.c b/common/init.c index 7ae21c7..cb39ebc 100644 --- a/common/init.c +++ b/common/init.c @@ -24,32 +24,33 @@ #include #endif -static int tegra_hwpm_init_chip_ip_structures(struct tegra_soc_hwpm *hwpm) + +static int tegra_hwpm_init_chip_ip_structures(struct tegra_soc_hwpm *hwpm, + u32 chip_id, u32 chip_id_rev) { int err = -EINVAL; tegra_hwpm_fn(hwpm, " "); - switch (hwpm->device_info.chip) { + switch (chip_id) { case 0x23: - switch (hwpm->device_info.chip_revision) { + switch (chip_id_rev) { case 0x4: err = t234_hwpm_init_chip_info(hwpm); break; default: #ifdef CONFIG_TEGRA_NEXT1_HWPM - err = tegra_hwpm_next1_init_chip_info(hwpm); + err = tegra_hwpm_next1_init_chip_info(hwpm, + chip_id, chip_id_rev); #else tegra_hwpm_err(hwpm, "Chip 0x%x rev 0x%x not supported", - hwpm->device_info.chip, - hwpm->device_info.chip_revision); + chip_id, chip_id_rev); #endif break; } break; default: - tegra_hwpm_err(hwpm, "Chip 0x%x not supported", - hwpm->device_info.chip); + tegra_hwpm_err(hwpm, "Chip 0x%x not supported", chip_id); break; } @@ -67,13 +68,16 @@ static int tegra_hwpm_init_chip_ip_structures(struct tegra_soc_hwpm *hwpm) return err; } -int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm) +int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm, + u32 chip_id, u32 chip_id_rev) { int err = 0; tegra_hwpm_fn(hwpm, " "); - err = tegra_hwpm_init_chip_ip_structures(hwpm); + hwpm->dbg_mask = TEGRA_HWPM_DEFAULT_DBG_MASK; + + err = tegra_hwpm_init_chip_ip_structures(hwpm, chip_id, chip_id_rev); if (err != 0) { tegra_hwpm_err(hwpm, "IP structure init failed"); return err; @@ -88,17 +92,6 @@ int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm) return 0; } -void tegra_hwpm_release_sw_components(struct tegra_soc_hwpm *hwpm) -{ - tegra_hwpm_fn(hwpm, " "); - - hwpm->active_chip->release_sw_setup(hwpm); - - tegra_hwpm_kfree(hwpm, hwpm->active_chip->chip_ips); - tegra_hwpm_kfree(hwpm, hwpm); - tegra_soc_hwpm_pdev = NULL; -} - int tegra_hwpm_setup_sw(struct tegra_soc_hwpm *hwpm) { int ret = 0; @@ -211,5 +204,7 @@ void tegra_hwpm_release_sw_setup(struct tegra_soc_hwpm *hwpm) return; } + tegra_hwpm_kfree(hwpm, hwpm->active_chip->chip_ips); + return; } diff --git a/hal/t234/t234_interface.c b/hal/t234/t234_interface.c index 2ef282a..3e946ca 100644 --- a/hal/t234/t234_interface.c +++ b/hal/t234/t234_interface.c @@ -59,8 +59,6 @@ static struct tegra_soc_hwpm_chip t234_chip_info = { .zero_alist_regs = t234_hwpm_zero_alist_regs, .copy_alist = t234_hwpm_copy_alist, .check_alist = t234_hwpm_check_alist, - - .release_sw_setup = tegra_hwpm_release_sw_setup, }; static bool t234_hwpm_validate_hals(struct tegra_soc_hwpm *hwpm) @@ -215,11 +213,6 @@ static bool t234_hwpm_validate_hals(struct tegra_soc_hwpm *hwpm) return false; } - if (hwpm->active_chip->release_sw_setup == NULL) { - tegra_hwpm_err(hwpm, "release_sw_setup uninitialized"); - return false; - } - return true; } diff --git a/include/tegra_hwpm.h b/include/tegra_hwpm.h index 83c04e6..7546f1b 100644 --- a/include/tegra_hwpm.h +++ b/include/tegra_hwpm.h @@ -14,13 +14,6 @@ #ifndef TEGRA_HWPM_H #define TEGRA_HWPM_H -#include -#include -#include -#include - -#include - #include #define TEGRA_SOC_HWPM_IP_INACTIVE ~(0U) @@ -431,54 +424,21 @@ struct tegra_soc_hwpm_chip { u64 *full_alist_idx); bool (*check_alist)(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_aperture *aperture, u64 phys_addr); - - void (*release_sw_setup)(struct tegra_soc_hwpm *hwpm); }; -extern struct platform_device *tegra_soc_hwpm_pdev; -extern const struct file_operations tegra_soc_hwpm_ops; -struct allowlist; -struct tegra_hwpm_mem_mgmt; -struct tegra_hwpm_allowlist_map; - /* 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; - - /* Device info */ - struct tegra_soc_hwpm_device_info device_info; - /* Active chip info */ struct tegra_soc_hwpm_chip *active_chip; - /* Clocks and resets */ - struct clk *la_clk; - struct clk *la_parent_clk; - struct reset_control *la_rst; - struct reset_control *hwpm_rst; - /* Memory Management */ struct tegra_hwpm_mem_mgmt *mem_mgmt; struct tegra_hwpm_allowlist_map *alist_map; /* SW State */ + u32 dbg_mask; bool bind_completed; bool device_opened; - - atomic_t hwpm_in_use; - - u32 dbg_mask; - - /* Debugging */ -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_root; -#endif bool fake_registers_enabled; }; diff --git a/include/tegra_hwpm_common.h b/include/tegra_hwpm_common.h index a0eb289..6797a9e 100644 --- a/include/tegra_hwpm_common.h +++ b/include/tegra_hwpm_common.h @@ -26,8 +26,8 @@ struct hwpm_ip; struct hwpm_ip_inst; struct hwpm_ip_aperture; -int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm); -void tegra_hwpm_release_sw_components(struct tegra_soc_hwpm *hwpm); +int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm, + u32 chip_id, u32 chip_id_rev); int tegra_hwpm_func_all_ip(struct tegra_soc_hwpm *hwpm, struct tegra_hwpm_func_args *func_args, diff --git a/include/tegra_hwpm_static_analysis.h b/include/tegra_hwpm_static_analysis.h index 9807992..6ca82d3 100644 --- a/include/tegra_hwpm_static_analysis.h +++ b/include/tegra_hwpm_static_analysis.h @@ -14,8 +14,7 @@ #ifndef TEGRA_HWPM_STATIC_ANALYSIS_H #define TEGRA_HWPM_STATIC_ANALYSIS_H -#include -#include +#include /** * @brief Add two u32 values and check for overflow. diff --git a/include/tegra_hwpm_types.h b/include/tegra_hwpm_types.h index f8373fb..c4b6554 100644 --- a/include/tegra_hwpm_types.h +++ b/include/tegra_hwpm_types.h @@ -16,6 +16,9 @@ #ifdef __KERNEL__ #include +#include +#include +#include #endif #endif /* TEGRA_HWPM_TYPES_H */ diff --git a/os/linux/aperture_utils.c b/os/linux/aperture_utils.c index 52210ad..6557fd1 100644 --- a/os/linux/aperture_utils.c +++ b/os/linux/aperture_utils.c @@ -20,24 +20,32 @@ #include #include #include +#include int tegra_hwpm_perfmon_reserve_impl(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_inst *ip_inst, struct hwpm_ip_aperture *perfmon) { struct resource *res = NULL; + struct tegra_hwpm_os_linux *hwpm_linux = NULL; tegra_hwpm_fn(hwpm, " "); + hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, "Invalid hwpm_linux struct"); + return -ENODEV; + } + /* Reserve */ - res = platform_get_resource_byname(hwpm->pdev, - IORESOURCE_MEM, perfmon->name); + res = platform_get_resource_byname(hwpm_linux->pdev, + IORESOURCE_MEM, perfmon->name); if ((!res) || (res->start == 0) || (res->end == 0)) { tegra_hwpm_err(hwpm, "Failed to get perfmon %s", perfmon->name); return -ENOMEM; } - perfmon->dt_mmio = devm_ioremap(hwpm->dev, res->start, - resource_size(res)); + perfmon->dt_mmio = devm_ioremap( + hwpm_linux->dev, res->start, resource_size(res)); if (IS_ERR(perfmon->dt_mmio)) { tegra_hwpm_err(hwpm, "Couldn't map perfmon %s", perfmon->name); return PTR_ERR(perfmon->dt_mmio); @@ -116,13 +124,21 @@ int tegra_hwpm_perfmux_reserve_impl(struct tegra_soc_hwpm *hwpm, int tegra_hwpm_perfmon_release_impl(struct tegra_soc_hwpm *hwpm, struct hwpm_ip_aperture *perfmon) { + struct tegra_hwpm_os_linux *hwpm_linux = NULL; + tegra_hwpm_fn(hwpm, " "); + hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, "Invalid hwpm_linux struct"); + return -ENODEV; + } + if (perfmon->dt_mmio == NULL) { tegra_hwpm_err(hwpm, "Perfmon was not mapped"); return -EINVAL; } - devm_iounmap(hwpm->dev, perfmon->dt_mmio); + devm_iounmap(hwpm_linux->dev, perfmon->dt_mmio); perfmon->dt_mmio = NULL; perfmon->start_pa = 0ULL; perfmon->end_pa = 0ULL; diff --git a/os/linux/debugfs.c b/os/linux/debugfs.c index 1e1f2d4..ba4a150 100644 --- a/os/linux/debugfs.c +++ b/os/linux/debugfs.c @@ -18,39 +18,44 @@ #include #include #include +#include -void tegra_hwpm_debugfs_init(struct tegra_soc_hwpm *hwpm) +void tegra_hwpm_debugfs_init(struct tegra_hwpm_os_linux *hwpm_linux) { - if (!hwpm) { - tegra_hwpm_err(hwpm, "Invalid hwpm struct"); + struct tegra_soc_hwpm *hwpm = &hwpm_linux->hwpm; + + if (!hwpm_linux) { + tegra_hwpm_err(hwpm, "Invalid hwpm_linux struct"); return; } - hwpm->debugfs_root = + hwpm_linux->debugfs_root = debugfs_create_dir(TEGRA_SOC_HWPM_MODULE_NAME, NULL); - if (!hwpm->debugfs_root) { + if (!hwpm_linux->debugfs_root) { tegra_hwpm_err(hwpm, "Failed to create debugfs root directory"); goto fail; } /* Debug logs */ - debugfs_create_u32("log_mask", S_IRUGO|S_IWUSR, hwpm->debugfs_root, - &hwpm->dbg_mask); + debugfs_create_u32("log_mask", S_IRUGO|S_IWUSR, + hwpm_linux->debugfs_root, &hwpm->dbg_mask); return; fail: - debugfs_remove_recursive(hwpm->debugfs_root); - hwpm->debugfs_root = NULL; + debugfs_remove_recursive(hwpm_linux->debugfs_root); + hwpm_linux->debugfs_root = NULL; } -void tegra_hwpm_debugfs_deinit(struct tegra_soc_hwpm *hwpm) +void tegra_hwpm_debugfs_deinit(struct tegra_hwpm_os_linux *hwpm_linux) { - if (!hwpm) { + struct tegra_soc_hwpm *hwpm = &hwpm_linux->hwpm; + + if (!hwpm_linux) { tegra_hwpm_err(hwpm, "Invalid hwpm struct"); return; } - debugfs_remove_recursive(hwpm->debugfs_root); - hwpm->debugfs_root = NULL; + debugfs_remove_recursive(hwpm_linux->debugfs_root); + hwpm_linux->debugfs_root = NULL; } diff --git a/os/linux/debugfs.h b/os/linux/debugfs.h index 18ac0a3..091d32a 100644 --- a/os/linux/debugfs.h +++ b/os/linux/debugfs.h @@ -15,13 +15,16 @@ #define TEGRA_HWPM_OS_LINUX_DEBUGFS_H struct tegra_soc_hwpm; +struct tegra_hwpm_os_linux; #ifdef CONFIG_DEBUG_FS -void tegra_hwpm_debugfs_init(struct tegra_soc_hwpm *hwpm); -void tegra_hwpm_debugfs_deinit(struct tegra_soc_hwpm *hwpm); +void tegra_hwpm_debugfs_init(struct tegra_hwpm_os_linux *hwpm_linux); +void tegra_hwpm_debugfs_deinit(struct tegra_hwpm_os_linux *hwpm_linux); #else -static inline void tegra_hwpm_debugfs_init(struct tegra_soc_hwpm *hwpm) {} -static inline void tegra_hwpm_debugfs_deinit(struct tegra_soc_hwpm *hwpm) {} +static inline void tegra_hwpm_debugfs_init( + struct tegra_hwpm_os_linux *hwpm_linux) {} +static inline void tegra_hwpm_debugfs_deinit( + struct tegra_hwpm_os_linux *hwpm_linux) {} #endif /* CONFIG_DEBUG_FS */ #endif /* TEGRA_HWPM_OS_LINUX_DEBUGFS_H */ diff --git a/os/linux/driver.c b/os/linux/driver.c index 1bf914d..b90018e 100644 --- a/os/linux/driver.c +++ b/os/linux/driver.c @@ -23,11 +23,13 @@ #include #include +#include #include #include +#include #include #include -#include +#include static const struct of_device_id tegra_soc_hwpm_of_match[] = { { @@ -64,16 +66,12 @@ static bool tegra_hwpm_read_support_soc_tools_prop(struct platform_device *pdev) return allow_node; } -static int tegra_hwpm_init_chip_info(struct tegra_soc_hwpm *hwpm) +int tegra_hwpm_init_chip_info(struct tegra_hwpm_os_linux *hwpm_linux) { - tegra_hwpm_fn(hwpm, " "); - - hwpm->dbg_mask = TEGRA_HWPM_DEFAULT_DBG_MASK; - - hwpm->device_info.chip = tegra_get_chip_id(); - hwpm->device_info.chip_revision = tegra_get_major_rev(); - hwpm->device_info.revision = tegra_chip_get_revision(); - hwpm->device_info.platform = tegra_get_platform(); + hwpm_linux->device_info.chip = tegra_get_chip_id(); + hwpm_linux->device_info.chip_revision = tegra_get_major_rev(); + hwpm_linux->device_info.revision = tegra_chip_get_revision(); + hwpm_linux->device_info.platform = tegra_get_platform(); return 0; } @@ -82,6 +80,7 @@ static int tegra_hwpm_probe(struct platform_device *pdev) { int ret = 0; struct device *dev = NULL; + struct tegra_hwpm_os_linux *hwpm_linux = NULL; struct tegra_soc_hwpm *hwpm = NULL; if (!pdev) { @@ -96,94 +95,100 @@ static int tegra_hwpm_probe(struct platform_device *pdev) goto fail; } - hwpm = kzalloc(sizeof(struct tegra_soc_hwpm), GFP_KERNEL); - if (!hwpm) { - tegra_hwpm_err(hwpm, "Couldn't allocate memory for hwpm struct"); + hwpm_linux = kzalloc(sizeof(struct tegra_hwpm_os_linux), GFP_KERNEL); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, + "Couldn't allocate memory for linux hwpm struct"); ret = -ENOMEM; goto fail; } - hwpm->pdev = pdev; - hwpm->dev = &pdev->dev; - hwpm->np = pdev->dev.of_node; - hwpm->class.owner = THIS_MODULE; - hwpm->class.name = TEGRA_SOC_HWPM_MODULE_NAME; + hwpm_linux->pdev = pdev; + hwpm_linux->dev = &pdev->dev; + hwpm_linux->np = pdev->dev.of_node; + hwpm_linux->class.owner = THIS_MODULE; + hwpm_linux->class.name = TEGRA_SOC_HWPM_MODULE_NAME; + + hwpm = &hwpm_linux->hwpm; /* Create device node */ - ret = class_register(&hwpm->class); + ret = class_register(&hwpm_linux->class); if (ret) { tegra_hwpm_err(hwpm, "Failed to register class"); goto class_register; } /* Set devnode to retrieve device permissions */ - hwpm->class.devnode = tegra_hwpm_get_devnode; + hwpm_linux->class.devnode = tegra_hwpm_get_devnode; - ret = alloc_chrdev_region(&hwpm->dev_t, 0, 1, dev_name(hwpm->dev)); + ret = alloc_chrdev_region(&hwpm_linux->dev_t, 0, 1, + dev_name(hwpm_linux->dev)); if (ret) { tegra_hwpm_err(hwpm, "Failed to allocate device region"); goto alloc_chrdev_region; } - cdev_init(&hwpm->cdev, &tegra_soc_hwpm_ops); - hwpm->cdev.owner = THIS_MODULE; + cdev_init(&hwpm_linux->cdev, &tegra_hwpm_ops); + hwpm_linux->cdev.owner = THIS_MODULE; - ret = cdev_add(&hwpm->cdev, hwpm->dev_t, 1); + ret = cdev_add(&hwpm_linux->cdev, hwpm_linux->dev_t, 1); if (ret) { tegra_hwpm_err(hwpm, "Failed to add cdev"); goto cdev_add; } - dev = device_create(&hwpm->class, - NULL, - hwpm->dev_t, - NULL, - TEGRA_SOC_HWPM_MODULE_NAME); + dev = device_create(&hwpm_linux->class, NULL, + hwpm_linux->dev_t, NULL, TEGRA_SOC_HWPM_MODULE_NAME); if (IS_ERR(dev)) { tegra_hwpm_err(hwpm, "Failed to create device"); ret = PTR_ERR(dev); goto device_create; } - (void) dma_set_mask_and_coherent(hwpm->dev, DMA_BIT_MASK(39)); + (void) dma_set_mask_and_coherent(hwpm_linux->dev, DMA_BIT_MASK(39)); if (tegra_hwpm_is_platform_silicon()) { - hwpm->la_clk = devm_clk_get(hwpm->dev, "la"); - if (IS_ERR(hwpm->la_clk)) { + hwpm_linux->la_clk = devm_clk_get(hwpm_linux->dev, "la"); + if (IS_ERR(hwpm_linux->la_clk)) { tegra_hwpm_err(hwpm, "Missing la clock"); - ret = PTR_ERR(hwpm->la_clk); + ret = PTR_ERR(hwpm_linux->la_clk); goto clock_reset_fail; } - hwpm->la_parent_clk = devm_clk_get(hwpm->dev, "parent"); - if (IS_ERR(hwpm->la_parent_clk)) { + hwpm_linux->la_parent_clk = + devm_clk_get(hwpm_linux->dev, "parent"); + if (IS_ERR(hwpm_linux->la_parent_clk)) { tegra_hwpm_err(hwpm, "Missing la parent clk"); - ret = PTR_ERR(hwpm->la_parent_clk); + ret = PTR_ERR(hwpm_linux->la_parent_clk); goto clock_reset_fail; } - hwpm->la_rst = devm_reset_control_get(hwpm->dev, "la"); - if (IS_ERR(hwpm->la_rst)) { + hwpm_linux->la_rst = + devm_reset_control_get(hwpm_linux->dev, "la"); + if (IS_ERR(hwpm_linux->la_rst)) { tegra_hwpm_err(hwpm, "Missing la reset"); - ret = PTR_ERR(hwpm->la_rst); + ret = PTR_ERR(hwpm_linux->la_rst); goto clock_reset_fail; } - hwpm->hwpm_rst = devm_reset_control_get(hwpm->dev, "hwpm"); - if (IS_ERR(hwpm->hwpm_rst)) { + hwpm_linux->hwpm_rst = + devm_reset_control_get(hwpm_linux->dev, "hwpm"); + if (IS_ERR(hwpm_linux->hwpm_rst)) { tegra_hwpm_err(hwpm, "Missing hwpm reset"); - ret = PTR_ERR(hwpm->hwpm_rst); + ret = PTR_ERR(hwpm_linux->hwpm_rst); goto clock_reset_fail; } } - tegra_hwpm_debugfs_init(hwpm); - ret = tegra_hwpm_init_chip_info(hwpm); + tegra_hwpm_debugfs_init(hwpm_linux); + + ret = tegra_hwpm_init_chip_info(hwpm_linux); if (ret != 0) { - tegra_hwpm_err(hwpm, "Failed to initialize current chip info."); + tegra_hwpm_err(hwpm, "Failed to initialize current chip info"); goto init_chip_info_fail; } - ret = tegra_hwpm_init_sw_components(hwpm); + ret = tegra_hwpm_init_sw_components(hwpm, hwpm_linux->device_info.chip, + hwpm_linux->device_info.chip_revision); if (ret != 0) { tegra_hwpm_err(hwpm, "Failed to init sw components"); goto init_sw_components_fail; @@ -207,25 +212,26 @@ static int tegra_hwpm_probe(struct platform_device *pdev) init_chip_info_fail: init_sw_components_fail: if (tegra_hwpm_is_platform_silicon()) { - if (hwpm->la_clk) - devm_clk_put(hwpm->dev, hwpm->la_clk); - if (hwpm->la_parent_clk) - devm_clk_put(hwpm->dev, hwpm->la_parent_clk); - if (hwpm->la_rst) - reset_control_assert(hwpm->la_rst); - if (hwpm->hwpm_rst) - reset_control_assert(hwpm->hwpm_rst); + if (hwpm_linux->la_clk) + devm_clk_put(hwpm_linux->dev, hwpm_linux->la_clk); + if (hwpm_linux->la_parent_clk) + devm_clk_put(hwpm_linux->dev, + hwpm_linux->la_parent_clk); + if (hwpm_linux->la_rst) + reset_control_assert(hwpm_linux->la_rst); + if (hwpm_linux->hwpm_rst) + reset_control_assert(hwpm_linux->hwpm_rst); } clock_reset_fail: - device_destroy(&hwpm->class, hwpm->dev_t); + device_destroy(&hwpm_linux->class, hwpm_linux->dev_t); device_create: - cdev_del(&hwpm->cdev); + cdev_del(&hwpm_linux->cdev); cdev_add: - unregister_chrdev_region(hwpm->dev_t, 1); + unregister_chrdev_region(hwpm_linux->dev_t, 1); alloc_chrdev_region: - class_unregister(&hwpm->class); + class_unregister(&hwpm_linux->class); class_register: - kfree(hwpm); + tegra_hwpm_kfree(NULL, hwpm_linux); fail: tegra_hwpm_err(NULL, "Probe failed!"); success: @@ -234,6 +240,7 @@ success: static int tegra_hwpm_remove(struct platform_device *pdev) { + struct tegra_hwpm_os_linux *hwpm_linux = NULL; struct tegra_soc_hwpm *hwpm = NULL; if (!pdev) { @@ -247,25 +254,34 @@ static int tegra_hwpm_remove(struct platform_device *pdev) return -ENODEV; } - if (tegra_hwpm_is_platform_silicon()) { - if (hwpm->la_clk) - devm_clk_put(hwpm->dev, hwpm->la_clk); - if (hwpm->la_parent_clk) - devm_clk_put(hwpm->dev, hwpm->la_parent_clk); - if (hwpm->la_rst) - reset_control_assert(hwpm->la_rst); - if (hwpm->hwpm_rst) - reset_control_assert(hwpm->hwpm_rst); + hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, "Invalid hwpm_linux struct"); + return -ENODEV; } - device_destroy(&hwpm->class, hwpm->dev_t); - cdev_del(&hwpm->cdev); - unregister_chrdev_region(hwpm->dev_t, 1); - class_unregister(&hwpm->class); + if (tegra_hwpm_is_platform_silicon()) { + if (hwpm_linux->la_clk) + devm_clk_put(hwpm_linux->dev, hwpm_linux->la_clk); + if (hwpm_linux->la_parent_clk) + devm_clk_put(hwpm_linux->dev, hwpm_linux->la_parent_clk); + if (hwpm_linux->la_rst) + reset_control_assert(hwpm_linux->la_rst); + if (hwpm_linux->hwpm_rst) + reset_control_assert(hwpm_linux->hwpm_rst); + } - tegra_hwpm_debugfs_deinit(hwpm); tegra_hwpm_release_ip_register_node(hwpm); - tegra_hwpm_release_sw_components(hwpm); + tegra_hwpm_release_sw_setup(hwpm); + tegra_hwpm_debugfs_deinit(hwpm_linux); + + device_destroy(&hwpm_linux->class, hwpm_linux->dev_t); + cdev_del(&hwpm_linux->cdev); + unregister_chrdev_region(hwpm_linux->dev_t, 1); + class_unregister(&hwpm_linux->class); + + tegra_hwpm_kfree(NULL, hwpm_linux); + tegra_soc_hwpm_pdev = NULL; return 0; } diff --git a/os/linux/driver.h b/os/linux/driver.h index 0145881..6958c36 100644 --- a/os/linux/driver.h +++ b/os/linux/driver.h @@ -14,10 +14,68 @@ #ifndef TEGRA_HWPM_OS_LINUX_DRIVER_H #define TEGRA_HWPM_OS_LINUX_DRIVER_H +#include +#include +#include +#include + +#include + +#include + +#define TEGRA_SOC_HWPM_MODULE_NAME "tegra-soc-hwpm" + +extern struct platform_device *tegra_soc_hwpm_pdev; +extern const struct file_operations tegra_hwpm_ops; + +typedef struct tegra_hwpm_linux_atomic_t { + atomic_t var; +} tegra_hwpm_atomic_t; + struct hwpm_ip_register_list { struct tegra_soc_hwpm_ip_ops ip_ops; struct hwpm_ip_register_list *next; }; extern struct hwpm_ip_register_list *ip_register_list_head; +struct tegra_hwpm_os_linux { + struct tegra_soc_hwpm hwpm; + + /* Device */ + struct platform_device *pdev; + struct device *dev; + struct device_node *np; + struct class class; + dev_t dev_t; + struct cdev cdev; + + /* Clocks and resets */ + struct clk *la_clk; + struct clk *la_parent_clk; + struct reset_control *la_rst; + struct reset_control *hwpm_rst; + + /* Device info */ + struct tegra_soc_hwpm_device_info device_info; + + /* Reference count */ + tegra_hwpm_atomic_t usage_count; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; +#endif +}; + +static inline struct tegra_hwpm_os_linux *tegra_hwpm_os_linux_from_cdev( + struct cdev *cdev) +{ + return container_of(cdev, struct tegra_hwpm_os_linux, cdev); +} + +static inline struct tegra_hwpm_os_linux *tegra_hwpm_os_linux_from_hwpm( + struct tegra_soc_hwpm *hwpm) +{ + return container_of(hwpm, struct tegra_hwpm_os_linux, hwpm); +} + #endif /* TEGRA_HWPM_OS_LINUX_DRIVER_H */ diff --git a/os/linux/ioctl.c b/os/linux/ioctl.c index 0430041..4e2fe6c 100644 --- a/os/linux/ioctl.c +++ b/os/linux/ioctl.c @@ -29,8 +29,11 @@ #include #include #include +#include #include #include + +#include #include #define LA_CLK_RATE 625000000UL @@ -38,12 +41,20 @@ static int tegra_hwpm_get_device_info_ioctl(struct tegra_soc_hwpm *hwpm, struct tegra_soc_hwpm_device_info *device_info) { + struct tegra_hwpm_os_linux *hwpm_linux = NULL; + tegra_hwpm_fn(hwpm, " "); - device_info->chip = hwpm->device_info.chip; - device_info->chip_revision = hwpm->device_info.chip_revision; - device_info->revision = hwpm->device_info.revision; - device_info->platform = hwpm->device_info.platform; + hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, "Invalid hwpm_linux struct"); + return -ENODEV; + } + + device_info->chip = hwpm_linux->device_info.chip; + device_info->chip_revision = hwpm_linux->device_info.chip_revision; + device_info->revision = hwpm_linux->device_info.revision; + device_info->platform = hwpm_linux->device_info.platform; tegra_hwpm_dbg(hwpm, hwpm_info | hwpm_dbg_device_info, "chip id 0x%x", device_info->chip); @@ -227,11 +238,6 @@ static int tegra_hwpm_update_get_put_ioctl(struct tegra_soc_hwpm *hwpm, " after the BIND IOCTL."); return -EPERM; } - if (!hwpm->mem_mgmt->mem_bytes_kernel) { - tegra_hwpm_err(hwpm, - "mem_bytes buffer is not mapped in the driver"); - return -ENXIO; - } return tegra_hwpm_update_mem_bytes(hwpm, update_get_put); } @@ -275,7 +281,7 @@ static long tegra_hwpm_ioctl(struct file *file, } if (!(_IOC_DIR(cmd) & _IOC_NONE)) { - buf = kzalloc(TEGRA_SOC_HWPM_MAX_ARG_SIZE, GFP_KERNEL); + buf = tegra_hwpm_kzalloc(hwpm, TEGRA_SOC_HWPM_MAX_ARG_SIZE); if (!buf) { tegra_hwpm_err(hwpm, "Kernel buf allocation failed"); ret = -ENOMEM; @@ -343,7 +349,7 @@ static long tegra_hwpm_ioctl(struct file *file, fail: if (buf) { - kfree(buf); + tegra_hwpm_kfree(hwpm, buf); } if (ret < 0) { @@ -360,51 +366,55 @@ static int tegra_hwpm_open(struct inode *inode, struct file *filp) int ret = 0; unsigned int minor; struct tegra_soc_hwpm *hwpm = NULL; + struct tegra_hwpm_os_linux *hwpm_linux = NULL; if (!inode) { - tegra_hwpm_err(hwpm, "Invalid inode"); + tegra_hwpm_err(NULL, "Invalid inode"); return -EINVAL; } if (!filp) { - tegra_hwpm_err(hwpm, "Invalid file"); + tegra_hwpm_err(NULL, "Invalid file"); return -EINVAL; } minor = iminor(inode); if (minor > 0) { - tegra_hwpm_err(hwpm, "Incorrect minor number"); + tegra_hwpm_err(NULL, "Incorrect minor number"); return -EBADFD; } - hwpm = container_of(inode->i_cdev, struct tegra_soc_hwpm, cdev); - if (!hwpm) { - tegra_hwpm_err(hwpm, "Invalid hwpm struct"); + hwpm_linux = + container_of(inode->i_cdev, struct tegra_hwpm_os_linux, cdev); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, "Invalid hwpm_linux struct"); return -EINVAL; } + hwpm = &hwpm_linux->hwpm; filp->private_data = hwpm; tegra_hwpm_fn(hwpm, " "); /* Initialize driver on first open call only */ - if (!atomic_add_unless(&hwpm->hwpm_in_use, 1U, 1U)) { + if (!atomic_add_unless(&hwpm_linux->usage_count.var, 1U, 1U)) { return -EAGAIN; } if (tegra_hwpm_is_platform_silicon()) { - ret = reset_control_assert(hwpm->hwpm_rst); + ret = reset_control_assert(hwpm_linux->hwpm_rst); if (ret < 0) { tegra_hwpm_err(hwpm, "hwpm reset assert failed"); goto fail; } - ret = reset_control_assert(hwpm->la_rst); + ret = reset_control_assert(hwpm_linux->la_rst); if (ret < 0) { tegra_hwpm_err(hwpm, "la reset assert failed"); goto fail; } /* Set required parent for la_clk */ - if (hwpm->la_clk && hwpm->la_parent_clk) { - ret = clk_set_parent(hwpm->la_clk, hwpm->la_parent_clk); + if (hwpm_linux->la_clk && hwpm_linux->la_parent_clk) { + ret = clk_set_parent( + hwpm_linux->la_clk, hwpm_linux->la_parent_clk); if (ret < 0) { tegra_hwpm_err(hwpm, "la clk set parent failed"); @@ -412,22 +422,22 @@ static int tegra_hwpm_open(struct inode *inode, struct file *filp) } } /* set la_clk rate to 625 MHZ */ - ret = clk_set_rate(hwpm->la_clk, LA_CLK_RATE); + ret = clk_set_rate(hwpm_linux->la_clk, LA_CLK_RATE); if (ret < 0) { tegra_hwpm_err(hwpm, "la clock set rate failed"); goto fail; } - ret = clk_prepare_enable(hwpm->la_clk); + ret = clk_prepare_enable(hwpm_linux->la_clk); if (ret < 0) { tegra_hwpm_err(hwpm, "la clock enable failed"); goto fail; } - ret = reset_control_deassert(hwpm->la_rst); + ret = reset_control_deassert(hwpm_linux->la_rst); if (ret < 0) { tegra_hwpm_err(hwpm, "la reset deassert failed"); goto fail; } - ret = reset_control_deassert(hwpm->hwpm_rst); + ret = reset_control_deassert(hwpm_linux->hwpm_rst); if (ret < 0) { tegra_hwpm_err(hwpm, "hwpm reset deassert failed"); goto fail; @@ -471,25 +481,33 @@ static ssize_t tegra_hwpm_read(struct file *file, static int tegra_hwpm_release(struct inode *inode, struct file *filp) { int ret = 0, err = 0; + struct tegra_hwpm_os_linux *hwpm_linux = NULL; struct tegra_soc_hwpm *hwpm = NULL; if (!inode) { - tegra_hwpm_err(hwpm, "Invalid inode"); + tegra_hwpm_err(NULL, "Invalid inode"); return -EINVAL; } if (!filp) { - tegra_hwpm_err(hwpm, "Invalid file"); + tegra_hwpm_err(NULL, "Invalid file"); return -EINVAL; } - hwpm = container_of(inode->i_cdev, struct tegra_soc_hwpm, cdev); - if (!hwpm) { - tegra_hwpm_err(hwpm, "Invalid hwpm struct"); + hwpm_linux = + container_of(inode->i_cdev, struct tegra_hwpm_os_linux, cdev); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, "Invalid hwpm_linux struct"); return -EINVAL; } + hwpm = &hwpm_linux->hwpm; tegra_hwpm_fn(hwpm, " "); + /* De-init driver on last close call only */ + if (!atomic_dec_and_test(&hwpm_linux->usage_count.var)) { + return 0; + } + if (hwpm->device_opened == false) { /* Device was not opened, do nothing */ return 0; @@ -528,24 +546,19 @@ static int tegra_hwpm_release(struct inode *inode, struct file *filp) } if (tegra_hwpm_is_platform_silicon()) { - ret = reset_control_assert(hwpm->hwpm_rst); + ret = reset_control_assert(hwpm_linux->hwpm_rst); if (ret < 0) { tegra_hwpm_err(hwpm, "hwpm reset assert failed"); err = ret; goto fail; } - ret = reset_control_assert(hwpm->la_rst); + ret = reset_control_assert(hwpm_linux->la_rst); if (ret < 0) { tegra_hwpm_err(hwpm, "la reset assert failed"); err = ret; goto fail; } - clk_disable_unprepare(hwpm->la_clk); - } - - /* De-init driver on last close call only */ - if (!atomic_dec_and_test(&hwpm->hwpm_in_use)) { - return 0; + clk_disable_unprepare(hwpm_linux->la_clk); } hwpm->device_opened = false; @@ -554,7 +567,7 @@ fail: } /* File ops for device node */ -const struct file_operations tegra_soc_hwpm_ops = { +const struct file_operations tegra_hwpm_ops = { .owner = THIS_MODULE, .open = tegra_hwpm_open, .read = tegra_hwpm_read, diff --git a/os/linux/ip_utils.c b/os/linux/ip_utils.c index 7a5e5d0..e7d6aa4 100644 --- a/os/linux/ip_utils.c +++ b/os/linux/ip_utils.c @@ -34,7 +34,8 @@ static int tegra_hwpm_alloc_ip_register_list_node( { struct hwpm_ip_register_list *new_node = NULL; - new_node = kzalloc(sizeof(struct hwpm_ip_register_list), GFP_KERNEL); + new_node = tegra_hwpm_kzalloc(NULL, + sizeof(struct hwpm_ip_register_list)); if (new_node == NULL) { tegra_hwpm_err(NULL, "struct hwpm_ip_register_list node allocation failed"); diff --git a/os/linux/mem_mgmt_utils.c b/os/linux/mem_mgmt_utils.c index cb11300..e31e842 100644 --- a/os/linux/mem_mgmt_utils.c +++ b/os/linux/mem_mgmt_utils.c @@ -31,11 +31,21 @@ #include #include +#include + static int tegra_hwpm_dma_map_stream_buffer(struct tegra_soc_hwpm *hwpm, struct tegra_soc_hwpm_alloc_pma_stream *alloc_pma_stream) { + struct tegra_hwpm_os_linux *hwpm_linux = NULL; + tegra_hwpm_fn(hwpm, " "); + hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, "Invalid hwpm_linux struct"); + return -ENODEV; + } + hwpm->mem_mgmt->stream_buf_size = alloc_pma_stream->stream_buf_size; hwpm->mem_mgmt->stream_dma_buf = dma_buf_get(tegra_hwpm_safe_cast_u64_to_s32( @@ -45,7 +55,7 @@ static int tegra_hwpm_dma_map_stream_buffer(struct tegra_soc_hwpm *hwpm, return PTR_ERR(hwpm->mem_mgmt->stream_dma_buf); } hwpm->mem_mgmt->stream_attach = - dma_buf_attach(hwpm->mem_mgmt->stream_dma_buf, hwpm->dev); + dma_buf_attach(hwpm->mem_mgmt->stream_dma_buf, hwpm_linux->dev); if (IS_ERR(hwpm->mem_mgmt->stream_attach)) { tegra_hwpm_err(hwpm, "Unable to attach stream dma_buf"); return PTR_ERR(hwpm->mem_mgmt->stream_attach); @@ -74,8 +84,16 @@ static int tegra_hwpm_dma_map_stream_buffer(struct tegra_soc_hwpm *hwpm, static int tegra_hwpm_dma_map_mem_bytes_buffer(struct tegra_soc_hwpm *hwpm, struct tegra_soc_hwpm_alloc_pma_stream *alloc_pma_stream) { + struct tegra_hwpm_os_linux *hwpm_linux = NULL; + tegra_hwpm_fn(hwpm, " "); + hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm); + if (!hwpm_linux) { + tegra_hwpm_err(NULL, "Invalid hwpm_linux struct"); + return -ENODEV; + } + hwpm->mem_mgmt->mem_bytes_dma_buf = dma_buf_get(tegra_hwpm_safe_cast_u64_to_s32( alloc_pma_stream->mem_bytes_buf_fd)); @@ -85,7 +103,7 @@ static int tegra_hwpm_dma_map_mem_bytes_buffer(struct tegra_soc_hwpm *hwpm, } hwpm->mem_mgmt->mem_bytes_attach = dma_buf_attach( - hwpm->mem_mgmt->mem_bytes_dma_buf, hwpm->dev); + hwpm->mem_mgmt->mem_bytes_dma_buf, hwpm_linux->dev); if (IS_ERR(hwpm->mem_mgmt->mem_bytes_attach)) { tegra_hwpm_err(hwpm, "Unable to attach mem bytes dma_buf"); return PTR_ERR(hwpm->mem_mgmt->mem_bytes_attach);