linux/drivers/misc/habanalabs/habanalabs_ioctl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * Copyright 2016-2019 HabanaLabs, Ltd.
   5 * All Rights Reserved.
   6 */
   7
   8#include <uapi/misc/habanalabs.h>
   9#include "habanalabs.h"
  10
  11#include <linux/fs.h>
  12#include <linux/uaccess.h>
  13#include <linux/slab.h>
  14
  15static u32 hl_debug_struct_size[HL_DEBUG_OP_TIMESTAMP + 1] = {
  16        [HL_DEBUG_OP_ETR] = sizeof(struct hl_debug_params_etr),
  17        [HL_DEBUG_OP_ETF] = sizeof(struct hl_debug_params_etf),
  18        [HL_DEBUG_OP_STM] = sizeof(struct hl_debug_params_stm),
  19        [HL_DEBUG_OP_FUNNEL] = 0,
  20        [HL_DEBUG_OP_BMON] = sizeof(struct hl_debug_params_bmon),
  21        [HL_DEBUG_OP_SPMU] = sizeof(struct hl_debug_params_spmu),
  22        [HL_DEBUG_OP_TIMESTAMP] = 0
  23
  24};
  25
  26static int device_status_info(struct hl_device *hdev, struct hl_info_args *args)
  27{
  28        struct hl_info_device_status dev_stat = {0};
  29        u32 size = args->return_size;
  30        void __user *out = (void __user *) (uintptr_t) args->return_pointer;
  31
  32        if ((!size) || (!out))
  33                return -EINVAL;
  34
  35        dev_stat.status = hl_device_status(hdev);
  36
  37        return copy_to_user(out, &dev_stat,
  38                        min((size_t)size, sizeof(dev_stat))) ? -EFAULT : 0;
  39}
  40
  41static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args)
  42{
  43        struct hl_info_hw_ip_info hw_ip = {0};
  44        u32 size = args->return_size;
  45        void __user *out = (void __user *) (uintptr_t) args->return_pointer;
  46        struct asic_fixed_properties *prop = &hdev->asic_prop;
  47        u64 sram_kmd_size, dram_kmd_size;
  48
  49        if ((!size) || (!out))
  50                return -EINVAL;
  51
  52        sram_kmd_size = (prop->sram_user_base_address -
  53                                prop->sram_base_address);
  54        dram_kmd_size = (prop->dram_user_base_address -
  55                                prop->dram_base_address);
  56
  57        hw_ip.device_id = hdev->asic_funcs->get_pci_id(hdev);
  58        hw_ip.sram_base_address = prop->sram_user_base_address;
  59        hw_ip.dram_base_address = prop->dram_user_base_address;
  60        hw_ip.tpc_enabled_mask = prop->tpc_enabled_mask;
  61        hw_ip.sram_size = prop->sram_size - sram_kmd_size;
  62        hw_ip.dram_size = prop->dram_size - dram_kmd_size;
  63        if (hw_ip.dram_size > 0)
  64                hw_ip.dram_enabled = 1;
  65        hw_ip.num_of_events = prop->num_of_events;
  66        memcpy(hw_ip.armcp_version,
  67                prop->armcp_info.armcp_version, VERSION_MAX_LEN);
  68        hw_ip.armcp_cpld_version = __le32_to_cpu(prop->armcp_info.cpld_version);
  69        hw_ip.psoc_pci_pll_nr = prop->psoc_pci_pll_nr;
  70        hw_ip.psoc_pci_pll_nf = prop->psoc_pci_pll_nf;
  71        hw_ip.psoc_pci_pll_od = prop->psoc_pci_pll_od;
  72        hw_ip.psoc_pci_pll_div_factor = prop->psoc_pci_pll_div_factor;
  73
  74        return copy_to_user(out, &hw_ip,
  75                min((size_t)size, sizeof(hw_ip))) ? -EFAULT : 0;
  76}
  77
  78static int hw_events_info(struct hl_device *hdev, struct hl_info_args *args)
  79{
  80        u32 size, max_size = args->return_size;
  81        void __user *out = (void __user *) (uintptr_t) args->return_pointer;
  82        void *arr;
  83
  84        if ((!max_size) || (!out))
  85                return -EINVAL;
  86
  87        arr = hdev->asic_funcs->get_events_stat(hdev, &size);
  88
  89        return copy_to_user(out, arr, min(max_size, size)) ? -EFAULT : 0;
  90}
  91
  92static int dram_usage_info(struct hl_device *hdev, struct hl_info_args *args)
  93{
  94        struct hl_info_dram_usage dram_usage = {0};
  95        u32 max_size = args->return_size;
  96        void __user *out = (void __user *) (uintptr_t) args->return_pointer;
  97        struct asic_fixed_properties *prop = &hdev->asic_prop;
  98        u64 dram_kmd_size;
  99
 100        if ((!max_size) || (!out))
 101                return -EINVAL;
 102
 103        dram_kmd_size = (prop->dram_user_base_address -
 104                                prop->dram_base_address);
 105        dram_usage.dram_free_mem = (prop->dram_size - dram_kmd_size) -
 106                                        atomic64_read(&hdev->dram_used_mem);
 107        dram_usage.ctx_dram_mem = atomic64_read(&hdev->user_ctx->dram_phys_mem);
 108
 109        return copy_to_user(out, &dram_usage,
 110                min((size_t) max_size, sizeof(dram_usage))) ? -EFAULT : 0;
 111}
 112
 113static int hw_idle(struct hl_device *hdev, struct hl_info_args *args)
 114{
 115        struct hl_info_hw_idle hw_idle = {0};
 116        u32 max_size = args->return_size;
 117        void __user *out = (void __user *) (uintptr_t) args->return_pointer;
 118
 119        if ((!max_size) || (!out))
 120                return -EINVAL;
 121
 122        hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev,
 123                                        &hw_idle.busy_engines_mask, NULL);
 124
 125        return copy_to_user(out, &hw_idle,
 126                min((size_t) max_size, sizeof(hw_idle))) ? -EFAULT : 0;
 127}
 128
 129static int debug_coresight(struct hl_device *hdev, struct hl_debug_args *args)
 130{
 131        struct hl_debug_params *params;
 132        void *input = NULL, *output = NULL;
 133        int rc;
 134
 135        params = kzalloc(sizeof(*params), GFP_KERNEL);
 136        if (!params)
 137                return -ENOMEM;
 138
 139        params->reg_idx = args->reg_idx;
 140        params->enable = args->enable;
 141        params->op = args->op;
 142
 143        if (args->input_ptr && args->input_size) {
 144                input = memdup_user(u64_to_user_ptr(args->input_ptr),
 145                                        args->input_size);
 146                if (IS_ERR(input)) {
 147                        rc = PTR_ERR(input);
 148                        input = NULL;
 149                        dev_err(hdev->dev,
 150                                "error %d when copying input debug data\n", rc);
 151                        goto out;
 152                }
 153
 154                params->input = input;
 155        }
 156
 157        if (args->output_ptr && args->output_size) {
 158                output = kzalloc(args->output_size, GFP_KERNEL);
 159                if (!output) {
 160                        rc = -ENOMEM;
 161                        goto out;
 162                }
 163
 164                params->output = output;
 165                params->output_size = args->output_size;
 166        }
 167
 168        rc = hdev->asic_funcs->debug_coresight(hdev, params);
 169        if (rc) {
 170                dev_err(hdev->dev,
 171                        "debug coresight operation failed %d\n", rc);
 172                goto out;
 173        }
 174
 175        if (output) {
 176                if (copy_to_user((void __user *) (uintptr_t) args->output_ptr,
 177                                        output,
 178                                        args->output_size)) {
 179                        dev_err(hdev->dev,
 180                                "copy to user failed in debug ioctl\n");
 181                        rc = -EFAULT;
 182                        goto out;
 183                }
 184        }
 185
 186out:
 187        kfree(params);
 188        kfree(output);
 189        kfree(input);
 190
 191        return rc;
 192}
 193
 194static int hl_info_ioctl(struct hl_fpriv *hpriv, void *data)
 195{
 196        struct hl_info_args *args = data;
 197        struct hl_device *hdev = hpriv->hdev;
 198        int rc;
 199
 200        /* We want to return device status even if it disabled or in reset */
 201        if (args->op == HL_INFO_DEVICE_STATUS)
 202                return device_status_info(hdev, args);
 203
 204        if (hl_device_disabled_or_in_reset(hdev)) {
 205                dev_warn_ratelimited(hdev->dev,
 206                        "Device is %s. Can't execute INFO IOCTL\n",
 207                        atomic_read(&hdev->in_reset) ? "in_reset" : "disabled");
 208                return -EBUSY;
 209        }
 210
 211        switch (args->op) {
 212        case HL_INFO_HW_IP_INFO:
 213                rc = hw_ip_info(hdev, args);
 214                break;
 215
 216        case HL_INFO_HW_EVENTS:
 217                rc = hw_events_info(hdev, args);
 218                break;
 219
 220        case HL_INFO_DRAM_USAGE:
 221                rc = dram_usage_info(hdev, args);
 222                break;
 223
 224        case HL_INFO_HW_IDLE:
 225                rc = hw_idle(hdev, args);
 226                break;
 227
 228        default:
 229                dev_err(hdev->dev, "Invalid request %d\n", args->op);
 230                rc = -ENOTTY;
 231                break;
 232        }
 233
 234        return rc;
 235}
 236
 237static int hl_debug_ioctl(struct hl_fpriv *hpriv, void *data)
 238{
 239        struct hl_debug_args *args = data;
 240        struct hl_device *hdev = hpriv->hdev;
 241        int rc = 0;
 242
 243        if (hl_device_disabled_or_in_reset(hdev)) {
 244                dev_warn_ratelimited(hdev->dev,
 245                        "Device is %s. Can't execute DEBUG IOCTL\n",
 246                        atomic_read(&hdev->in_reset) ? "in_reset" : "disabled");
 247                return -EBUSY;
 248        }
 249
 250        switch (args->op) {
 251        case HL_DEBUG_OP_ETR:
 252        case HL_DEBUG_OP_ETF:
 253        case HL_DEBUG_OP_STM:
 254        case HL_DEBUG_OP_FUNNEL:
 255        case HL_DEBUG_OP_BMON:
 256        case HL_DEBUG_OP_SPMU:
 257        case HL_DEBUG_OP_TIMESTAMP:
 258                if (!hdev->in_debug) {
 259                        dev_err_ratelimited(hdev->dev,
 260                                "Rejecting debug configuration request because device not in debug mode\n");
 261                        return -EFAULT;
 262                }
 263                args->input_size =
 264                        min(args->input_size, hl_debug_struct_size[args->op]);
 265                rc = debug_coresight(hdev, args);
 266                break;
 267        case HL_DEBUG_OP_SET_MODE:
 268                rc = hl_device_set_debug_mode(hdev, (bool) args->enable);
 269                break;
 270        default:
 271                dev_err(hdev->dev, "Invalid request %d\n", args->op);
 272                rc = -ENOTTY;
 273                break;
 274        }
 275
 276        return rc;
 277}
 278
 279#define HL_IOCTL_DEF(ioctl, _func) \
 280        [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func}
 281
 282static const struct hl_ioctl_desc hl_ioctls[] = {
 283        HL_IOCTL_DEF(HL_IOCTL_INFO, hl_info_ioctl),
 284        HL_IOCTL_DEF(HL_IOCTL_CB, hl_cb_ioctl),
 285        HL_IOCTL_DEF(HL_IOCTL_CS, hl_cs_ioctl),
 286        HL_IOCTL_DEF(HL_IOCTL_WAIT_CS, hl_cs_wait_ioctl),
 287        HL_IOCTL_DEF(HL_IOCTL_MEMORY, hl_mem_ioctl),
 288        HL_IOCTL_DEF(HL_IOCTL_DEBUG, hl_debug_ioctl)
 289};
 290
 291#define HL_CORE_IOCTL_COUNT     ARRAY_SIZE(hl_ioctls)
 292
 293long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 294{
 295        struct hl_fpriv *hpriv = filep->private_data;
 296        struct hl_device *hdev = hpriv->hdev;
 297        hl_ioctl_t *func;
 298        const struct hl_ioctl_desc *ioctl = NULL;
 299        unsigned int nr = _IOC_NR(cmd);
 300        char stack_kdata[128] = {0};
 301        char *kdata = NULL;
 302        unsigned int usize, asize;
 303        int retcode;
 304
 305        if (hdev->hard_reset_pending) {
 306                dev_crit_ratelimited(hdev->dev,
 307                        "Device HARD reset pending! Please close FD\n");
 308                return -ENODEV;
 309        }
 310
 311        if ((nr >= HL_COMMAND_START) && (nr < HL_COMMAND_END)) {
 312                u32 hl_size;
 313
 314                ioctl = &hl_ioctls[nr];
 315
 316                hl_size = _IOC_SIZE(ioctl->cmd);
 317                usize = asize = _IOC_SIZE(cmd);
 318                if (hl_size > asize)
 319                        asize = hl_size;
 320
 321                cmd = ioctl->cmd;
 322        } else {
 323                dev_err(hdev->dev, "invalid ioctl: pid=%d, nr=0x%02x\n",
 324                          task_pid_nr(current), nr);
 325                return -ENOTTY;
 326        }
 327
 328        /* Do not trust userspace, use our own definition */
 329        func = ioctl->func;
 330
 331        if (unlikely(!func)) {
 332                dev_dbg(hdev->dev, "no function\n");
 333                retcode = -ENOTTY;
 334                goto out_err;
 335        }
 336
 337        if (cmd & (IOC_IN | IOC_OUT)) {
 338                if (asize <= sizeof(stack_kdata)) {
 339                        kdata = stack_kdata;
 340                } else {
 341                        kdata = kzalloc(asize, GFP_KERNEL);
 342                        if (!kdata) {
 343                                retcode = -ENOMEM;
 344                                goto out_err;
 345                        }
 346                }
 347        }
 348
 349        if (cmd & IOC_IN) {
 350                if (copy_from_user(kdata, (void __user *)arg, usize)) {
 351                        retcode = -EFAULT;
 352                        goto out_err;
 353                }
 354        } else if (cmd & IOC_OUT) {
 355                memset(kdata, 0, usize);
 356        }
 357
 358        retcode = func(hpriv, kdata);
 359
 360        if (cmd & IOC_OUT)
 361                if (copy_to_user((void __user *)arg, kdata, usize))
 362                        retcode = -EFAULT;
 363
 364out_err:
 365        if (retcode)
 366                dev_dbg(hdev->dev,
 367                        "error in ioctl: pid=%d, cmd=0x%02x, nr=0x%02x\n",
 368                          task_pid_nr(current), cmd, nr);
 369
 370        if (kdata != stack_kdata)
 371                kfree(kdata);
 372
 373        return retcode;
 374}
 375