162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci * Copyright 2016-2022 HabanaLabs, Ltd.
562306a36Sopenharmony_ci * All Rights Reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt)	"habanalabs: " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <uapi/drm/habanalabs_accel.h>
1162306a36Sopenharmony_ci#include "habanalabs.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/fs.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/pci.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/uaccess.h>
1862306a36Sopenharmony_ci#include <linux/vmalloc.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic u32 hl_debug_struct_size[HL_DEBUG_OP_TIMESTAMP + 1] = {
2162306a36Sopenharmony_ci	[HL_DEBUG_OP_ETR] = sizeof(struct hl_debug_params_etr),
2262306a36Sopenharmony_ci	[HL_DEBUG_OP_ETF] = sizeof(struct hl_debug_params_etf),
2362306a36Sopenharmony_ci	[HL_DEBUG_OP_STM] = sizeof(struct hl_debug_params_stm),
2462306a36Sopenharmony_ci	[HL_DEBUG_OP_FUNNEL] = 0,
2562306a36Sopenharmony_ci	[HL_DEBUG_OP_BMON] = sizeof(struct hl_debug_params_bmon),
2662306a36Sopenharmony_ci	[HL_DEBUG_OP_SPMU] = sizeof(struct hl_debug_params_spmu),
2762306a36Sopenharmony_ci	[HL_DEBUG_OP_TIMESTAMP] = 0
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int device_status_info(struct hl_device *hdev, struct hl_info_args *args)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct hl_info_device_status dev_stat = {0};
3462306a36Sopenharmony_ci	u32 size = args->return_size;
3562306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if ((!size) || (!out))
3862306a36Sopenharmony_ci		return -EINVAL;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	dev_stat.status = hl_device_status(hdev);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return copy_to_user(out, &dev_stat,
4362306a36Sopenharmony_ci			min((size_t)size, sizeof(dev_stat))) ? -EFAULT : 0;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct hl_info_hw_ip_info hw_ip = {0};
4962306a36Sopenharmony_ci	u32 size = args->return_size;
5062306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
5162306a36Sopenharmony_ci	struct asic_fixed_properties *prop = &hdev->asic_prop;
5262306a36Sopenharmony_ci	u64 sram_kmd_size, dram_kmd_size, dram_available_size;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if ((!size) || (!out))
5562306a36Sopenharmony_ci		return -EINVAL;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	sram_kmd_size = (prop->sram_user_base_address -
5862306a36Sopenharmony_ci				prop->sram_base_address);
5962306a36Sopenharmony_ci	dram_kmd_size = (prop->dram_user_base_address -
6062306a36Sopenharmony_ci				prop->dram_base_address);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	hw_ip.device_id = hdev->asic_funcs->get_pci_id(hdev);
6362306a36Sopenharmony_ci	hw_ip.sram_base_address = prop->sram_user_base_address;
6462306a36Sopenharmony_ci	hw_ip.dram_base_address =
6562306a36Sopenharmony_ci			prop->dram_supports_virtual_memory ?
6662306a36Sopenharmony_ci			prop->dmmu.start_addr : prop->dram_user_base_address;
6762306a36Sopenharmony_ci	hw_ip.tpc_enabled_mask = prop->tpc_enabled_mask & 0xFF;
6862306a36Sopenharmony_ci	hw_ip.tpc_enabled_mask_ext = prop->tpc_enabled_mask;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	hw_ip.sram_size = prop->sram_size - sram_kmd_size;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	dram_available_size = prop->dram_size - dram_kmd_size;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	hw_ip.dram_size = DIV_ROUND_DOWN_ULL(dram_available_size, prop->dram_page_size) *
7562306a36Sopenharmony_ci				prop->dram_page_size;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (hw_ip.dram_size > PAGE_SIZE)
7862306a36Sopenharmony_ci		hw_ip.dram_enabled = 1;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	hw_ip.dram_page_size = prop->dram_page_size;
8162306a36Sopenharmony_ci	hw_ip.device_mem_alloc_default_page_size = prop->device_mem_alloc_default_page_size;
8262306a36Sopenharmony_ci	hw_ip.num_of_events = prop->num_of_events;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	memcpy(hw_ip.cpucp_version, prop->cpucp_info.cpucp_version,
8562306a36Sopenharmony_ci		min(VERSION_MAX_LEN, HL_INFO_VERSION_MAX_LEN));
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	memcpy(hw_ip.card_name, prop->cpucp_info.card_name,
8862306a36Sopenharmony_ci		min(CARD_NAME_MAX_LEN, HL_INFO_CARD_NAME_MAX_LEN));
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	hw_ip.cpld_version = le32_to_cpu(prop->cpucp_info.cpld_version);
9162306a36Sopenharmony_ci	hw_ip.module_id = le32_to_cpu(prop->cpucp_info.card_location);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	hw_ip.psoc_pci_pll_nr = prop->psoc_pci_pll_nr;
9462306a36Sopenharmony_ci	hw_ip.psoc_pci_pll_nf = prop->psoc_pci_pll_nf;
9562306a36Sopenharmony_ci	hw_ip.psoc_pci_pll_od = prop->psoc_pci_pll_od;
9662306a36Sopenharmony_ci	hw_ip.psoc_pci_pll_div_factor = prop->psoc_pci_pll_div_factor;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	hw_ip.decoder_enabled_mask = prop->decoder_enabled_mask;
9962306a36Sopenharmony_ci	hw_ip.mme_master_slave_mode = prop->mme_master_slave_mode;
10062306a36Sopenharmony_ci	hw_ip.first_available_interrupt_id = prop->first_available_user_interrupt;
10162306a36Sopenharmony_ci	hw_ip.number_of_user_interrupts = prop->user_interrupt_count;
10262306a36Sopenharmony_ci	hw_ip.tpc_interrupt_id = prop->tpc_interrupt_id;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	hw_ip.edma_enabled_mask = prop->edma_enabled_mask;
10562306a36Sopenharmony_ci	hw_ip.server_type = prop->server_type;
10662306a36Sopenharmony_ci	hw_ip.security_enabled = prop->fw_security_enabled;
10762306a36Sopenharmony_ci	hw_ip.revision_id = hdev->pdev->revision;
10862306a36Sopenharmony_ci	hw_ip.rotator_enabled_mask = prop->rotator_enabled_mask;
10962306a36Sopenharmony_ci	hw_ip.engine_core_interrupt_reg_addr = prop->engine_core_interrupt_reg_addr;
11062306a36Sopenharmony_ci	hw_ip.reserved_dram_size = dram_kmd_size;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return copy_to_user(out, &hw_ip,
11362306a36Sopenharmony_ci		min((size_t) size, sizeof(hw_ip))) ? -EFAULT : 0;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int hw_events_info(struct hl_device *hdev, bool aggregate,
11762306a36Sopenharmony_ci			struct hl_info_args *args)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	u32 size, max_size = args->return_size;
12062306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
12162306a36Sopenharmony_ci	void *arr;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if ((!max_size) || (!out))
12462306a36Sopenharmony_ci		return -EINVAL;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	arr = hdev->asic_funcs->get_events_stat(hdev, aggregate, &size);
12762306a36Sopenharmony_ci	if (!arr) {
12862306a36Sopenharmony_ci		dev_err(hdev->dev, "Events info not supported\n");
12962306a36Sopenharmony_ci		return -EOPNOTSUPP;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return copy_to_user(out, arr, min(max_size, size)) ? -EFAULT : 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int events_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	u32 max_size = args->return_size;
13862306a36Sopenharmony_ci	u64 events_mask;
13962306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if ((max_size < sizeof(u64)) || (!out))
14262306a36Sopenharmony_ci		return -EINVAL;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	mutex_lock(&hpriv->notifier_event.lock);
14562306a36Sopenharmony_ci	events_mask = hpriv->notifier_event.events_mask;
14662306a36Sopenharmony_ci	hpriv->notifier_event.events_mask = 0;
14762306a36Sopenharmony_ci	mutex_unlock(&hpriv->notifier_event.lock);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return copy_to_user(out, &events_mask, sizeof(u64)) ? -EFAULT : 0;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int dram_usage_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
15562306a36Sopenharmony_ci	struct hl_info_dram_usage dram_usage = {0};
15662306a36Sopenharmony_ci	u32 max_size = args->return_size;
15762306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
15862306a36Sopenharmony_ci	struct asic_fixed_properties *prop = &hdev->asic_prop;
15962306a36Sopenharmony_ci	u64 dram_kmd_size;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if ((!max_size) || (!out))
16262306a36Sopenharmony_ci		return -EINVAL;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	dram_kmd_size = (prop->dram_user_base_address -
16562306a36Sopenharmony_ci				prop->dram_base_address);
16662306a36Sopenharmony_ci	dram_usage.dram_free_mem = (prop->dram_size - dram_kmd_size) -
16762306a36Sopenharmony_ci					atomic64_read(&hdev->dram_used_mem);
16862306a36Sopenharmony_ci	if (hpriv->ctx)
16962306a36Sopenharmony_ci		dram_usage.ctx_dram_mem =
17062306a36Sopenharmony_ci			atomic64_read(&hpriv->ctx->dram_phys_mem);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return copy_to_user(out, &dram_usage,
17362306a36Sopenharmony_ci		min((size_t) max_size, sizeof(dram_usage))) ? -EFAULT : 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int hw_idle(struct hl_device *hdev, struct hl_info_args *args)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct hl_info_hw_idle hw_idle = {0};
17962306a36Sopenharmony_ci	u32 max_size = args->return_size;
18062306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if ((!max_size) || (!out))
18362306a36Sopenharmony_ci		return -EINVAL;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev,
18662306a36Sopenharmony_ci					hw_idle.busy_engines_mask_ext,
18762306a36Sopenharmony_ci					HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL);
18862306a36Sopenharmony_ci	hw_idle.busy_engines_mask =
18962306a36Sopenharmony_ci			lower_32_bits(hw_idle.busy_engines_mask_ext[0]);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return copy_to_user(out, &hw_idle,
19262306a36Sopenharmony_ci		min((size_t) max_size, sizeof(hw_idle))) ? -EFAULT : 0;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int debug_coresight(struct hl_device *hdev, struct hl_ctx *ctx, struct hl_debug_args *args)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct hl_debug_params *params;
19862306a36Sopenharmony_ci	void *input = NULL, *output = NULL;
19962306a36Sopenharmony_ci	int rc;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	params = kzalloc(sizeof(*params), GFP_KERNEL);
20262306a36Sopenharmony_ci	if (!params)
20362306a36Sopenharmony_ci		return -ENOMEM;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	params->reg_idx = args->reg_idx;
20662306a36Sopenharmony_ci	params->enable = args->enable;
20762306a36Sopenharmony_ci	params->op = args->op;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (args->input_ptr && args->input_size) {
21062306a36Sopenharmony_ci		input = kzalloc(hl_debug_struct_size[args->op], GFP_KERNEL);
21162306a36Sopenharmony_ci		if (!input) {
21262306a36Sopenharmony_ci			rc = -ENOMEM;
21362306a36Sopenharmony_ci			goto out;
21462306a36Sopenharmony_ci		}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		if (copy_from_user(input, u64_to_user_ptr(args->input_ptr),
21762306a36Sopenharmony_ci					args->input_size)) {
21862306a36Sopenharmony_ci			rc = -EFAULT;
21962306a36Sopenharmony_ci			dev_err(hdev->dev, "failed to copy input debug data\n");
22062306a36Sopenharmony_ci			goto out;
22162306a36Sopenharmony_ci		}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		params->input = input;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (args->output_ptr && args->output_size) {
22762306a36Sopenharmony_ci		output = kzalloc(args->output_size, GFP_KERNEL);
22862306a36Sopenharmony_ci		if (!output) {
22962306a36Sopenharmony_ci			rc = -ENOMEM;
23062306a36Sopenharmony_ci			goto out;
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		params->output = output;
23462306a36Sopenharmony_ci		params->output_size = args->output_size;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	rc = hdev->asic_funcs->debug_coresight(hdev, ctx, params);
23862306a36Sopenharmony_ci	if (rc) {
23962306a36Sopenharmony_ci		dev_err(hdev->dev,
24062306a36Sopenharmony_ci			"debug coresight operation failed %d\n", rc);
24162306a36Sopenharmony_ci		goto out;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (output && copy_to_user((void __user *) (uintptr_t) args->output_ptr,
24562306a36Sopenharmony_ci					output, args->output_size)) {
24662306a36Sopenharmony_ci		dev_err(hdev->dev, "copy to user failed in debug ioctl\n");
24762306a36Sopenharmony_ci		rc = -EFAULT;
24862306a36Sopenharmony_ci		goto out;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ciout:
25362306a36Sopenharmony_ci	kfree(params);
25462306a36Sopenharmony_ci	kfree(output);
25562306a36Sopenharmony_ci	kfree(input);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return rc;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int device_utilization(struct hl_device *hdev, struct hl_info_args *args)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct hl_info_device_utilization device_util = {0};
26362306a36Sopenharmony_ci	u32 max_size = args->return_size;
26462306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
26562306a36Sopenharmony_ci	int rc;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if ((!max_size) || (!out))
26862306a36Sopenharmony_ci		return -EINVAL;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	rc = hl_device_utilization(hdev, &device_util.utilization);
27162306a36Sopenharmony_ci	if (rc)
27262306a36Sopenharmony_ci		return -EINVAL;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	return copy_to_user(out, &device_util,
27562306a36Sopenharmony_ci		min((size_t) max_size, sizeof(device_util))) ? -EFAULT : 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic int get_clk_rate(struct hl_device *hdev, struct hl_info_args *args)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct hl_info_clk_rate clk_rate = {0};
28162306a36Sopenharmony_ci	u32 max_size = args->return_size;
28262306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
28362306a36Sopenharmony_ci	int rc;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if ((!max_size) || (!out))
28662306a36Sopenharmony_ci		return -EINVAL;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	rc = hl_fw_get_clk_rate(hdev, &clk_rate.cur_clk_rate_mhz, &clk_rate.max_clk_rate_mhz);
28962306a36Sopenharmony_ci	if (rc)
29062306a36Sopenharmony_ci		return rc;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return copy_to_user(out, &clk_rate, min_t(size_t, max_size, sizeof(clk_rate)))
29362306a36Sopenharmony_ci										? -EFAULT : 0;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int get_reset_count(struct hl_device *hdev, struct hl_info_args *args)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct hl_info_reset_count reset_count = {0};
29962306a36Sopenharmony_ci	u32 max_size = args->return_size;
30062306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if ((!max_size) || (!out))
30362306a36Sopenharmony_ci		return -EINVAL;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	reset_count.hard_reset_cnt = hdev->reset_info.hard_reset_cnt;
30662306a36Sopenharmony_ci	reset_count.soft_reset_cnt = hdev->reset_info.compute_reset_cnt;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return copy_to_user(out, &reset_count,
30962306a36Sopenharmony_ci		min((size_t) max_size, sizeof(reset_count))) ? -EFAULT : 0;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic int time_sync_info(struct hl_device *hdev, struct hl_info_args *args)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct hl_info_time_sync time_sync = {0};
31562306a36Sopenharmony_ci	u32 max_size = args->return_size;
31662306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if ((!max_size) || (!out))
31962306a36Sopenharmony_ci		return -EINVAL;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	time_sync.device_time = hdev->asic_funcs->get_device_time(hdev);
32262306a36Sopenharmony_ci	time_sync.host_time = ktime_get_raw_ns();
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	return copy_to_user(out, &time_sync,
32562306a36Sopenharmony_ci		min((size_t) max_size, sizeof(time_sync))) ? -EFAULT : 0;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int pci_counters_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
33162306a36Sopenharmony_ci	struct hl_info_pci_counters pci_counters = {0};
33262306a36Sopenharmony_ci	u32 max_size = args->return_size;
33362306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
33462306a36Sopenharmony_ci	int rc;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if ((!max_size) || (!out))
33762306a36Sopenharmony_ci		return -EINVAL;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	rc = hl_fw_cpucp_pci_counters_get(hdev, &pci_counters);
34062306a36Sopenharmony_ci	if (rc)
34162306a36Sopenharmony_ci		return rc;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return copy_to_user(out, &pci_counters,
34462306a36Sopenharmony_ci		min((size_t) max_size, sizeof(pci_counters))) ? -EFAULT : 0;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int clk_throttle_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
35062306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
35162306a36Sopenharmony_ci	struct hl_info_clk_throttle clk_throttle = {0};
35262306a36Sopenharmony_ci	ktime_t end_time, zero_time = ktime_set(0, 0);
35362306a36Sopenharmony_ci	u32 max_size = args->return_size;
35462306a36Sopenharmony_ci	int i;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if ((!max_size) || (!out))
35762306a36Sopenharmony_ci		return -EINVAL;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	mutex_lock(&hdev->clk_throttling.lock);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	clk_throttle.clk_throttling_reason = hdev->clk_throttling.current_reason;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	for (i = 0 ; i < HL_CLK_THROTTLE_TYPE_MAX ; i++) {
36462306a36Sopenharmony_ci		if (!(hdev->clk_throttling.aggregated_reason & BIT(i)))
36562306a36Sopenharmony_ci			continue;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		clk_throttle.clk_throttling_timestamp_us[i] =
36862306a36Sopenharmony_ci			ktime_to_us(hdev->clk_throttling.timestamp[i].start);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		if (ktime_compare(hdev->clk_throttling.timestamp[i].end, zero_time))
37162306a36Sopenharmony_ci			end_time = hdev->clk_throttling.timestamp[i].end;
37262306a36Sopenharmony_ci		else
37362306a36Sopenharmony_ci			end_time = ktime_get();
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		clk_throttle.clk_throttling_duration_ns[i] =
37662306a36Sopenharmony_ci			ktime_to_ns(ktime_sub(end_time,
37762306a36Sopenharmony_ci				hdev->clk_throttling.timestamp[i].start));
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	mutex_unlock(&hdev->clk_throttling.lock);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	return copy_to_user(out, &clk_throttle,
38362306a36Sopenharmony_ci		min((size_t) max_size, sizeof(clk_throttle))) ? -EFAULT : 0;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic int cs_counters_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
38962306a36Sopenharmony_ci	struct hl_info_cs_counters cs_counters = {0};
39062306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
39162306a36Sopenharmony_ci	struct hl_cs_counters_atomic *cntr;
39262306a36Sopenharmony_ci	u32 max_size = args->return_size;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	cntr = &hdev->aggregated_cs_counters;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if ((!max_size) || (!out))
39762306a36Sopenharmony_ci		return -EINVAL;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	cs_counters.total_out_of_mem_drop_cnt =
40062306a36Sopenharmony_ci			atomic64_read(&cntr->out_of_mem_drop_cnt);
40162306a36Sopenharmony_ci	cs_counters.total_parsing_drop_cnt =
40262306a36Sopenharmony_ci			atomic64_read(&cntr->parsing_drop_cnt);
40362306a36Sopenharmony_ci	cs_counters.total_queue_full_drop_cnt =
40462306a36Sopenharmony_ci			atomic64_read(&cntr->queue_full_drop_cnt);
40562306a36Sopenharmony_ci	cs_counters.total_device_in_reset_drop_cnt =
40662306a36Sopenharmony_ci			atomic64_read(&cntr->device_in_reset_drop_cnt);
40762306a36Sopenharmony_ci	cs_counters.total_max_cs_in_flight_drop_cnt =
40862306a36Sopenharmony_ci			atomic64_read(&cntr->max_cs_in_flight_drop_cnt);
40962306a36Sopenharmony_ci	cs_counters.total_validation_drop_cnt =
41062306a36Sopenharmony_ci			atomic64_read(&cntr->validation_drop_cnt);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (hpriv->ctx) {
41362306a36Sopenharmony_ci		cs_counters.ctx_out_of_mem_drop_cnt =
41462306a36Sopenharmony_ci				atomic64_read(
41562306a36Sopenharmony_ci				&hpriv->ctx->cs_counters.out_of_mem_drop_cnt);
41662306a36Sopenharmony_ci		cs_counters.ctx_parsing_drop_cnt =
41762306a36Sopenharmony_ci				atomic64_read(
41862306a36Sopenharmony_ci				&hpriv->ctx->cs_counters.parsing_drop_cnt);
41962306a36Sopenharmony_ci		cs_counters.ctx_queue_full_drop_cnt =
42062306a36Sopenharmony_ci				atomic64_read(
42162306a36Sopenharmony_ci				&hpriv->ctx->cs_counters.queue_full_drop_cnt);
42262306a36Sopenharmony_ci		cs_counters.ctx_device_in_reset_drop_cnt =
42362306a36Sopenharmony_ci				atomic64_read(
42462306a36Sopenharmony_ci			&hpriv->ctx->cs_counters.device_in_reset_drop_cnt);
42562306a36Sopenharmony_ci		cs_counters.ctx_max_cs_in_flight_drop_cnt =
42662306a36Sopenharmony_ci				atomic64_read(
42762306a36Sopenharmony_ci			&hpriv->ctx->cs_counters.max_cs_in_flight_drop_cnt);
42862306a36Sopenharmony_ci		cs_counters.ctx_validation_drop_cnt =
42962306a36Sopenharmony_ci				atomic64_read(
43062306a36Sopenharmony_ci				&hpriv->ctx->cs_counters.validation_drop_cnt);
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return copy_to_user(out, &cs_counters,
43462306a36Sopenharmony_ci		min((size_t) max_size, sizeof(cs_counters))) ? -EFAULT : 0;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int sync_manager_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
44062306a36Sopenharmony_ci	struct asic_fixed_properties *prop = &hdev->asic_prop;
44162306a36Sopenharmony_ci	struct hl_info_sync_manager sm_info = {0};
44262306a36Sopenharmony_ci	u32 max_size = args->return_size;
44362306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if ((!max_size) || (!out))
44662306a36Sopenharmony_ci		return -EINVAL;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (args->dcore_id >= HL_MAX_DCORES)
44962306a36Sopenharmony_ci		return -EINVAL;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	sm_info.first_available_sync_object =
45262306a36Sopenharmony_ci			prop->first_available_user_sob[args->dcore_id];
45362306a36Sopenharmony_ci	sm_info.first_available_monitor =
45462306a36Sopenharmony_ci			prop->first_available_user_mon[args->dcore_id];
45562306a36Sopenharmony_ci	sm_info.first_available_cq =
45662306a36Sopenharmony_ci			prop->first_available_cq[args->dcore_id];
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return copy_to_user(out, &sm_info, min_t(size_t, (size_t) max_size,
45962306a36Sopenharmony_ci			sizeof(sm_info))) ? -EFAULT : 0;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic int total_energy_consumption_info(struct hl_fpriv *hpriv,
46362306a36Sopenharmony_ci			struct hl_info_args *args)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
46662306a36Sopenharmony_ci	struct hl_info_energy total_energy = {0};
46762306a36Sopenharmony_ci	u32 max_size = args->return_size;
46862306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
46962306a36Sopenharmony_ci	int rc;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if ((!max_size) || (!out))
47262306a36Sopenharmony_ci		return -EINVAL;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	rc = hl_fw_cpucp_total_energy_get(hdev,
47562306a36Sopenharmony_ci			&total_energy.total_energy_consumption);
47662306a36Sopenharmony_ci	if (rc)
47762306a36Sopenharmony_ci		return rc;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return copy_to_user(out, &total_energy,
48062306a36Sopenharmony_ci		min((size_t) max_size, sizeof(total_energy))) ? -EFAULT : 0;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic int pll_frequency_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
48662306a36Sopenharmony_ci	struct hl_pll_frequency_info freq_info = { {0} };
48762306a36Sopenharmony_ci	u32 max_size = args->return_size;
48862306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
48962306a36Sopenharmony_ci	int rc;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if ((!max_size) || (!out))
49262306a36Sopenharmony_ci		return -EINVAL;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	rc = hl_fw_cpucp_pll_info_get(hdev, args->pll_index, freq_info.output);
49562306a36Sopenharmony_ci	if (rc)
49662306a36Sopenharmony_ci		return rc;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return copy_to_user(out, &freq_info,
49962306a36Sopenharmony_ci		min((size_t) max_size, sizeof(freq_info))) ? -EFAULT : 0;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic int power_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
50562306a36Sopenharmony_ci	u32 max_size = args->return_size;
50662306a36Sopenharmony_ci	struct hl_power_info power_info = {0};
50762306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
50862306a36Sopenharmony_ci	int rc;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if ((!max_size) || (!out))
51162306a36Sopenharmony_ci		return -EINVAL;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	rc = hl_fw_cpucp_power_get(hdev, &power_info.power);
51462306a36Sopenharmony_ci	if (rc)
51562306a36Sopenharmony_ci		return rc;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	return copy_to_user(out, &power_info,
51862306a36Sopenharmony_ci		min((size_t) max_size, sizeof(power_info))) ? -EFAULT : 0;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic int open_stats_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
52462306a36Sopenharmony_ci	u32 max_size = args->return_size;
52562306a36Sopenharmony_ci	struct hl_open_stats_info open_stats_info = {0};
52662306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if ((!max_size) || (!out))
52962306a36Sopenharmony_ci		return -EINVAL;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	open_stats_info.last_open_period_ms = jiffies64_to_msecs(
53262306a36Sopenharmony_ci		hdev->last_open_session_duration_jif);
53362306a36Sopenharmony_ci	open_stats_info.open_counter = hdev->open_counter;
53462306a36Sopenharmony_ci	open_stats_info.is_compute_ctx_active = hdev->is_compute_ctx_active;
53562306a36Sopenharmony_ci	open_stats_info.compute_ctx_in_release = hdev->compute_ctx_in_release;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return copy_to_user(out, &open_stats_info,
53862306a36Sopenharmony_ci		min((size_t) max_size, sizeof(open_stats_info))) ? -EFAULT : 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic int dram_pending_rows_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
54462306a36Sopenharmony_ci	u32 max_size = args->return_size;
54562306a36Sopenharmony_ci	u32 pend_rows_num = 0;
54662306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
54762306a36Sopenharmony_ci	int rc;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if ((!max_size) || (!out))
55062306a36Sopenharmony_ci		return -EINVAL;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	rc = hl_fw_dram_pending_row_get(hdev, &pend_rows_num);
55362306a36Sopenharmony_ci	if (rc)
55462306a36Sopenharmony_ci		return rc;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	return copy_to_user(out, &pend_rows_num,
55762306a36Sopenharmony_ci			min_t(size_t, max_size, sizeof(pend_rows_num))) ? -EFAULT : 0;
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic int dram_replaced_rows_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
56362306a36Sopenharmony_ci	u32 max_size = args->return_size;
56462306a36Sopenharmony_ci	struct cpucp_hbm_row_info info = {0};
56562306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
56662306a36Sopenharmony_ci	int rc;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	if ((!max_size) || (!out))
56962306a36Sopenharmony_ci		return -EINVAL;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	rc = hl_fw_dram_replaced_row_get(hdev, &info);
57262306a36Sopenharmony_ci	if (rc)
57362306a36Sopenharmony_ci		return rc;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic int last_err_open_dev_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct hl_info_last_err_open_dev_time info = {0};
58162306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
58262306a36Sopenharmony_ci	u32 max_size = args->return_size;
58362306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if ((!max_size) || (!out))
58662306a36Sopenharmony_ci		return -EINVAL;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	info.timestamp = ktime_to_ns(hdev->last_successful_open_ktime);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic int cs_timeout_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	struct hl_info_cs_timeout_event info = {0};
59662306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
59762306a36Sopenharmony_ci	u32 max_size = args->return_size;
59862306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if ((!max_size) || (!out))
60162306a36Sopenharmony_ci		return -EINVAL;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	info.seq = hdev->captured_err_info.cs_timeout.seq;
60462306a36Sopenharmony_ci	info.timestamp = ktime_to_ns(hdev->captured_err_info.cs_timeout.timestamp);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic int razwi_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
61262306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
61362306a36Sopenharmony_ci	u32 max_size = args->return_size;
61462306a36Sopenharmony_ci	struct razwi_info *razwi_info;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if ((!max_size) || (!out))
61762306a36Sopenharmony_ci		return -EINVAL;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	razwi_info = &hdev->captured_err_info.razwi_info;
62062306a36Sopenharmony_ci	if (!razwi_info->razwi_info_available)
62162306a36Sopenharmony_ci		return 0;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	return copy_to_user(out, &razwi_info->razwi,
62462306a36Sopenharmony_ci			min_t(size_t, max_size, sizeof(struct hl_info_razwi_event))) ? -EFAULT : 0;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic int undefined_opcode_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
63062306a36Sopenharmony_ci	u32 max_size = args->return_size;
63162306a36Sopenharmony_ci	struct hl_info_undefined_opcode_event info = {0};
63262306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if ((!max_size) || (!out))
63562306a36Sopenharmony_ci		return -EINVAL;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	info.timestamp = ktime_to_ns(hdev->captured_err_info.undef_opcode.timestamp);
63862306a36Sopenharmony_ci	info.engine_id = hdev->captured_err_info.undef_opcode.engine_id;
63962306a36Sopenharmony_ci	info.cq_addr = hdev->captured_err_info.undef_opcode.cq_addr;
64062306a36Sopenharmony_ci	info.cq_size = hdev->captured_err_info.undef_opcode.cq_size;
64162306a36Sopenharmony_ci	info.stream_id = hdev->captured_err_info.undef_opcode.stream_id;
64262306a36Sopenharmony_ci	info.cb_addr_streams_len = hdev->captured_err_info.undef_opcode.cb_addr_streams_len;
64362306a36Sopenharmony_ci	memcpy(info.cb_addr_streams, hdev->captured_err_info.undef_opcode.cb_addr_streams,
64462306a36Sopenharmony_ci			sizeof(info.cb_addr_streams));
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic int dev_mem_alloc_page_sizes_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
65262306a36Sopenharmony_ci	struct hl_info_dev_memalloc_page_sizes info = {0};
65362306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
65462306a36Sopenharmony_ci	u32 max_size = args->return_size;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if ((!max_size) || (!out))
65762306a36Sopenharmony_ci		return -EINVAL;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	/*
66062306a36Sopenharmony_ci	 * Future ASICs that will support multiple DRAM page sizes will support only "powers of 2"
66162306a36Sopenharmony_ci	 * pages (unlike some of the ASICs before supporting multiple page sizes).
66262306a36Sopenharmony_ci	 * For this reason for all ASICs that not support multiple page size the function will
66362306a36Sopenharmony_ci	 * return an empty bitmask indicating that multiple page sizes is not supported.
66462306a36Sopenharmony_ci	 */
66562306a36Sopenharmony_ci	info.page_order_bitmask = hdev->asic_prop.dmmu.supported_pages_mask;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic int sec_attest_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
67362306a36Sopenharmony_ci	struct cpucp_sec_attest_info *sec_attest_info;
67462306a36Sopenharmony_ci	struct hl_info_sec_attest *info;
67562306a36Sopenharmony_ci	u32 max_size = args->return_size;
67662306a36Sopenharmony_ci	int rc;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if ((!max_size) || (!out))
67962306a36Sopenharmony_ci		return -EINVAL;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	sec_attest_info = kmalloc(sizeof(*sec_attest_info), GFP_KERNEL);
68262306a36Sopenharmony_ci	if (!sec_attest_info)
68362306a36Sopenharmony_ci		return -ENOMEM;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	info = kzalloc(sizeof(*info), GFP_KERNEL);
68662306a36Sopenharmony_ci	if (!info) {
68762306a36Sopenharmony_ci		rc = -ENOMEM;
68862306a36Sopenharmony_ci		goto free_sec_attest_info;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	rc = hl_fw_get_sec_attest_info(hpriv->hdev, sec_attest_info, args->sec_attest_nonce);
69262306a36Sopenharmony_ci	if (rc)
69362306a36Sopenharmony_ci		goto free_info;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	info->nonce = le32_to_cpu(sec_attest_info->nonce);
69662306a36Sopenharmony_ci	info->pcr_quote_len = le16_to_cpu(sec_attest_info->pcr_quote_len);
69762306a36Sopenharmony_ci	info->pub_data_len = le16_to_cpu(sec_attest_info->pub_data_len);
69862306a36Sopenharmony_ci	info->certificate_len = le16_to_cpu(sec_attest_info->certificate_len);
69962306a36Sopenharmony_ci	info->pcr_num_reg = sec_attest_info->pcr_num_reg;
70062306a36Sopenharmony_ci	info->pcr_reg_len = sec_attest_info->pcr_reg_len;
70162306a36Sopenharmony_ci	info->quote_sig_len = sec_attest_info->quote_sig_len;
70262306a36Sopenharmony_ci	memcpy(&info->pcr_data, &sec_attest_info->pcr_data, sizeof(info->pcr_data));
70362306a36Sopenharmony_ci	memcpy(&info->pcr_quote, &sec_attest_info->pcr_quote, sizeof(info->pcr_quote));
70462306a36Sopenharmony_ci	memcpy(&info->public_data, &sec_attest_info->public_data, sizeof(info->public_data));
70562306a36Sopenharmony_ci	memcpy(&info->certificate, &sec_attest_info->certificate, sizeof(info->certificate));
70662306a36Sopenharmony_ci	memcpy(&info->quote_sig, &sec_attest_info->quote_sig, sizeof(info->quote_sig));
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	rc = copy_to_user(out, info,
70962306a36Sopenharmony_ci				min_t(size_t, max_size, sizeof(*info))) ? -EFAULT : 0;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cifree_info:
71262306a36Sopenharmony_ci	kfree(info);
71362306a36Sopenharmony_cifree_sec_attest_info:
71462306a36Sopenharmony_ci	kfree(sec_attest_info);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return rc;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic int eventfd_register(struct hl_fpriv *hpriv, struct hl_info_args *args)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	int rc;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/* check if there is already a registered on that process */
72462306a36Sopenharmony_ci	mutex_lock(&hpriv->notifier_event.lock);
72562306a36Sopenharmony_ci	if (hpriv->notifier_event.eventfd) {
72662306a36Sopenharmony_ci		mutex_unlock(&hpriv->notifier_event.lock);
72762306a36Sopenharmony_ci		return -EINVAL;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	hpriv->notifier_event.eventfd = eventfd_ctx_fdget(args->eventfd);
73162306a36Sopenharmony_ci	if (IS_ERR(hpriv->notifier_event.eventfd)) {
73262306a36Sopenharmony_ci		rc = PTR_ERR(hpriv->notifier_event.eventfd);
73362306a36Sopenharmony_ci		hpriv->notifier_event.eventfd = NULL;
73462306a36Sopenharmony_ci		mutex_unlock(&hpriv->notifier_event.lock);
73562306a36Sopenharmony_ci		return rc;
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	mutex_unlock(&hpriv->notifier_event.lock);
73962306a36Sopenharmony_ci	return 0;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic int eventfd_unregister(struct hl_fpriv *hpriv, struct hl_info_args *args)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	mutex_lock(&hpriv->notifier_event.lock);
74562306a36Sopenharmony_ci	if (!hpriv->notifier_event.eventfd) {
74662306a36Sopenharmony_ci		mutex_unlock(&hpriv->notifier_event.lock);
74762306a36Sopenharmony_ci		return -EINVAL;
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	eventfd_ctx_put(hpriv->notifier_event.eventfd);
75162306a36Sopenharmony_ci	hpriv->notifier_event.eventfd = NULL;
75262306a36Sopenharmony_ci	mutex_unlock(&hpriv->notifier_event.lock);
75362306a36Sopenharmony_ci	return 0;
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic int engine_status_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
75962306a36Sopenharmony_ci	u32 status_buf_size = args->return_size;
76062306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
76162306a36Sopenharmony_ci	struct engines_data eng_data;
76262306a36Sopenharmony_ci	int rc;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if ((status_buf_size < SZ_1K) || (status_buf_size > HL_ENGINES_DATA_MAX_SIZE) || (!out))
76562306a36Sopenharmony_ci		return -EINVAL;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	eng_data.actual_size = 0;
76862306a36Sopenharmony_ci	eng_data.allocated_buf_size = status_buf_size;
76962306a36Sopenharmony_ci	eng_data.buf = vmalloc(status_buf_size);
77062306a36Sopenharmony_ci	if (!eng_data.buf)
77162306a36Sopenharmony_ci		return -ENOMEM;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	hdev->asic_funcs->is_device_idle(hdev, NULL, 0, &eng_data);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (eng_data.actual_size > eng_data.allocated_buf_size) {
77662306a36Sopenharmony_ci		dev_err(hdev->dev,
77762306a36Sopenharmony_ci			"Engines data size (%d Bytes) is bigger than allocated size (%u Bytes)\n",
77862306a36Sopenharmony_ci			eng_data.actual_size, status_buf_size);
77962306a36Sopenharmony_ci		vfree(eng_data.buf);
78062306a36Sopenharmony_ci		return -ENOMEM;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	args->user_buffer_actual_size = eng_data.actual_size;
78462306a36Sopenharmony_ci	rc = copy_to_user(out, eng_data.buf, min_t(size_t, status_buf_size, eng_data.actual_size)) ?
78562306a36Sopenharmony_ci				-EFAULT : 0;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	vfree(eng_data.buf);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	return rc;
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic int page_fault_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
79562306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
79662306a36Sopenharmony_ci	u32 max_size = args->return_size;
79762306a36Sopenharmony_ci	struct page_fault_info *pgf_info;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if ((!max_size) || (!out))
80062306a36Sopenharmony_ci		return -EINVAL;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	pgf_info = &hdev->captured_err_info.page_fault_info;
80362306a36Sopenharmony_ci	if (!pgf_info->page_fault_info_available)
80462306a36Sopenharmony_ci		return 0;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	return copy_to_user(out, &pgf_info->page_fault,
80762306a36Sopenharmony_ci			min_t(size_t, max_size, sizeof(struct hl_page_fault_info))) ? -EFAULT : 0;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic int user_mappings_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
81362306a36Sopenharmony_ci	u32 user_buf_size = args->return_size;
81462306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
81562306a36Sopenharmony_ci	struct page_fault_info *pgf_info;
81662306a36Sopenharmony_ci	u64 actual_size;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	if (!out)
81962306a36Sopenharmony_ci		return -EINVAL;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	pgf_info = &hdev->captured_err_info.page_fault_info;
82262306a36Sopenharmony_ci	if (!pgf_info->page_fault_info_available)
82362306a36Sopenharmony_ci		return 0;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	args->array_size = pgf_info->num_of_user_mappings;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	actual_size = pgf_info->num_of_user_mappings * sizeof(struct hl_user_mapping);
82862306a36Sopenharmony_ci	if (user_buf_size < actual_size)
82962306a36Sopenharmony_ci		return -ENOMEM;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	return copy_to_user(out, pgf_info->user_mappings, actual_size) ? -EFAULT : 0;
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_cistatic int hw_err_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	void __user *user_buf = (void __user *) (uintptr_t) args->return_pointer;
83762306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
83862306a36Sopenharmony_ci	u32 user_buf_size = args->return_size;
83962306a36Sopenharmony_ci	struct hw_err_info *info;
84062306a36Sopenharmony_ci	int rc;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	if (!user_buf)
84362306a36Sopenharmony_ci		return -EINVAL;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	info = &hdev->captured_err_info.hw_err;
84662306a36Sopenharmony_ci	if (!info->event_info_available)
84762306a36Sopenharmony_ci		return 0;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (user_buf_size < sizeof(struct hl_info_hw_err_event))
85062306a36Sopenharmony_ci		return -ENOMEM;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	rc = copy_to_user(user_buf, &info->event, sizeof(struct hl_info_hw_err_event));
85362306a36Sopenharmony_ci	return rc ? -EFAULT : 0;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic int fw_err_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	void __user *user_buf = (void __user *) (uintptr_t) args->return_pointer;
85962306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
86062306a36Sopenharmony_ci	u32 user_buf_size = args->return_size;
86162306a36Sopenharmony_ci	struct fw_err_info *info;
86262306a36Sopenharmony_ci	int rc;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (!user_buf)
86562306a36Sopenharmony_ci		return -EINVAL;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	info = &hdev->captured_err_info.fw_err;
86862306a36Sopenharmony_ci	if (!info->event_info_available)
86962306a36Sopenharmony_ci		return 0;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	if (user_buf_size < sizeof(struct hl_info_fw_err_event))
87262306a36Sopenharmony_ci		return -ENOMEM;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	rc = copy_to_user(user_buf, &info->event, sizeof(struct hl_info_fw_err_event));
87562306a36Sopenharmony_ci	return rc ? -EFAULT : 0;
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic int send_fw_generic_request(struct hl_device *hdev, struct hl_info_args *info_args)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	void __user *buff = (void __user *) (uintptr_t) info_args->return_pointer;
88162306a36Sopenharmony_ci	u32 size = info_args->return_size;
88262306a36Sopenharmony_ci	dma_addr_t dma_handle;
88362306a36Sopenharmony_ci	bool need_input_buff;
88462306a36Sopenharmony_ci	void *fw_buff;
88562306a36Sopenharmony_ci	int rc = 0;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	switch (info_args->fw_sub_opcode) {
88862306a36Sopenharmony_ci	case HL_PASSTHROUGH_VERSIONS:
88962306a36Sopenharmony_ci		need_input_buff = false;
89062306a36Sopenharmony_ci		break;
89162306a36Sopenharmony_ci	default:
89262306a36Sopenharmony_ci		return -EINVAL;
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (size > SZ_1M) {
89662306a36Sopenharmony_ci		dev_err(hdev->dev, "buffer size cannot exceed 1MB\n");
89762306a36Sopenharmony_ci		return -EINVAL;
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	fw_buff = hl_cpu_accessible_dma_pool_alloc(hdev, size, &dma_handle);
90162306a36Sopenharmony_ci	if (!fw_buff)
90262306a36Sopenharmony_ci		return -ENOMEM;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	if (need_input_buff && copy_from_user(fw_buff, buff, size)) {
90662306a36Sopenharmony_ci		dev_dbg(hdev->dev, "Failed to copy from user FW buff\n");
90762306a36Sopenharmony_ci		rc = -EFAULT;
90862306a36Sopenharmony_ci		goto free_buff;
90962306a36Sopenharmony_ci	}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	rc = hl_fw_send_generic_request(hdev, info_args->fw_sub_opcode, dma_handle, &size);
91262306a36Sopenharmony_ci	if (rc)
91362306a36Sopenharmony_ci		goto free_buff;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (copy_to_user(buff, fw_buff, min(size, info_args->return_size))) {
91662306a36Sopenharmony_ci		dev_dbg(hdev->dev, "Failed to copy to user FW generic req output\n");
91762306a36Sopenharmony_ci		rc = -EFAULT;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cifree_buff:
92162306a36Sopenharmony_ci	hl_cpu_accessible_dma_pool_free(hdev, info_args->return_size, fw_buff);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	return rc;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
92762306a36Sopenharmony_ci				struct device *dev)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	enum hl_device_status status;
93062306a36Sopenharmony_ci	struct hl_info_args *args = data;
93162306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
93262306a36Sopenharmony_ci	int rc;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (args->pad) {
93562306a36Sopenharmony_ci		dev_dbg(hdev->dev, "Padding bytes must be 0\n");
93662306a36Sopenharmony_ci		return -EINVAL;
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/*
94062306a36Sopenharmony_ci	 * Information is returned for the following opcodes even if the device
94162306a36Sopenharmony_ci	 * is disabled or in reset.
94262306a36Sopenharmony_ci	 */
94362306a36Sopenharmony_ci	switch (args->op) {
94462306a36Sopenharmony_ci	case HL_INFO_HW_IP_INFO:
94562306a36Sopenharmony_ci		return hw_ip_info(hdev, args);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	case HL_INFO_DEVICE_STATUS:
94862306a36Sopenharmony_ci		return device_status_info(hdev, args);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	case HL_INFO_RESET_COUNT:
95162306a36Sopenharmony_ci		return get_reset_count(hdev, args);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	case HL_INFO_HW_EVENTS:
95462306a36Sopenharmony_ci		return hw_events_info(hdev, false, args);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	case HL_INFO_HW_EVENTS_AGGREGATE:
95762306a36Sopenharmony_ci		return hw_events_info(hdev, true, args);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	case HL_INFO_CS_COUNTERS:
96062306a36Sopenharmony_ci		return cs_counters_info(hpriv, args);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	case HL_INFO_CLK_THROTTLE_REASON:
96362306a36Sopenharmony_ci		return clk_throttle_info(hpriv, args);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	case HL_INFO_SYNC_MANAGER:
96662306a36Sopenharmony_ci		return sync_manager_info(hpriv, args);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	case HL_INFO_OPEN_STATS:
96962306a36Sopenharmony_ci		return open_stats_info(hpriv, args);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	case HL_INFO_LAST_ERR_OPEN_DEV_TIME:
97262306a36Sopenharmony_ci		return last_err_open_dev_info(hpriv, args);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	case HL_INFO_CS_TIMEOUT_EVENT:
97562306a36Sopenharmony_ci		return cs_timeout_info(hpriv, args);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	case HL_INFO_RAZWI_EVENT:
97862306a36Sopenharmony_ci		return razwi_info(hpriv, args);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	case HL_INFO_UNDEFINED_OPCODE_EVENT:
98162306a36Sopenharmony_ci		return undefined_opcode_info(hpriv, args);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	case HL_INFO_DEV_MEM_ALLOC_PAGE_SIZES:
98462306a36Sopenharmony_ci		return dev_mem_alloc_page_sizes_info(hpriv, args);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	case HL_INFO_GET_EVENTS:
98762306a36Sopenharmony_ci		return events_info(hpriv, args);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	case HL_INFO_PAGE_FAULT_EVENT:
99062306a36Sopenharmony_ci		return page_fault_info(hpriv, args);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	case HL_INFO_USER_MAPPINGS:
99362306a36Sopenharmony_ci		return user_mappings_info(hpriv, args);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	case HL_INFO_UNREGISTER_EVENTFD:
99662306a36Sopenharmony_ci		return eventfd_unregister(hpriv, args);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	case HL_INFO_HW_ERR_EVENT:
99962306a36Sopenharmony_ci		return hw_err_info(hpriv, args);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	case HL_INFO_FW_ERR_EVENT:
100262306a36Sopenharmony_ci		return fw_err_info(hpriv, args);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	case HL_INFO_DRAM_USAGE:
100562306a36Sopenharmony_ci		return dram_usage_info(hpriv, args);
100662306a36Sopenharmony_ci	default:
100762306a36Sopenharmony_ci		break;
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	if (!hl_device_operational(hdev, &status)) {
101162306a36Sopenharmony_ci		dev_dbg_ratelimited(dev,
101262306a36Sopenharmony_ci			"Device is %s. Can't execute INFO IOCTL\n",
101362306a36Sopenharmony_ci			hdev->status[status]);
101462306a36Sopenharmony_ci		return -EBUSY;
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	switch (args->op) {
101862306a36Sopenharmony_ci	case HL_INFO_HW_IDLE:
101962306a36Sopenharmony_ci		rc = hw_idle(hdev, args);
102062306a36Sopenharmony_ci		break;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	case HL_INFO_DEVICE_UTILIZATION:
102362306a36Sopenharmony_ci		rc = device_utilization(hdev, args);
102462306a36Sopenharmony_ci		break;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	case HL_INFO_CLK_RATE:
102762306a36Sopenharmony_ci		rc = get_clk_rate(hdev, args);
102862306a36Sopenharmony_ci		break;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	case HL_INFO_TIME_SYNC:
103162306a36Sopenharmony_ci		return time_sync_info(hdev, args);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	case HL_INFO_PCI_COUNTERS:
103462306a36Sopenharmony_ci		return pci_counters_info(hpriv, args);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	case HL_INFO_TOTAL_ENERGY:
103762306a36Sopenharmony_ci		return total_energy_consumption_info(hpriv, args);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	case HL_INFO_PLL_FREQUENCY:
104062306a36Sopenharmony_ci		return pll_frequency_info(hpriv, args);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	case HL_INFO_POWER:
104362306a36Sopenharmony_ci		return power_info(hpriv, args);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	case HL_INFO_DRAM_REPLACED_ROWS:
104762306a36Sopenharmony_ci		return dram_replaced_rows_info(hpriv, args);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	case HL_INFO_DRAM_PENDING_ROWS:
105062306a36Sopenharmony_ci		return dram_pending_rows_info(hpriv, args);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	case HL_INFO_SECURED_ATTESTATION:
105362306a36Sopenharmony_ci		return sec_attest_info(hpriv, args);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	case HL_INFO_REGISTER_EVENTFD:
105662306a36Sopenharmony_ci		return eventfd_register(hpriv, args);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	case HL_INFO_ENGINE_STATUS:
105962306a36Sopenharmony_ci		return engine_status_info(hpriv, args);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	case HL_INFO_FW_GENERIC_REQ:
106262306a36Sopenharmony_ci		return send_fw_generic_request(hdev, args);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	default:
106562306a36Sopenharmony_ci		dev_err(dev, "Invalid request %d\n", args->op);
106662306a36Sopenharmony_ci		rc = -EINVAL;
106762306a36Sopenharmony_ci		break;
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	return rc;
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic int hl_info_ioctl(struct hl_fpriv *hpriv, void *data)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	return _hl_info_ioctl(hpriv, data, hpriv->hdev->dev);
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cistatic int hl_info_ioctl_control(struct hl_fpriv *hpriv, void *data)
107962306a36Sopenharmony_ci{
108062306a36Sopenharmony_ci	return _hl_info_ioctl(hpriv, data, hpriv->hdev->dev_ctrl);
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic int hl_debug_ioctl(struct hl_fpriv *hpriv, void *data)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	struct hl_debug_args *args = data;
108662306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
108762306a36Sopenharmony_ci	enum hl_device_status status;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	int rc = 0;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	if (!hl_device_operational(hdev, &status)) {
109262306a36Sopenharmony_ci		dev_dbg_ratelimited(hdev->dev,
109362306a36Sopenharmony_ci			"Device is %s. Can't execute DEBUG IOCTL\n",
109462306a36Sopenharmony_ci			hdev->status[status]);
109562306a36Sopenharmony_ci		return -EBUSY;
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	switch (args->op) {
109962306a36Sopenharmony_ci	case HL_DEBUG_OP_ETR:
110062306a36Sopenharmony_ci	case HL_DEBUG_OP_ETF:
110162306a36Sopenharmony_ci	case HL_DEBUG_OP_STM:
110262306a36Sopenharmony_ci	case HL_DEBUG_OP_FUNNEL:
110362306a36Sopenharmony_ci	case HL_DEBUG_OP_BMON:
110462306a36Sopenharmony_ci	case HL_DEBUG_OP_SPMU:
110562306a36Sopenharmony_ci	case HL_DEBUG_OP_TIMESTAMP:
110662306a36Sopenharmony_ci		if (!hdev->in_debug) {
110762306a36Sopenharmony_ci			dev_err_ratelimited(hdev->dev,
110862306a36Sopenharmony_ci				"Rejecting debug configuration request because device not in debug mode\n");
110962306a36Sopenharmony_ci			return -EFAULT;
111062306a36Sopenharmony_ci		}
111162306a36Sopenharmony_ci		args->input_size = min(args->input_size, hl_debug_struct_size[args->op]);
111262306a36Sopenharmony_ci		rc = debug_coresight(hdev, hpriv->ctx, args);
111362306a36Sopenharmony_ci		break;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	case HL_DEBUG_OP_SET_MODE:
111662306a36Sopenharmony_ci		rc = hl_device_set_debug_mode(hdev, hpriv->ctx, (bool) args->enable);
111762306a36Sopenharmony_ci		break;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	default:
112062306a36Sopenharmony_ci		dev_err(hdev->dev, "Invalid request %d\n", args->op);
112162306a36Sopenharmony_ci		rc = -EINVAL;
112262306a36Sopenharmony_ci		break;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	return rc;
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci#define HL_IOCTL_DEF(ioctl, _func) \
112962306a36Sopenharmony_ci	[_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_cistatic const struct hl_ioctl_desc hl_ioctls[] = {
113262306a36Sopenharmony_ci	HL_IOCTL_DEF(HL_IOCTL_INFO, hl_info_ioctl),
113362306a36Sopenharmony_ci	HL_IOCTL_DEF(HL_IOCTL_CB, hl_cb_ioctl),
113462306a36Sopenharmony_ci	HL_IOCTL_DEF(HL_IOCTL_CS, hl_cs_ioctl),
113562306a36Sopenharmony_ci	HL_IOCTL_DEF(HL_IOCTL_WAIT_CS, hl_wait_ioctl),
113662306a36Sopenharmony_ci	HL_IOCTL_DEF(HL_IOCTL_MEMORY, hl_mem_ioctl),
113762306a36Sopenharmony_ci	HL_IOCTL_DEF(HL_IOCTL_DEBUG, hl_debug_ioctl)
113862306a36Sopenharmony_ci};
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic const struct hl_ioctl_desc hl_ioctls_control[] = {
114162306a36Sopenharmony_ci	HL_IOCTL_DEF(HL_IOCTL_INFO, hl_info_ioctl_control)
114262306a36Sopenharmony_ci};
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_cistatic long _hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg,
114562306a36Sopenharmony_ci		const struct hl_ioctl_desc *ioctl, struct device *dev)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	struct hl_fpriv *hpriv = filep->private_data;
114862306a36Sopenharmony_ci	unsigned int nr = _IOC_NR(cmd);
114962306a36Sopenharmony_ci	char stack_kdata[128] = {0};
115062306a36Sopenharmony_ci	char *kdata = NULL;
115162306a36Sopenharmony_ci	unsigned int usize, asize;
115262306a36Sopenharmony_ci	hl_ioctl_t *func;
115362306a36Sopenharmony_ci	u32 hl_size;
115462306a36Sopenharmony_ci	int retcode;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	/* Do not trust userspace, use our own definition */
115762306a36Sopenharmony_ci	func = ioctl->func;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	if (unlikely(!func)) {
116062306a36Sopenharmony_ci		dev_dbg(dev, "no function\n");
116162306a36Sopenharmony_ci		retcode = -ENOTTY;
116262306a36Sopenharmony_ci		goto out_err;
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	hl_size = _IOC_SIZE(ioctl->cmd);
116662306a36Sopenharmony_ci	usize = asize = _IOC_SIZE(cmd);
116762306a36Sopenharmony_ci	if (hl_size > asize)
116862306a36Sopenharmony_ci		asize = hl_size;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	cmd = ioctl->cmd;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (cmd & (IOC_IN | IOC_OUT)) {
117362306a36Sopenharmony_ci		if (asize <= sizeof(stack_kdata)) {
117462306a36Sopenharmony_ci			kdata = stack_kdata;
117562306a36Sopenharmony_ci		} else {
117662306a36Sopenharmony_ci			kdata = kzalloc(asize, GFP_KERNEL);
117762306a36Sopenharmony_ci			if (!kdata) {
117862306a36Sopenharmony_ci				retcode = -ENOMEM;
117962306a36Sopenharmony_ci				goto out_err;
118062306a36Sopenharmony_ci			}
118162306a36Sopenharmony_ci		}
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	if (cmd & IOC_IN) {
118562306a36Sopenharmony_ci		if (copy_from_user(kdata, (void __user *)arg, usize)) {
118662306a36Sopenharmony_ci			retcode = -EFAULT;
118762306a36Sopenharmony_ci			goto out_err;
118862306a36Sopenharmony_ci		}
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	retcode = func(hpriv, kdata);
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	if ((cmd & IOC_OUT) && copy_to_user((void __user *)arg, kdata, usize))
119462306a36Sopenharmony_ci		retcode = -EFAULT;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ciout_err:
119762306a36Sopenharmony_ci	if (retcode)
119862306a36Sopenharmony_ci		dev_dbg_ratelimited(dev, "error in ioctl: pid=%d, cmd=0x%02x, nr=0x%02x\n",
119962306a36Sopenharmony_ci			  task_pid_nr(current), cmd, nr);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (kdata != stack_kdata)
120262306a36Sopenharmony_ci		kfree(kdata);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	return retcode;
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_cilong hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	struct hl_fpriv *hpriv = filep->private_data;
121062306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
121162306a36Sopenharmony_ci	const struct hl_ioctl_desc *ioctl = NULL;
121262306a36Sopenharmony_ci	unsigned int nr = _IOC_NR(cmd);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	if (!hdev) {
121562306a36Sopenharmony_ci		pr_err_ratelimited("Sending ioctl after device was removed! Please close FD\n");
121662306a36Sopenharmony_ci		return -ENODEV;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if ((nr >= HL_COMMAND_START) && (nr < HL_COMMAND_END)) {
122062306a36Sopenharmony_ci		ioctl = &hl_ioctls[nr];
122162306a36Sopenharmony_ci	} else {
122262306a36Sopenharmony_ci		dev_dbg_ratelimited(hdev->dev, "invalid ioctl: pid=%d, nr=0x%02x\n",
122362306a36Sopenharmony_ci			task_pid_nr(current), nr);
122462306a36Sopenharmony_ci		return -ENOTTY;
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	return _hl_ioctl(filep, cmd, arg, ioctl, hdev->dev);
122862306a36Sopenharmony_ci}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_cilong hl_ioctl_control(struct file *filep, unsigned int cmd, unsigned long arg)
123162306a36Sopenharmony_ci{
123262306a36Sopenharmony_ci	struct hl_fpriv *hpriv = filep->private_data;
123362306a36Sopenharmony_ci	struct hl_device *hdev = hpriv->hdev;
123462306a36Sopenharmony_ci	const struct hl_ioctl_desc *ioctl = NULL;
123562306a36Sopenharmony_ci	unsigned int nr = _IOC_NR(cmd);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	if (!hdev) {
123862306a36Sopenharmony_ci		pr_err_ratelimited("Sending ioctl after device was removed! Please close FD\n");
123962306a36Sopenharmony_ci		return -ENODEV;
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	if (nr == _IOC_NR(HL_IOCTL_INFO)) {
124362306a36Sopenharmony_ci		ioctl = &hl_ioctls_control[nr];
124462306a36Sopenharmony_ci	} else {
124562306a36Sopenharmony_ci		dev_dbg_ratelimited(hdev->dev_ctrl, "invalid ioctl: pid=%d, nr=0x%02x\n",
124662306a36Sopenharmony_ci			task_pid_nr(current), nr);
124762306a36Sopenharmony_ci		return -ENOTTY;
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	return _hl_ioctl(filep, cmd, arg, ioctl, hdev->dev_ctrl);
125162306a36Sopenharmony_ci}
1252