Path: blob/master/drivers/accel/habanalabs/common/habanalabs_ioctl.c
26436 views
// SPDX-License-Identifier: GPL-2.012/*3* Copyright 2016-2022 HabanaLabs, Ltd.4* All Rights Reserved.5*/67#define pr_fmt(fmt) "habanalabs: " fmt89#include <uapi/drm/habanalabs_accel.h>10#include "habanalabs.h"1112#include <linux/fs.h>13#include <linux/kernel.h>14#include <linux/pci.h>15#include <linux/slab.h>16#include <linux/uaccess.h>17#include <linux/vmalloc.h>1819/* make sure there is space for all the signed info */20static_assert(sizeof(struct cpucp_info) <= SEC_DEV_INFO_BUF_SZ);2122static u32 hl_debug_struct_size[HL_DEBUG_OP_TIMESTAMP + 1] = {23[HL_DEBUG_OP_ETR] = sizeof(struct hl_debug_params_etr),24[HL_DEBUG_OP_ETF] = sizeof(struct hl_debug_params_etf),25[HL_DEBUG_OP_STM] = sizeof(struct hl_debug_params_stm),26[HL_DEBUG_OP_FUNNEL] = 0,27[HL_DEBUG_OP_BMON] = sizeof(struct hl_debug_params_bmon),28[HL_DEBUG_OP_SPMU] = sizeof(struct hl_debug_params_spmu),29[HL_DEBUG_OP_TIMESTAMP] = 03031};3233static int device_status_info(struct hl_device *hdev, struct hl_info_args *args)34{35struct hl_info_device_status dev_stat = {0};36u32 size = args->return_size;37void __user *out = (void __user *) (uintptr_t) args->return_pointer;3839if ((!size) || (!out))40return -EINVAL;4142dev_stat.status = hl_device_status(hdev);4344return copy_to_user(out, &dev_stat,45min((size_t)size, sizeof(dev_stat))) ? -EFAULT : 0;46}4748static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args)49{50struct hl_info_hw_ip_info hw_ip = {0};51u32 size = args->return_size;52void __user *out = (void __user *) (uintptr_t) args->return_pointer;53struct asic_fixed_properties *prop = &hdev->asic_prop;54u64 sram_kmd_size, dram_kmd_size, dram_available_size;5556if ((!size) || (!out))57return -EINVAL;5859sram_kmd_size = (prop->sram_user_base_address -60prop->sram_base_address);61dram_kmd_size = (prop->dram_user_base_address -62prop->dram_base_address);6364hw_ip.device_id = hdev->asic_funcs->get_pci_id(hdev);65hw_ip.sram_base_address = prop->sram_user_base_address;66hw_ip.dram_base_address =67prop->dram_supports_virtual_memory ?68prop->dmmu.start_addr : prop->dram_user_base_address;69hw_ip.tpc_enabled_mask = prop->tpc_enabled_mask & 0xFF;70hw_ip.tpc_enabled_mask_ext = prop->tpc_enabled_mask;7172hw_ip.sram_size = prop->sram_size - sram_kmd_size;7374dram_available_size = prop->dram_size - dram_kmd_size;7576hw_ip.dram_size = DIV_ROUND_DOWN_ULL(dram_available_size, prop->dram_page_size) *77prop->dram_page_size;7879if (hw_ip.dram_size > PAGE_SIZE)80hw_ip.dram_enabled = 1;8182hw_ip.dram_page_size = prop->dram_page_size;83hw_ip.device_mem_alloc_default_page_size = prop->device_mem_alloc_default_page_size;84hw_ip.num_of_events = prop->num_of_events;8586memcpy(hw_ip.cpucp_version, prop->cpucp_info.cpucp_version,87min(VERSION_MAX_LEN, HL_INFO_VERSION_MAX_LEN));8889memcpy(hw_ip.card_name, prop->cpucp_info.card_name,90min(CARD_NAME_MAX_LEN, HL_INFO_CARD_NAME_MAX_LEN));9192hw_ip.cpld_version = le32_to_cpu(prop->cpucp_info.cpld_version);93hw_ip.module_id = le32_to_cpu(prop->cpucp_info.card_location);9495hw_ip.psoc_pci_pll_nr = prop->psoc_pci_pll_nr;96hw_ip.psoc_pci_pll_nf = prop->psoc_pci_pll_nf;97hw_ip.psoc_pci_pll_od = prop->psoc_pci_pll_od;98hw_ip.psoc_pci_pll_div_factor = prop->psoc_pci_pll_div_factor;99100hw_ip.decoder_enabled_mask = prop->decoder_enabled_mask;101hw_ip.mme_master_slave_mode = prop->mme_master_slave_mode;102hw_ip.first_available_interrupt_id = prop->first_available_user_interrupt;103hw_ip.number_of_user_interrupts = prop->user_interrupt_count;104hw_ip.tpc_interrupt_id = prop->tpc_interrupt_id;105106hw_ip.edma_enabled_mask = prop->edma_enabled_mask;107hw_ip.server_type = prop->server_type;108hw_ip.security_enabled = prop->fw_security_enabled;109hw_ip.revision_id = hdev->pdev->revision;110hw_ip.rotator_enabled_mask = prop->rotator_enabled_mask;111hw_ip.engine_core_interrupt_reg_addr = prop->engine_core_interrupt_reg_addr;112hw_ip.reserved_dram_size = dram_kmd_size;113114return copy_to_user(out, &hw_ip,115min((size_t) size, sizeof(hw_ip))) ? -EFAULT : 0;116}117118static int hw_events_info(struct hl_device *hdev, bool aggregate,119struct hl_info_args *args)120{121u32 size, max_size = args->return_size;122void __user *out = (void __user *) (uintptr_t) args->return_pointer;123void *arr;124125if ((!max_size) || (!out))126return -EINVAL;127128arr = hdev->asic_funcs->get_events_stat(hdev, aggregate, &size);129if (!arr) {130dev_err(hdev->dev, "Events info not supported\n");131return -EOPNOTSUPP;132}133134return copy_to_user(out, arr, min(max_size, size)) ? -EFAULT : 0;135}136137static int events_info(struct hl_fpriv *hpriv, struct hl_info_args *args)138{139u32 max_size = args->return_size;140u64 events_mask;141void __user *out = (void __user *) (uintptr_t) args->return_pointer;142143if ((max_size < sizeof(u64)) || (!out))144return -EINVAL;145146mutex_lock(&hpriv->notifier_event.lock);147events_mask = hpriv->notifier_event.events_mask;148hpriv->notifier_event.events_mask = 0;149mutex_unlock(&hpriv->notifier_event.lock);150151return copy_to_user(out, &events_mask, sizeof(u64)) ? -EFAULT : 0;152}153154static int dram_usage_info(struct hl_fpriv *hpriv, struct hl_info_args *args)155{156struct hl_device *hdev = hpriv->hdev;157struct hl_info_dram_usage dram_usage = {0};158u32 max_size = args->return_size;159void __user *out = (void __user *) (uintptr_t) args->return_pointer;160struct asic_fixed_properties *prop = &hdev->asic_prop;161u64 dram_kmd_size;162163if ((!max_size) || (!out))164return -EINVAL;165166dram_kmd_size = (prop->dram_user_base_address -167prop->dram_base_address);168dram_usage.dram_free_mem = (prop->dram_size - dram_kmd_size) -169atomic64_read(&hdev->dram_used_mem);170if (hpriv->ctx)171dram_usage.ctx_dram_mem =172atomic64_read(&hpriv->ctx->dram_phys_mem);173174return copy_to_user(out, &dram_usage,175min((size_t) max_size, sizeof(dram_usage))) ? -EFAULT : 0;176}177178static int hw_idle(struct hl_device *hdev, struct hl_info_args *args)179{180struct hl_info_hw_idle hw_idle = {0};181u32 max_size = args->return_size;182void __user *out = (void __user *) (uintptr_t) args->return_pointer;183184if ((!max_size) || (!out))185return -EINVAL;186187hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev,188hw_idle.busy_engines_mask_ext,189HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL);190hw_idle.busy_engines_mask =191lower_32_bits(hw_idle.busy_engines_mask_ext[0]);192193return copy_to_user(out, &hw_idle,194min((size_t) max_size, sizeof(hw_idle))) ? -EFAULT : 0;195}196197static int debug_coresight(struct hl_device *hdev, struct hl_ctx *ctx, struct hl_debug_args *args)198{199struct hl_debug_params *params;200void *input = NULL, *output = NULL;201int rc;202203params = kzalloc(sizeof(*params), GFP_KERNEL);204if (!params)205return -ENOMEM;206207params->reg_idx = args->reg_idx;208params->enable = args->enable;209params->op = args->op;210211if (args->input_ptr && args->input_size) {212input = kzalloc(hl_debug_struct_size[args->op], GFP_KERNEL);213if (!input) {214rc = -ENOMEM;215goto out;216}217218if (copy_from_user(input, u64_to_user_ptr(args->input_ptr),219args->input_size)) {220rc = -EFAULT;221dev_err(hdev->dev, "failed to copy input debug data\n");222goto out;223}224225params->input = input;226}227228if (args->output_ptr && args->output_size) {229output = kzalloc(args->output_size, GFP_KERNEL);230if (!output) {231rc = -ENOMEM;232goto out;233}234235params->output = output;236params->output_size = args->output_size;237}238239rc = hdev->asic_funcs->debug_coresight(hdev, ctx, params);240if (rc) {241dev_err(hdev->dev,242"debug coresight operation failed %d\n", rc);243goto out;244}245246if (output && copy_to_user((void __user *) (uintptr_t) args->output_ptr,247output, args->output_size)) {248dev_err(hdev->dev, "copy to user failed in debug ioctl\n");249rc = -EFAULT;250goto out;251}252253254out:255kfree(params);256kfree(output);257kfree(input);258259return rc;260}261262static int device_utilization(struct hl_device *hdev, struct hl_info_args *args)263{264struct hl_info_device_utilization device_util = {0};265u32 max_size = args->return_size;266void __user *out = (void __user *) (uintptr_t) args->return_pointer;267int rc;268269if ((!max_size) || (!out))270return -EINVAL;271272rc = hl_device_utilization(hdev, &device_util.utilization);273if (rc)274return -EINVAL;275276return copy_to_user(out, &device_util,277min((size_t) max_size, sizeof(device_util))) ? -EFAULT : 0;278}279280static int get_clk_rate(struct hl_device *hdev, struct hl_info_args *args)281{282struct hl_info_clk_rate clk_rate = {0};283u32 max_size = args->return_size;284void __user *out = (void __user *) (uintptr_t) args->return_pointer;285int rc;286287if ((!max_size) || (!out))288return -EINVAL;289290rc = hl_fw_get_clk_rate(hdev, &clk_rate.cur_clk_rate_mhz, &clk_rate.max_clk_rate_mhz);291if (rc)292return rc;293294return copy_to_user(out, &clk_rate, min_t(size_t, max_size, sizeof(clk_rate)))295? -EFAULT : 0;296}297298static int get_reset_count(struct hl_device *hdev, struct hl_info_args *args)299{300struct hl_info_reset_count reset_count = {0};301u32 max_size = args->return_size;302void __user *out = (void __user *) (uintptr_t) args->return_pointer;303304if ((!max_size) || (!out))305return -EINVAL;306307reset_count.hard_reset_cnt = hdev->reset_info.hard_reset_cnt;308reset_count.soft_reset_cnt = hdev->reset_info.compute_reset_cnt;309310return copy_to_user(out, &reset_count,311min((size_t) max_size, sizeof(reset_count))) ? -EFAULT : 0;312}313314static int time_sync_info(struct hl_device *hdev, struct hl_info_args *args)315{316struct hl_info_time_sync time_sync = {0};317u32 max_size = args->return_size;318void __user *out = (void __user *) (uintptr_t) args->return_pointer;319320if ((!max_size) || (!out))321return -EINVAL;322323time_sync.device_time = hdev->asic_funcs->get_device_time(hdev);324time_sync.host_time = ktime_get_raw_ns();325time_sync.tsc_time = rdtsc();326327return copy_to_user(out, &time_sync,328min((size_t) max_size, sizeof(time_sync))) ? -EFAULT : 0;329}330331static int pci_counters_info(struct hl_fpriv *hpriv, struct hl_info_args *args)332{333struct hl_device *hdev = hpriv->hdev;334struct hl_info_pci_counters pci_counters = {0};335u32 max_size = args->return_size;336void __user *out = (void __user *) (uintptr_t) args->return_pointer;337int rc;338339if ((!max_size) || (!out))340return -EINVAL;341342rc = hl_fw_cpucp_pci_counters_get(hdev, &pci_counters);343if (rc)344return rc;345346return copy_to_user(out, &pci_counters,347min((size_t) max_size, sizeof(pci_counters))) ? -EFAULT : 0;348}349350static int clk_throttle_info(struct hl_fpriv *hpriv, struct hl_info_args *args)351{352void __user *out = (void __user *) (uintptr_t) args->return_pointer;353struct hl_device *hdev = hpriv->hdev;354struct hl_info_clk_throttle clk_throttle = {0};355ktime_t end_time, zero_time = ktime_set(0, 0);356u32 max_size = args->return_size;357int i;358359if ((!max_size) || (!out))360return -EINVAL;361362mutex_lock(&hdev->clk_throttling.lock);363364clk_throttle.clk_throttling_reason = hdev->clk_throttling.current_reason;365366for (i = 0 ; i < HL_CLK_THROTTLE_TYPE_MAX ; i++) {367if (!(hdev->clk_throttling.aggregated_reason & BIT(i)))368continue;369370clk_throttle.clk_throttling_timestamp_us[i] =371ktime_to_us(hdev->clk_throttling.timestamp[i].start);372373if (ktime_compare(hdev->clk_throttling.timestamp[i].end, zero_time))374end_time = hdev->clk_throttling.timestamp[i].end;375else376end_time = ktime_get();377378clk_throttle.clk_throttling_duration_ns[i] =379ktime_to_ns(ktime_sub(end_time,380hdev->clk_throttling.timestamp[i].start));381382}383mutex_unlock(&hdev->clk_throttling.lock);384385return copy_to_user(out, &clk_throttle,386min((size_t) max_size, sizeof(clk_throttle))) ? -EFAULT : 0;387}388389static int cs_counters_info(struct hl_fpriv *hpriv, struct hl_info_args *args)390{391void __user *out = (void __user *) (uintptr_t) args->return_pointer;392struct hl_info_cs_counters cs_counters = {0};393struct hl_device *hdev = hpriv->hdev;394struct hl_cs_counters_atomic *cntr;395u32 max_size = args->return_size;396397cntr = &hdev->aggregated_cs_counters;398399if ((!max_size) || (!out))400return -EINVAL;401402cs_counters.total_out_of_mem_drop_cnt =403atomic64_read(&cntr->out_of_mem_drop_cnt);404cs_counters.total_parsing_drop_cnt =405atomic64_read(&cntr->parsing_drop_cnt);406cs_counters.total_queue_full_drop_cnt =407atomic64_read(&cntr->queue_full_drop_cnt);408cs_counters.total_device_in_reset_drop_cnt =409atomic64_read(&cntr->device_in_reset_drop_cnt);410cs_counters.total_max_cs_in_flight_drop_cnt =411atomic64_read(&cntr->max_cs_in_flight_drop_cnt);412cs_counters.total_validation_drop_cnt =413atomic64_read(&cntr->validation_drop_cnt);414415if (hpriv->ctx) {416cs_counters.ctx_out_of_mem_drop_cnt =417atomic64_read(418&hpriv->ctx->cs_counters.out_of_mem_drop_cnt);419cs_counters.ctx_parsing_drop_cnt =420atomic64_read(421&hpriv->ctx->cs_counters.parsing_drop_cnt);422cs_counters.ctx_queue_full_drop_cnt =423atomic64_read(424&hpriv->ctx->cs_counters.queue_full_drop_cnt);425cs_counters.ctx_device_in_reset_drop_cnt =426atomic64_read(427&hpriv->ctx->cs_counters.device_in_reset_drop_cnt);428cs_counters.ctx_max_cs_in_flight_drop_cnt =429atomic64_read(430&hpriv->ctx->cs_counters.max_cs_in_flight_drop_cnt);431cs_counters.ctx_validation_drop_cnt =432atomic64_read(433&hpriv->ctx->cs_counters.validation_drop_cnt);434}435436return copy_to_user(out, &cs_counters,437min((size_t) max_size, sizeof(cs_counters))) ? -EFAULT : 0;438}439440static int sync_manager_info(struct hl_fpriv *hpriv, struct hl_info_args *args)441{442struct hl_device *hdev = hpriv->hdev;443struct asic_fixed_properties *prop = &hdev->asic_prop;444struct hl_info_sync_manager sm_info = {0};445u32 max_size = args->return_size;446void __user *out = (void __user *) (uintptr_t) args->return_pointer;447448if ((!max_size) || (!out))449return -EINVAL;450451if (args->dcore_id >= HL_MAX_DCORES)452return -EINVAL;453454sm_info.first_available_sync_object =455prop->first_available_user_sob[args->dcore_id];456sm_info.first_available_monitor =457prop->first_available_user_mon[args->dcore_id];458sm_info.first_available_cq =459prop->first_available_cq[args->dcore_id];460461return copy_to_user(out, &sm_info, min_t(size_t, (size_t) max_size,462sizeof(sm_info))) ? -EFAULT : 0;463}464465static int total_energy_consumption_info(struct hl_fpriv *hpriv,466struct hl_info_args *args)467{468struct hl_device *hdev = hpriv->hdev;469struct hl_info_energy total_energy = {0};470u32 max_size = args->return_size;471void __user *out = (void __user *) (uintptr_t) args->return_pointer;472int rc;473474if ((!max_size) || (!out))475return -EINVAL;476477rc = hl_fw_cpucp_total_energy_get(hdev,478&total_energy.total_energy_consumption);479if (rc)480return rc;481482return copy_to_user(out, &total_energy,483min((size_t) max_size, sizeof(total_energy))) ? -EFAULT : 0;484}485486static int pll_frequency_info(struct hl_fpriv *hpriv, struct hl_info_args *args)487{488struct hl_device *hdev = hpriv->hdev;489struct hl_pll_frequency_info freq_info = { {0} };490u32 max_size = args->return_size;491void __user *out = (void __user *) (uintptr_t) args->return_pointer;492int rc;493494if ((!max_size) || (!out))495return -EINVAL;496497rc = hl_fw_cpucp_pll_info_get(hdev, args->pll_index, freq_info.output);498if (rc)499return rc;500501return copy_to_user(out, &freq_info,502min((size_t) max_size, sizeof(freq_info))) ? -EFAULT : 0;503}504505static int power_info(struct hl_fpriv *hpriv, struct hl_info_args *args)506{507struct hl_device *hdev = hpriv->hdev;508u32 max_size = args->return_size;509struct hl_power_info power_info = {0};510void __user *out = (void __user *) (uintptr_t) args->return_pointer;511int rc;512513if ((!max_size) || (!out))514return -EINVAL;515516rc = hl_fw_cpucp_power_get(hdev, &power_info.power);517if (rc)518return rc;519520return copy_to_user(out, &power_info,521min((size_t) max_size, sizeof(power_info))) ? -EFAULT : 0;522}523524static int open_stats_info(struct hl_fpriv *hpriv, struct hl_info_args *args)525{526struct hl_device *hdev = hpriv->hdev;527u32 max_size = args->return_size;528struct hl_open_stats_info open_stats_info = {0};529void __user *out = (void __user *) (uintptr_t) args->return_pointer;530531if ((!max_size) || (!out))532return -EINVAL;533534open_stats_info.last_open_period_ms = jiffies64_to_msecs(535hdev->last_open_session_duration_jif);536open_stats_info.open_counter = hdev->open_counter;537open_stats_info.is_compute_ctx_active = hdev->is_compute_ctx_active;538open_stats_info.compute_ctx_in_release = hdev->compute_ctx_in_release;539540return copy_to_user(out, &open_stats_info,541min((size_t) max_size, sizeof(open_stats_info))) ? -EFAULT : 0;542}543544static int dram_pending_rows_info(struct hl_fpriv *hpriv, struct hl_info_args *args)545{546struct hl_device *hdev = hpriv->hdev;547u32 max_size = args->return_size;548u32 pend_rows_num = 0;549void __user *out = (void __user *) (uintptr_t) args->return_pointer;550int rc;551552if ((!max_size) || (!out))553return -EINVAL;554555rc = hl_fw_dram_pending_row_get(hdev, &pend_rows_num);556if (rc)557return rc;558559return copy_to_user(out, &pend_rows_num,560min_t(size_t, max_size, sizeof(pend_rows_num))) ? -EFAULT : 0;561}562563static int dram_replaced_rows_info(struct hl_fpriv *hpriv, struct hl_info_args *args)564{565struct hl_device *hdev = hpriv->hdev;566u32 max_size = args->return_size;567struct cpucp_hbm_row_info info = {0};568void __user *out = (void __user *) (uintptr_t) args->return_pointer;569int rc;570571if ((!max_size) || (!out))572return -EINVAL;573574rc = hl_fw_dram_replaced_row_get(hdev, &info);575if (rc)576return rc;577578return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;579}580581static int last_err_open_dev_info(struct hl_fpriv *hpriv, struct hl_info_args *args)582{583struct hl_info_last_err_open_dev_time info = {0};584struct hl_device *hdev = hpriv->hdev;585u32 max_size = args->return_size;586void __user *out = (void __user *) (uintptr_t) args->return_pointer;587588if ((!max_size) || (!out))589return -EINVAL;590591info.timestamp = ktime_to_ns(hdev->last_successful_open_ktime);592593return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;594}595596static int cs_timeout_info(struct hl_fpriv *hpriv, struct hl_info_args *args)597{598struct hl_info_cs_timeout_event info = {0};599struct hl_device *hdev = hpriv->hdev;600u32 max_size = args->return_size;601void __user *out = (void __user *) (uintptr_t) args->return_pointer;602603if ((!max_size) || (!out))604return -EINVAL;605606info.seq = hdev->captured_err_info.cs_timeout.seq;607info.timestamp = ktime_to_ns(hdev->captured_err_info.cs_timeout.timestamp);608609return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;610}611612static int razwi_info(struct hl_fpriv *hpriv, struct hl_info_args *args)613{614void __user *out = (void __user *) (uintptr_t) args->return_pointer;615struct hl_device *hdev = hpriv->hdev;616u32 max_size = args->return_size;617struct razwi_info *razwi_info;618619if ((!max_size) || (!out))620return -EINVAL;621622razwi_info = &hdev->captured_err_info.razwi_info;623if (!razwi_info->razwi_info_available)624return 0;625626return copy_to_user(out, &razwi_info->razwi,627min_t(size_t, max_size, sizeof(struct hl_info_razwi_event))) ? -EFAULT : 0;628}629630static int undefined_opcode_info(struct hl_fpriv *hpriv, struct hl_info_args *args)631{632struct hl_device *hdev = hpriv->hdev;633u32 max_size = args->return_size;634struct hl_info_undefined_opcode_event info = {0};635void __user *out = (void __user *) (uintptr_t) args->return_pointer;636637if ((!max_size) || (!out))638return -EINVAL;639640info.timestamp = ktime_to_ns(hdev->captured_err_info.undef_opcode.timestamp);641info.engine_id = hdev->captured_err_info.undef_opcode.engine_id;642info.cq_addr = hdev->captured_err_info.undef_opcode.cq_addr;643info.cq_size = hdev->captured_err_info.undef_opcode.cq_size;644info.stream_id = hdev->captured_err_info.undef_opcode.stream_id;645info.cb_addr_streams_len = hdev->captured_err_info.undef_opcode.cb_addr_streams_len;646memcpy(info.cb_addr_streams, hdev->captured_err_info.undef_opcode.cb_addr_streams,647sizeof(info.cb_addr_streams));648649return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;650}651652static int dev_mem_alloc_page_sizes_info(struct hl_fpriv *hpriv, struct hl_info_args *args)653{654void __user *out = (void __user *) (uintptr_t) args->return_pointer;655struct hl_info_dev_memalloc_page_sizes info = {0};656struct hl_device *hdev = hpriv->hdev;657u32 max_size = args->return_size;658659if ((!max_size) || (!out))660return -EINVAL;661662/*663* Future ASICs that will support multiple DRAM page sizes will support only "powers of 2"664* pages (unlike some of the ASICs before supporting multiple page sizes).665* For this reason for all ASICs that not support multiple page size the function will666* return an empty bitmask indicating that multiple page sizes is not supported.667*/668info.page_order_bitmask = hdev->asic_prop.dmmu.supported_pages_mask;669670return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;671}672673static int sec_attest_info(struct hl_fpriv *hpriv, struct hl_info_args *args)674{675void __user *out = (void __user *) (uintptr_t) args->return_pointer;676struct cpucp_sec_attest_info *sec_attest_info;677struct hl_info_sec_attest *info;678u32 max_size = args->return_size;679int rc;680681if ((!max_size) || (!out))682return -EINVAL;683684sec_attest_info = kmalloc(sizeof(*sec_attest_info), GFP_KERNEL);685if (!sec_attest_info)686return -ENOMEM;687688info = kzalloc(sizeof(*info), GFP_KERNEL);689if (!info) {690rc = -ENOMEM;691goto free_sec_attest_info;692}693694rc = hl_fw_get_sec_attest_info(hpriv->hdev, sec_attest_info, args->sec_attest_nonce);695if (rc)696goto free_info;697698info->nonce = le32_to_cpu(sec_attest_info->nonce);699info->pcr_quote_len = le16_to_cpu(sec_attest_info->pcr_quote_len);700info->pub_data_len = le16_to_cpu(sec_attest_info->pub_data_len);701info->certificate_len = le16_to_cpu(sec_attest_info->certificate_len);702info->pcr_num_reg = sec_attest_info->pcr_num_reg;703info->pcr_reg_len = sec_attest_info->pcr_reg_len;704info->quote_sig_len = sec_attest_info->quote_sig_len;705memcpy(&info->pcr_data, &sec_attest_info->pcr_data, sizeof(info->pcr_data));706memcpy(&info->pcr_quote, &sec_attest_info->pcr_quote, sizeof(info->pcr_quote));707memcpy(&info->public_data, &sec_attest_info->public_data, sizeof(info->public_data));708memcpy(&info->certificate, &sec_attest_info->certificate, sizeof(info->certificate));709memcpy(&info->quote_sig, &sec_attest_info->quote_sig, sizeof(info->quote_sig));710711rc = copy_to_user(out, info,712min_t(size_t, max_size, sizeof(*info))) ? -EFAULT : 0;713714free_info:715kfree(info);716free_sec_attest_info:717kfree(sec_attest_info);718719return rc;720}721722static int dev_info_signed(struct hl_fpriv *hpriv, struct hl_info_args *args)723{724void __user *out = (void __user *) (uintptr_t) args->return_pointer;725struct cpucp_dev_info_signed *dev_info_signed;726struct hl_info_signed *info;727u32 max_size = args->return_size;728int rc;729730if ((!max_size) || (!out))731return -EINVAL;732733dev_info_signed = kzalloc(sizeof(*dev_info_signed), GFP_KERNEL);734if (!dev_info_signed)735return -ENOMEM;736737info = kzalloc(sizeof(*info), GFP_KERNEL);738if (!info) {739rc = -ENOMEM;740goto free_dev_info_signed;741}742743rc = hl_fw_get_dev_info_signed(hpriv->hdev,744dev_info_signed, args->sec_attest_nonce);745if (rc)746goto free_info;747748info->nonce = le32_to_cpu(dev_info_signed->nonce);749info->info_sig_len = dev_info_signed->info_sig_len;750info->pub_data_len = le16_to_cpu(dev_info_signed->pub_data_len);751info->certificate_len = le16_to_cpu(dev_info_signed->certificate_len);752info->dev_info_len = sizeof(struct cpucp_info);753memcpy(&info->info_sig, &dev_info_signed->info_sig, sizeof(info->info_sig));754memcpy(&info->public_data, &dev_info_signed->public_data, sizeof(info->public_data));755memcpy(&info->certificate, &dev_info_signed->certificate, sizeof(info->certificate));756memcpy(&info->dev_info, &dev_info_signed->info, info->dev_info_len);757758rc = copy_to_user(out, info, min_t(size_t, max_size, sizeof(*info))) ? -EFAULT : 0;759760free_info:761kfree(info);762free_dev_info_signed:763kfree(dev_info_signed);764765return rc;766}767768769static int eventfd_register(struct hl_fpriv *hpriv, struct hl_info_args *args)770{771int rc;772773/* check if there is already a registered on that process */774mutex_lock(&hpriv->notifier_event.lock);775if (hpriv->notifier_event.eventfd) {776mutex_unlock(&hpriv->notifier_event.lock);777return -EINVAL;778}779780hpriv->notifier_event.eventfd = eventfd_ctx_fdget(args->eventfd);781if (IS_ERR(hpriv->notifier_event.eventfd)) {782rc = PTR_ERR(hpriv->notifier_event.eventfd);783hpriv->notifier_event.eventfd = NULL;784mutex_unlock(&hpriv->notifier_event.lock);785return rc;786}787788mutex_unlock(&hpriv->notifier_event.lock);789return 0;790}791792static int eventfd_unregister(struct hl_fpriv *hpriv, struct hl_info_args *args)793{794mutex_lock(&hpriv->notifier_event.lock);795if (!hpriv->notifier_event.eventfd) {796mutex_unlock(&hpriv->notifier_event.lock);797return -EINVAL;798}799800eventfd_ctx_put(hpriv->notifier_event.eventfd);801hpriv->notifier_event.eventfd = NULL;802mutex_unlock(&hpriv->notifier_event.lock);803return 0;804}805806static int engine_status_info(struct hl_fpriv *hpriv, struct hl_info_args *args)807{808void __user *out = (void __user *) (uintptr_t) args->return_pointer;809u32 status_buf_size = args->return_size;810struct hl_device *hdev = hpriv->hdev;811struct engines_data eng_data;812int rc;813814if ((status_buf_size < SZ_1K) || (status_buf_size > HL_ENGINES_DATA_MAX_SIZE) || (!out))815return -EINVAL;816817eng_data.actual_size = 0;818eng_data.allocated_buf_size = status_buf_size;819eng_data.buf = vmalloc(status_buf_size);820if (!eng_data.buf)821return -ENOMEM;822823hdev->asic_funcs->is_device_idle(hdev, NULL, 0, &eng_data);824825if (eng_data.actual_size > eng_data.allocated_buf_size) {826dev_err(hdev->dev,827"Engines data size (%d Bytes) is bigger than allocated size (%u Bytes)\n",828eng_data.actual_size, status_buf_size);829vfree(eng_data.buf);830return -ENOMEM;831}832833args->user_buffer_actual_size = eng_data.actual_size;834rc = copy_to_user(out, eng_data.buf, min_t(size_t, status_buf_size, eng_data.actual_size)) ?835-EFAULT : 0;836837vfree(eng_data.buf);838839return rc;840}841842static int page_fault_info(struct hl_fpriv *hpriv, struct hl_info_args *args)843{844void __user *out = (void __user *) (uintptr_t) args->return_pointer;845struct hl_device *hdev = hpriv->hdev;846u32 max_size = args->return_size;847struct page_fault_info *pgf_info;848849if ((!max_size) || (!out))850return -EINVAL;851852pgf_info = &hdev->captured_err_info.page_fault_info;853if (!pgf_info->page_fault_info_available)854return 0;855856return copy_to_user(out, &pgf_info->page_fault,857min_t(size_t, max_size, sizeof(struct hl_page_fault_info))) ? -EFAULT : 0;858}859860static int user_mappings_info(struct hl_fpriv *hpriv, struct hl_info_args *args)861{862void __user *out = (void __user *) (uintptr_t) args->return_pointer;863u32 user_buf_size = args->return_size;864struct hl_device *hdev = hpriv->hdev;865struct page_fault_info *pgf_info;866u64 actual_size;867868if (!out)869return -EINVAL;870871pgf_info = &hdev->captured_err_info.page_fault_info;872if (!pgf_info->page_fault_info_available)873return 0;874875args->array_size = pgf_info->num_of_user_mappings;876877actual_size = pgf_info->num_of_user_mappings * sizeof(struct hl_user_mapping);878if (user_buf_size < actual_size)879return -ENOMEM;880881return copy_to_user(out, pgf_info->user_mappings, actual_size) ? -EFAULT : 0;882}883884static int hw_err_info(struct hl_fpriv *hpriv, struct hl_info_args *args)885{886void __user *user_buf = (void __user *) (uintptr_t) args->return_pointer;887struct hl_device *hdev = hpriv->hdev;888u32 user_buf_size = args->return_size;889struct hw_err_info *info;890int rc;891892if (!user_buf)893return -EINVAL;894895info = &hdev->captured_err_info.hw_err;896if (!info->event_info_available)897return 0;898899if (user_buf_size < sizeof(struct hl_info_hw_err_event))900return -ENOMEM;901902rc = copy_to_user(user_buf, &info->event, sizeof(struct hl_info_hw_err_event));903return rc ? -EFAULT : 0;904}905906static int fw_err_info(struct hl_fpriv *hpriv, struct hl_info_args *args)907{908void __user *user_buf = (void __user *) (uintptr_t) args->return_pointer;909struct hl_device *hdev = hpriv->hdev;910u32 user_buf_size = args->return_size;911struct fw_err_info *info;912int rc;913914if (!user_buf)915return -EINVAL;916917info = &hdev->captured_err_info.fw_err;918if (!info->event_info_available)919return 0;920921if (user_buf_size < sizeof(struct hl_info_fw_err_event))922return -ENOMEM;923924rc = copy_to_user(user_buf, &info->event, sizeof(struct hl_info_fw_err_event));925return rc ? -EFAULT : 0;926}927928static int engine_err_info(struct hl_fpriv *hpriv, struct hl_info_args *args)929{930void __user *user_buf = (void __user *) (uintptr_t) args->return_pointer;931struct hl_device *hdev = hpriv->hdev;932u32 user_buf_size = args->return_size;933struct engine_err_info *info;934int rc;935936if (!user_buf)937return -EINVAL;938939info = &hdev->captured_err_info.engine_err;940if (!info->event_info_available)941return 0;942943if (user_buf_size < sizeof(struct hl_info_engine_err_event))944return -ENOMEM;945946rc = copy_to_user(user_buf, &info->event, sizeof(struct hl_info_engine_err_event));947return rc ? -EFAULT : 0;948}949950static int send_fw_generic_request(struct hl_device *hdev, struct hl_info_args *info_args)951{952void __user *buff = (void __user *) (uintptr_t) info_args->return_pointer;953u32 size = info_args->return_size;954dma_addr_t dma_handle;955bool need_input_buff;956void *fw_buff;957int rc = 0;958959switch (info_args->fw_sub_opcode) {960case HL_PASSTHROUGH_VERSIONS:961need_input_buff = false;962break;963default:964return -EINVAL;965}966967if (size > SZ_1M) {968dev_err(hdev->dev, "buffer size cannot exceed 1MB\n");969return -EINVAL;970}971972fw_buff = hl_cpu_accessible_dma_pool_alloc(hdev, size, &dma_handle);973if (!fw_buff)974return -ENOMEM;975976977if (need_input_buff && copy_from_user(fw_buff, buff, size)) {978dev_dbg(hdev->dev, "Failed to copy from user FW buff\n");979rc = -EFAULT;980goto free_buff;981}982983rc = hl_fw_send_generic_request(hdev, info_args->fw_sub_opcode, dma_handle, &size);984if (rc)985goto free_buff;986987if (copy_to_user(buff, fw_buff, min(size, info_args->return_size))) {988dev_dbg(hdev->dev, "Failed to copy to user FW generic req output\n");989rc = -EFAULT;990}991992free_buff:993hl_cpu_accessible_dma_pool_free(hdev, info_args->return_size, fw_buff);994995return rc;996}997998static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,999struct device *dev)1000{1001enum hl_device_status status;1002struct hl_info_args *args = data;1003struct hl_device *hdev = hpriv->hdev;1004int rc;10051006if (args->pad) {1007dev_dbg(hdev->dev, "Padding bytes must be 0\n");1008return -EINVAL;1009}10101011/*1012* Information is returned for the following opcodes even if the device1013* is disabled or in reset.1014*/1015switch (args->op) {1016case HL_INFO_HW_IP_INFO:1017return hw_ip_info(hdev, args);10181019case HL_INFO_DEVICE_STATUS:1020return device_status_info(hdev, args);10211022case HL_INFO_RESET_COUNT:1023return get_reset_count(hdev, args);10241025case HL_INFO_HW_EVENTS:1026return hw_events_info(hdev, false, args);10271028case HL_INFO_HW_EVENTS_AGGREGATE:1029return hw_events_info(hdev, true, args);10301031case HL_INFO_CS_COUNTERS:1032return cs_counters_info(hpriv, args);10331034case HL_INFO_CLK_THROTTLE_REASON:1035return clk_throttle_info(hpriv, args);10361037case HL_INFO_SYNC_MANAGER:1038return sync_manager_info(hpriv, args);10391040case HL_INFO_OPEN_STATS:1041return open_stats_info(hpriv, args);10421043case HL_INFO_LAST_ERR_OPEN_DEV_TIME:1044return last_err_open_dev_info(hpriv, args);10451046case HL_INFO_CS_TIMEOUT_EVENT:1047return cs_timeout_info(hpriv, args);10481049case HL_INFO_RAZWI_EVENT:1050return razwi_info(hpriv, args);10511052case HL_INFO_UNDEFINED_OPCODE_EVENT:1053return undefined_opcode_info(hpriv, args);10541055case HL_INFO_DEV_MEM_ALLOC_PAGE_SIZES:1056return dev_mem_alloc_page_sizes_info(hpriv, args);10571058case HL_INFO_GET_EVENTS:1059return events_info(hpriv, args);10601061case HL_INFO_PAGE_FAULT_EVENT:1062return page_fault_info(hpriv, args);10631064case HL_INFO_USER_MAPPINGS:1065return user_mappings_info(hpriv, args);10661067case HL_INFO_UNREGISTER_EVENTFD:1068return eventfd_unregister(hpriv, args);10691070case HL_INFO_HW_ERR_EVENT:1071return hw_err_info(hpriv, args);10721073case HL_INFO_FW_ERR_EVENT:1074return fw_err_info(hpriv, args);10751076case HL_INFO_USER_ENGINE_ERR_EVENT:1077return engine_err_info(hpriv, args);10781079case HL_INFO_DRAM_USAGE:1080return dram_usage_info(hpriv, args);1081default:1082break;1083}10841085if (!hl_device_operational(hdev, &status)) {1086dev_dbg_ratelimited(dev,1087"Device is %s. Can't execute INFO IOCTL\n",1088hdev->status[status]);1089return -EBUSY;1090}10911092switch (args->op) {1093case HL_INFO_HW_IDLE:1094rc = hw_idle(hdev, args);1095break;10961097case HL_INFO_DEVICE_UTILIZATION:1098rc = device_utilization(hdev, args);1099break;11001101case HL_INFO_CLK_RATE:1102rc = get_clk_rate(hdev, args);1103break;11041105case HL_INFO_TIME_SYNC:1106return time_sync_info(hdev, args);11071108case HL_INFO_PCI_COUNTERS:1109return pci_counters_info(hpriv, args);11101111case HL_INFO_TOTAL_ENERGY:1112return total_energy_consumption_info(hpriv, args);11131114case HL_INFO_PLL_FREQUENCY:1115return pll_frequency_info(hpriv, args);11161117case HL_INFO_POWER:1118return power_info(hpriv, args);111911201121case HL_INFO_DRAM_REPLACED_ROWS:1122return dram_replaced_rows_info(hpriv, args);11231124case HL_INFO_DRAM_PENDING_ROWS:1125return dram_pending_rows_info(hpriv, args);11261127case HL_INFO_SECURED_ATTESTATION:1128return sec_attest_info(hpriv, args);11291130case HL_INFO_REGISTER_EVENTFD:1131return eventfd_register(hpriv, args);11321133case HL_INFO_ENGINE_STATUS:1134return engine_status_info(hpriv, args);11351136case HL_INFO_FW_GENERIC_REQ:1137return send_fw_generic_request(hdev, args);11381139case HL_INFO_DEV_SIGNED:1140return dev_info_signed(hpriv, args);11411142default:1143dev_err(dev, "Invalid request %d\n", args->op);1144rc = -EINVAL;1145break;1146}11471148return rc;1149}11501151int hl_info_ioctl(struct drm_device *ddev, void *data, struct drm_file *file_priv)1152{1153struct hl_fpriv *hpriv = file_priv->driver_priv;11541155return _hl_info_ioctl(hpriv, data, hpriv->hdev->dev);1156}11571158static int hl_info_ioctl_control(struct hl_fpriv *hpriv, void *data)1159{1160struct hl_info_args *args = data;11611162switch (args->op) {1163case HL_INFO_GET_EVENTS:1164case HL_INFO_UNREGISTER_EVENTFD:1165case HL_INFO_REGISTER_EVENTFD:1166return -EOPNOTSUPP;1167default:1168break;1169}11701171return _hl_info_ioctl(hpriv, data, hpriv->hdev->dev_ctrl);1172}11731174int hl_debug_ioctl(struct drm_device *ddev, void *data, struct drm_file *file_priv)1175{1176struct hl_fpriv *hpriv = file_priv->driver_priv;1177struct hl_device *hdev = hpriv->hdev;1178struct hl_debug_args *args = data;1179enum hl_device_status status;11801181int rc = 0;11821183if (!hl_device_operational(hdev, &status)) {1184dev_dbg_ratelimited(hdev->dev,1185"Device is %s. Can't execute DEBUG IOCTL\n",1186hdev->status[status]);1187return -EBUSY;1188}11891190switch (args->op) {1191case HL_DEBUG_OP_ETR:1192case HL_DEBUG_OP_ETF:1193case HL_DEBUG_OP_STM:1194case HL_DEBUG_OP_FUNNEL:1195case HL_DEBUG_OP_BMON:1196case HL_DEBUG_OP_SPMU:1197case HL_DEBUG_OP_TIMESTAMP:1198if (!hdev->in_debug) {1199dev_err_ratelimited(hdev->dev,1200"Rejecting debug configuration request because device not in debug mode\n");1201return -EFAULT;1202}1203args->input_size = min(args->input_size, hl_debug_struct_size[args->op]);1204rc = debug_coresight(hdev, hpriv->ctx, args);1205break;12061207case HL_DEBUG_OP_SET_MODE:1208rc = hl_device_set_debug_mode(hdev, hpriv->ctx, (bool) args->enable);1209break;12101211default:1212dev_err(hdev->dev, "Invalid request %d\n", args->op);1213rc = -EINVAL;1214break;1215}12161217return rc;1218}12191220#define HL_IOCTL_DEF(ioctl, _func) \1221[_IOC_NR(ioctl) - HL_COMMAND_START] = {.cmd = ioctl, .func = _func}12221223static const struct hl_ioctl_desc hl_ioctls_control[] = {1224HL_IOCTL_DEF(DRM_IOCTL_HL_INFO, hl_info_ioctl_control)1225};12261227static long _hl_ioctl(struct hl_fpriv *hpriv, unsigned int cmd, unsigned long arg,1228const struct hl_ioctl_desc *ioctl, struct device *dev)1229{1230unsigned int nr = _IOC_NR(cmd);1231char stack_kdata[128] = {0};1232char *kdata = NULL;1233unsigned int usize, asize;1234hl_ioctl_t *func;1235u32 hl_size;1236int retcode;12371238/* Do not trust userspace, use our own definition */1239func = ioctl->func;12401241if (unlikely(!func)) {1242dev_dbg(dev, "no function\n");1243retcode = -ENOTTY;1244goto out_err;1245}12461247hl_size = _IOC_SIZE(ioctl->cmd);1248usize = asize = _IOC_SIZE(cmd);1249if (hl_size > asize)1250asize = hl_size;12511252cmd = ioctl->cmd;12531254if (cmd & (IOC_IN | IOC_OUT)) {1255if (asize <= sizeof(stack_kdata)) {1256kdata = stack_kdata;1257} else {1258kdata = kzalloc(asize, GFP_KERNEL);1259if (!kdata) {1260retcode = -ENOMEM;1261goto out_err;1262}1263}1264}12651266if (cmd & IOC_IN) {1267if (copy_from_user(kdata, (void __user *)arg, usize)) {1268retcode = -EFAULT;1269goto out_err;1270}1271}12721273retcode = func(hpriv, kdata);12741275if ((cmd & IOC_OUT) && copy_to_user((void __user *)arg, kdata, usize))1276retcode = -EFAULT;12771278out_err:1279if (retcode)1280dev_dbg_ratelimited(dev,1281"error in ioctl: pid=%d, comm=\"%s\", cmd=%#010x, nr=%#04x\n",1282task_pid_nr(current), current->comm, cmd, nr);12831284if (kdata != stack_kdata)1285kfree(kdata);12861287return retcode;1288}12891290long hl_ioctl_control(struct file *filep, unsigned int cmd, unsigned long arg)1291{1292struct hl_fpriv *hpriv = filep->private_data;1293struct hl_device *hdev = hpriv->hdev;1294const struct hl_ioctl_desc *ioctl = NULL;1295unsigned int nr = _IOC_NR(cmd);12961297if (!hdev) {1298pr_err_ratelimited("Sending ioctl after device was removed! Please close FD\n");1299return -ENODEV;1300}13011302if (nr == _IOC_NR(DRM_IOCTL_HL_INFO)) {1303ioctl = &hl_ioctls_control[nr - HL_COMMAND_START];1304} else {1305dev_dbg_ratelimited(hdev->dev_ctrl,1306"invalid ioctl: pid=%d, comm=\"%s\", cmd=%#010x, nr=%#04x\n",1307task_pid_nr(current), current->comm, cmd, nr);1308return -ENOTTY;1309}13101311return _hl_ioctl(hpriv, cmd, arg, ioctl, hdev->dev_ctrl);1312}131313141315