linux/drivers/misc/habanalabs/debugfs.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 "habanalabs.h"
   9#include "include/hw_ip/mmu/mmu_general.h"
  10
  11#include <linux/pci.h>
  12#include <linux/debugfs.h>
  13#include <linux/uaccess.h>
  14
  15#define MMU_ADDR_BUF_SIZE       40
  16#define MMU_ASID_BUF_SIZE       10
  17#define MMU_KBUF_SIZE           (MMU_ADDR_BUF_SIZE + MMU_ASID_BUF_SIZE)
  18
  19static struct dentry *hl_debug_root;
  20
  21static int hl_debugfs_i2c_read(struct hl_device *hdev, u8 i2c_bus, u8 i2c_addr,
  22                                u8 i2c_reg, u32 *val)
  23{
  24        struct armcp_packet pkt;
  25        int rc;
  26
  27        if (hl_device_disabled_or_in_reset(hdev))
  28                return -EBUSY;
  29
  30        memset(&pkt, 0, sizeof(pkt));
  31
  32        pkt.ctl = __cpu_to_le32(ARMCP_PACKET_I2C_RD <<
  33                                ARMCP_PKT_CTL_OPCODE_SHIFT);
  34        pkt.i2c_bus = i2c_bus;
  35        pkt.i2c_addr = i2c_addr;
  36        pkt.i2c_reg = i2c_reg;
  37
  38        rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
  39                                        HL_DEVICE_TIMEOUT_USEC, (long *) val);
  40
  41        if (rc)
  42                dev_err(hdev->dev, "Failed to read from I2C, error %d\n", rc);
  43
  44        return rc;
  45}
  46
  47static int hl_debugfs_i2c_write(struct hl_device *hdev, u8 i2c_bus, u8 i2c_addr,
  48                                u8 i2c_reg, u32 val)
  49{
  50        struct armcp_packet pkt;
  51        int rc;
  52
  53        if (hl_device_disabled_or_in_reset(hdev))
  54                return -EBUSY;
  55
  56        memset(&pkt, 0, sizeof(pkt));
  57
  58        pkt.ctl = __cpu_to_le32(ARMCP_PACKET_I2C_WR <<
  59                                ARMCP_PKT_CTL_OPCODE_SHIFT);
  60        pkt.i2c_bus = i2c_bus;
  61        pkt.i2c_addr = i2c_addr;
  62        pkt.i2c_reg = i2c_reg;
  63        pkt.value = __cpu_to_le64(val);
  64
  65        rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
  66                                        HL_DEVICE_TIMEOUT_USEC, NULL);
  67
  68        if (rc)
  69                dev_err(hdev->dev, "Failed to write to I2C, error %d\n", rc);
  70
  71        return rc;
  72}
  73
  74static void hl_debugfs_led_set(struct hl_device *hdev, u8 led, u8 state)
  75{
  76        struct armcp_packet pkt;
  77        int rc;
  78
  79        if (hl_device_disabled_or_in_reset(hdev))
  80                return;
  81
  82        memset(&pkt, 0, sizeof(pkt));
  83
  84        pkt.ctl = __cpu_to_le32(ARMCP_PACKET_LED_SET <<
  85                                ARMCP_PKT_CTL_OPCODE_SHIFT);
  86        pkt.led_index = __cpu_to_le32(led);
  87        pkt.value = __cpu_to_le64(state);
  88
  89        rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
  90                                                HL_DEVICE_TIMEOUT_USEC, NULL);
  91
  92        if (rc)
  93                dev_err(hdev->dev, "Failed to set LED %d, error %d\n", led, rc);
  94}
  95
  96static int command_buffers_show(struct seq_file *s, void *data)
  97{
  98        struct hl_debugfs_entry *entry = s->private;
  99        struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
 100        struct hl_cb *cb;
 101        bool first = true;
 102
 103        spin_lock(&dev_entry->cb_spinlock);
 104
 105        list_for_each_entry(cb, &dev_entry->cb_list, debugfs_list) {
 106                if (first) {
 107                        first = false;
 108                        seq_puts(s, "\n");
 109                        seq_puts(s, " CB ID   CTX ID   CB size    CB RefCnt    mmap?   CS counter\n");
 110                        seq_puts(s, "---------------------------------------------------------------\n");
 111                }
 112                seq_printf(s,
 113                        "   %03d        %d    0x%08x      %d          %d          %d\n",
 114                        cb->id, cb->ctx_id, cb->size,
 115                        kref_read(&cb->refcount),
 116                        cb->mmap, cb->cs_cnt);
 117        }
 118
 119        spin_unlock(&dev_entry->cb_spinlock);
 120
 121        if (!first)
 122                seq_puts(s, "\n");
 123
 124        return 0;
 125}
 126
 127static int command_submission_show(struct seq_file *s, void *data)
 128{
 129        struct hl_debugfs_entry *entry = s->private;
 130        struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
 131        struct hl_cs *cs;
 132        bool first = true;
 133
 134        spin_lock(&dev_entry->cs_spinlock);
 135
 136        list_for_each_entry(cs, &dev_entry->cs_list, debugfs_list) {
 137                if (first) {
 138                        first = false;
 139                        seq_puts(s, "\n");
 140                        seq_puts(s, " CS ID   CTX ASID   CS RefCnt   Submitted    Completed\n");
 141                        seq_puts(s, "------------------------------------------------------\n");
 142                }
 143                seq_printf(s,
 144                        "   %llu       %d          %d           %d            %d\n",
 145                        cs->sequence, cs->ctx->asid,
 146                        kref_read(&cs->refcount),
 147                        cs->submitted, cs->completed);
 148        }
 149
 150        spin_unlock(&dev_entry->cs_spinlock);
 151
 152        if (!first)
 153                seq_puts(s, "\n");
 154
 155        return 0;
 156}
 157
 158static int command_submission_jobs_show(struct seq_file *s, void *data)
 159{
 160        struct hl_debugfs_entry *entry = s->private;
 161        struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
 162        struct hl_cs_job *job;
 163        bool first = true;
 164
 165        spin_lock(&dev_entry->cs_job_spinlock);
 166
 167        list_for_each_entry(job, &dev_entry->cs_job_list, debugfs_list) {
 168                if (first) {
 169                        first = false;
 170                        seq_puts(s, "\n");
 171                        seq_puts(s, " JOB ID   CS ID    CTX ASID   H/W Queue\n");
 172                        seq_puts(s, "---------------------------------------\n");
 173                }
 174                if (job->cs)
 175                        seq_printf(s,
 176                                "    %02d       %llu         %d         %d\n",
 177                                job->id, job->cs->sequence, job->cs->ctx->asid,
 178                                job->hw_queue_id);
 179                else
 180                        seq_printf(s,
 181                                "    %02d       0         %d         %d\n",
 182                                job->id, HL_KERNEL_ASID_ID, job->hw_queue_id);
 183        }
 184
 185        spin_unlock(&dev_entry->cs_job_spinlock);
 186
 187        if (!first)
 188                seq_puts(s, "\n");
 189
 190        return 0;
 191}
 192
 193static int userptr_show(struct seq_file *s, void *data)
 194{
 195        struct hl_debugfs_entry *entry = s->private;
 196        struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
 197        struct hl_userptr *userptr;
 198        char dma_dir[4][30] = {"DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
 199                                "DMA_FROM_DEVICE", "DMA_NONE"};
 200        bool first = true;
 201
 202        spin_lock(&dev_entry->userptr_spinlock);
 203
 204        list_for_each_entry(userptr, &dev_entry->userptr_list, debugfs_list) {
 205                if (first) {
 206                        first = false;
 207                        seq_puts(s, "\n");
 208                        seq_puts(s, " user virtual address     size             dma dir\n");
 209                        seq_puts(s, "----------------------------------------------------------\n");
 210                }
 211                seq_printf(s,
 212                        "    0x%-14llx      %-10u    %-30s\n",
 213                        userptr->addr, userptr->size, dma_dir[userptr->dir]);
 214        }
 215
 216        spin_unlock(&dev_entry->userptr_spinlock);
 217
 218        if (!first)
 219                seq_puts(s, "\n");
 220
 221        return 0;
 222}
 223
 224static int vm_show(struct seq_file *s, void *data)
 225{
 226        struct hl_debugfs_entry *entry = s->private;
 227        struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
 228        struct hl_ctx *ctx;
 229        struct hl_vm *vm;
 230        struct hl_vm_hash_node *hnode;
 231        struct hl_userptr *userptr;
 232        struct hl_vm_phys_pg_pack *phys_pg_pack = NULL;
 233        enum vm_type_t *vm_type;
 234        bool once = true;
 235        u64 j;
 236        int i;
 237
 238        if (!dev_entry->hdev->mmu_enable)
 239                return 0;
 240
 241        spin_lock(&dev_entry->ctx_mem_hash_spinlock);
 242
 243        list_for_each_entry(ctx, &dev_entry->ctx_mem_hash_list, debugfs_list) {
 244                once = false;
 245                seq_puts(s, "\n\n----------------------------------------------------");
 246                seq_puts(s, "\n----------------------------------------------------\n\n");
 247                seq_printf(s, "ctx asid: %u\n", ctx->asid);
 248
 249                seq_puts(s, "\nmappings:\n\n");
 250                seq_puts(s, "    virtual address        size          handle\n");
 251                seq_puts(s, "----------------------------------------------------\n");
 252                mutex_lock(&ctx->mem_hash_lock);
 253                hash_for_each(ctx->mem_hash, i, hnode, node) {
 254                        vm_type = hnode->ptr;
 255
 256                        if (*vm_type == VM_TYPE_USERPTR) {
 257                                userptr = hnode->ptr;
 258                                seq_printf(s,
 259                                        "    0x%-14llx      %-10u\n",
 260                                        hnode->vaddr, userptr->size);
 261                        } else {
 262                                phys_pg_pack = hnode->ptr;
 263                                seq_printf(s,
 264                                        "    0x%-14llx      %-10llu       %-4u\n",
 265                                        hnode->vaddr, phys_pg_pack->total_size,
 266                                        phys_pg_pack->handle);
 267                        }
 268                }
 269                mutex_unlock(&ctx->mem_hash_lock);
 270
 271                vm = &ctx->hdev->vm;
 272                spin_lock(&vm->idr_lock);
 273
 274                if (!idr_is_empty(&vm->phys_pg_pack_handles))
 275                        seq_puts(s, "\n\nallocations:\n");
 276
 277                idr_for_each_entry(&vm->phys_pg_pack_handles, phys_pg_pack, i) {
 278                        if (phys_pg_pack->asid != ctx->asid)
 279                                continue;
 280
 281                        seq_printf(s, "\nhandle: %u\n", phys_pg_pack->handle);
 282                        seq_printf(s, "page size: %u\n\n",
 283                                                phys_pg_pack->page_size);
 284                        seq_puts(s, "   physical address\n");
 285                        seq_puts(s, "---------------------\n");
 286                        for (j = 0 ; j < phys_pg_pack->npages ; j++) {
 287                                seq_printf(s, "    0x%-14llx\n",
 288                                                phys_pg_pack->pages[j]);
 289                        }
 290                }
 291                spin_unlock(&vm->idr_lock);
 292
 293        }
 294
 295        spin_unlock(&dev_entry->ctx_mem_hash_spinlock);
 296
 297        if (!once)
 298                seq_puts(s, "\n");
 299
 300        return 0;
 301}
 302
 303/* these inline functions are copied from mmu.c */
 304static inline u64 get_hop0_addr(struct hl_ctx *ctx)
 305{
 306        return ctx->hdev->asic_prop.mmu_pgt_addr +
 307                        (ctx->asid * ctx->hdev->asic_prop.mmu_hop_table_size);
 308}
 309
 310static inline u64 get_hop0_pte_addr(struct hl_ctx *ctx, u64 hop_addr,
 311                u64 virt_addr)
 312{
 313        return hop_addr + ctx->hdev->asic_prop.mmu_pte_size *
 314                        ((virt_addr & HOP0_MASK) >> HOP0_SHIFT);
 315}
 316
 317static inline u64 get_hop1_pte_addr(struct hl_ctx *ctx, u64 hop_addr,
 318                u64 virt_addr)
 319{
 320        return hop_addr + ctx->hdev->asic_prop.mmu_pte_size *
 321                        ((virt_addr & HOP1_MASK) >> HOP1_SHIFT);
 322}
 323
 324static inline u64 get_hop2_pte_addr(struct hl_ctx *ctx, u64 hop_addr,
 325                u64 virt_addr)
 326{
 327        return hop_addr + ctx->hdev->asic_prop.mmu_pte_size *
 328                        ((virt_addr & HOP2_MASK) >> HOP2_SHIFT);
 329}
 330
 331static inline u64 get_hop3_pte_addr(struct hl_ctx *ctx, u64 hop_addr,
 332                u64 virt_addr)
 333{
 334        return hop_addr + ctx->hdev->asic_prop.mmu_pte_size *
 335                        ((virt_addr & HOP3_MASK) >> HOP3_SHIFT);
 336}
 337
 338static inline u64 get_hop4_pte_addr(struct hl_ctx *ctx, u64 hop_addr,
 339                u64 virt_addr)
 340{
 341        return hop_addr + ctx->hdev->asic_prop.mmu_pte_size *
 342                        ((virt_addr & HOP4_MASK) >> HOP4_SHIFT);
 343}
 344
 345static inline u64 get_next_hop_addr(u64 curr_pte)
 346{
 347        if (curr_pte & PAGE_PRESENT_MASK)
 348                return curr_pte & PHYS_ADDR_MASK;
 349        else
 350                return ULLONG_MAX;
 351}
 352
 353static int mmu_show(struct seq_file *s, void *data)
 354{
 355        struct hl_debugfs_entry *entry = s->private;
 356        struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
 357        struct hl_device *hdev = dev_entry->hdev;
 358        struct hl_ctx *ctx = hdev->user_ctx;
 359
 360        u64 hop0_addr = 0, hop0_pte_addr = 0, hop0_pte = 0,
 361                hop1_addr = 0, hop1_pte_addr = 0, hop1_pte = 0,
 362                hop2_addr = 0, hop2_pte_addr = 0, hop2_pte = 0,
 363                hop3_addr = 0, hop3_pte_addr = 0, hop3_pte = 0,
 364                hop4_addr = 0, hop4_pte_addr = 0, hop4_pte = 0,
 365                virt_addr = dev_entry->mmu_addr;
 366
 367        if (!hdev->mmu_enable)
 368                return 0;
 369
 370        if (!ctx) {
 371                dev_err(hdev->dev, "no ctx available\n");
 372                return 0;
 373        }
 374
 375        mutex_lock(&ctx->mmu_lock);
 376
 377        /* the following lookup is copied from unmap() in mmu.c */
 378
 379        hop0_addr = get_hop0_addr(ctx);
 380        hop0_pte_addr = get_hop0_pte_addr(ctx, hop0_addr, virt_addr);
 381        hop0_pte = hdev->asic_funcs->read_pte(hdev, hop0_pte_addr);
 382        hop1_addr = get_next_hop_addr(hop0_pte);
 383
 384        if (hop1_addr == ULLONG_MAX)
 385                goto not_mapped;
 386
 387        hop1_pte_addr = get_hop1_pte_addr(ctx, hop1_addr, virt_addr);
 388        hop1_pte = hdev->asic_funcs->read_pte(hdev, hop1_pte_addr);
 389        hop2_addr = get_next_hop_addr(hop1_pte);
 390
 391        if (hop2_addr == ULLONG_MAX)
 392                goto not_mapped;
 393
 394        hop2_pte_addr = get_hop2_pte_addr(ctx, hop2_addr, virt_addr);
 395        hop2_pte = hdev->asic_funcs->read_pte(hdev, hop2_pte_addr);
 396        hop3_addr = get_next_hop_addr(hop2_pte);
 397
 398        if (hop3_addr == ULLONG_MAX)
 399                goto not_mapped;
 400
 401        hop3_pte_addr = get_hop3_pte_addr(ctx, hop3_addr, virt_addr);
 402        hop3_pte = hdev->asic_funcs->read_pte(hdev, hop3_pte_addr);
 403
 404        if (!(hop3_pte & LAST_MASK)) {
 405                hop4_addr = get_next_hop_addr(hop3_pte);
 406
 407                if (hop4_addr == ULLONG_MAX)
 408                        goto not_mapped;
 409
 410                hop4_pte_addr = get_hop4_pte_addr(ctx, hop4_addr, virt_addr);
 411                hop4_pte = hdev->asic_funcs->read_pte(hdev, hop4_pte_addr);
 412                if (!(hop4_pte & PAGE_PRESENT_MASK))
 413                        goto not_mapped;
 414        } else {
 415                if (!(hop3_pte & PAGE_PRESENT_MASK))
 416                        goto not_mapped;
 417        }
 418
 419        seq_printf(s, "asid: %u, virt_addr: 0x%llx\n",
 420                        dev_entry->mmu_asid, dev_entry->mmu_addr);
 421
 422        seq_printf(s, "hop0_addr: 0x%llx\n", hop0_addr);
 423        seq_printf(s, "hop0_pte_addr: 0x%llx\n", hop0_pte_addr);
 424        seq_printf(s, "hop0_pte: 0x%llx\n", hop0_pte);
 425
 426        seq_printf(s, "hop1_addr: 0x%llx\n", hop1_addr);
 427        seq_printf(s, "hop1_pte_addr: 0x%llx\n", hop1_pte_addr);
 428        seq_printf(s, "hop1_pte: 0x%llx\n", hop1_pte);
 429
 430        seq_printf(s, "hop2_addr: 0x%llx\n", hop2_addr);
 431        seq_printf(s, "hop2_pte_addr: 0x%llx\n", hop2_pte_addr);
 432        seq_printf(s, "hop2_pte: 0x%llx\n", hop2_pte);
 433
 434        seq_printf(s, "hop3_addr: 0x%llx\n", hop3_addr);
 435        seq_printf(s, "hop3_pte_addr: 0x%llx\n", hop3_pte_addr);
 436        seq_printf(s, "hop3_pte: 0x%llx\n", hop3_pte);
 437
 438        if (!(hop3_pte & LAST_MASK)) {
 439                seq_printf(s, "hop4_addr: 0x%llx\n", hop4_addr);
 440                seq_printf(s, "hop4_pte_addr: 0x%llx\n", hop4_pte_addr);
 441                seq_printf(s, "hop4_pte: 0x%llx\n", hop4_pte);
 442        }
 443
 444        goto out;
 445
 446not_mapped:
 447        dev_err(hdev->dev, "virt addr 0x%llx is not mapped to phys addr\n",
 448                        virt_addr);
 449out:
 450        mutex_unlock(&ctx->mmu_lock);
 451
 452        return 0;
 453}
 454
 455static ssize_t mmu_write(struct file *file, const char __user *buf,
 456                size_t count, loff_t *f_pos)
 457{
 458        struct seq_file *s = file->private_data;
 459        struct hl_debugfs_entry *entry = s->private;
 460        struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
 461        struct hl_device *hdev = dev_entry->hdev;
 462        char kbuf[MMU_KBUF_SIZE];
 463        char *c;
 464        ssize_t rc;
 465
 466        if (!hdev->mmu_enable)
 467                return count;
 468
 469        if (count > sizeof(kbuf) - 1)
 470                goto err;
 471        if (copy_from_user(kbuf, buf, count))
 472                goto err;
 473        kbuf[count] = 0;
 474
 475        c = strchr(kbuf, ' ');
 476        if (!c)
 477                goto err;
 478        *c = '\0';
 479
 480        rc = kstrtouint(kbuf, 10, &dev_entry->mmu_asid);
 481        if (rc)
 482                goto err;
 483
 484        if (strncmp(c+1, "0x", 2))
 485                goto err;
 486        rc = kstrtoull(c+3, 16, &dev_entry->mmu_addr);
 487        if (rc)
 488                goto err;
 489
 490        return count;
 491
 492err:
 493        dev_err(hdev->dev, "usage: echo <asid> <0xaddr> > mmu\n");
 494
 495        return -EINVAL;
 496}
 497
 498static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr,
 499                                u64 *phys_addr)
 500{
 501        struct hl_ctx *ctx = hdev->user_ctx;
 502        u64 hop_addr, hop_pte_addr, hop_pte;
 503        u64 offset_mask = HOP4_MASK | OFFSET_MASK;
 504        int rc = 0;
 505
 506        if (!ctx) {
 507                dev_err(hdev->dev, "no ctx available\n");
 508                return -EINVAL;
 509        }
 510
 511        mutex_lock(&ctx->mmu_lock);
 512
 513        /* hop 0 */
 514        hop_addr = get_hop0_addr(ctx);
 515        hop_pte_addr = get_hop0_pte_addr(ctx, hop_addr, virt_addr);
 516        hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
 517
 518        /* hop 1 */
 519        hop_addr = get_next_hop_addr(hop_pte);
 520        if (hop_addr == ULLONG_MAX)
 521                goto not_mapped;
 522        hop_pte_addr = get_hop1_pte_addr(ctx, hop_addr, virt_addr);
 523        hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
 524
 525        /* hop 2 */
 526        hop_addr = get_next_hop_addr(hop_pte);
 527        if (hop_addr == ULLONG_MAX)
 528                goto not_mapped;
 529        hop_pte_addr = get_hop2_pte_addr(ctx, hop_addr, virt_addr);
 530        hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
 531
 532        /* hop 3 */
 533        hop_addr = get_next_hop_addr(hop_pte);
 534        if (hop_addr == ULLONG_MAX)
 535                goto not_mapped;
 536        hop_pte_addr = get_hop3_pte_addr(ctx, hop_addr, virt_addr);
 537        hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
 538
 539        if (!(hop_pte & LAST_MASK)) {
 540                /* hop 4 */
 541                hop_addr = get_next_hop_addr(hop_pte);
 542                if (hop_addr == ULLONG_MAX)
 543                        goto not_mapped;
 544                hop_pte_addr = get_hop4_pte_addr(ctx, hop_addr, virt_addr);
 545                hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
 546
 547                offset_mask = OFFSET_MASK;
 548        }
 549
 550        if (!(hop_pte & PAGE_PRESENT_MASK))
 551                goto not_mapped;
 552
 553        *phys_addr = (hop_pte & ~offset_mask) | (virt_addr & offset_mask);
 554
 555        goto out;
 556
 557not_mapped:
 558        dev_err(hdev->dev, "virt addr 0x%llx is not mapped to phys addr\n",
 559                        virt_addr);
 560        rc = -EINVAL;
 561out:
 562        mutex_unlock(&ctx->mmu_lock);
 563        return rc;
 564}
 565
 566static ssize_t hl_data_read32(struct file *f, char __user *buf,
 567                                        size_t count, loff_t *ppos)
 568{
 569        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 570        struct hl_device *hdev = entry->hdev;
 571        struct asic_fixed_properties *prop = &hdev->asic_prop;
 572        char tmp_buf[32];
 573        u64 addr = entry->addr;
 574        u32 val;
 575        ssize_t rc;
 576
 577        if (*ppos)
 578                return 0;
 579
 580        if (addr >= prop->va_space_dram_start_address &&
 581                        addr < prop->va_space_dram_end_address &&
 582                        hdev->mmu_enable &&
 583                        hdev->dram_supports_virtual_memory) {
 584                rc = device_va_to_pa(hdev, entry->addr, &addr);
 585                if (rc)
 586                        return rc;
 587        }
 588
 589        rc = hdev->asic_funcs->debugfs_read32(hdev, addr, &val);
 590        if (rc) {
 591                dev_err(hdev->dev, "Failed to read from 0x%010llx\n", addr);
 592                return rc;
 593        }
 594
 595        sprintf(tmp_buf, "0x%08x\n", val);
 596        return simple_read_from_buffer(buf, count, ppos, tmp_buf,
 597                        strlen(tmp_buf));
 598}
 599
 600static ssize_t hl_data_write32(struct file *f, const char __user *buf,
 601                                        size_t count, loff_t *ppos)
 602{
 603        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 604        struct hl_device *hdev = entry->hdev;
 605        struct asic_fixed_properties *prop = &hdev->asic_prop;
 606        u64 addr = entry->addr;
 607        u32 value;
 608        ssize_t rc;
 609
 610        rc = kstrtouint_from_user(buf, count, 16, &value);
 611        if (rc)
 612                return rc;
 613
 614        if (addr >= prop->va_space_dram_start_address &&
 615                        addr < prop->va_space_dram_end_address &&
 616                        hdev->mmu_enable &&
 617                        hdev->dram_supports_virtual_memory) {
 618                rc = device_va_to_pa(hdev, entry->addr, &addr);
 619                if (rc)
 620                        return rc;
 621        }
 622
 623        rc = hdev->asic_funcs->debugfs_write32(hdev, addr, value);
 624        if (rc) {
 625                dev_err(hdev->dev, "Failed to write 0x%08x to 0x%010llx\n",
 626                        value, addr);
 627                return rc;
 628        }
 629
 630        return count;
 631}
 632
 633static ssize_t hl_get_power_state(struct file *f, char __user *buf,
 634                size_t count, loff_t *ppos)
 635{
 636        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 637        struct hl_device *hdev = entry->hdev;
 638        char tmp_buf[200];
 639        int i;
 640
 641        if (*ppos)
 642                return 0;
 643
 644        if (hdev->pdev->current_state == PCI_D0)
 645                i = 1;
 646        else if (hdev->pdev->current_state == PCI_D3hot)
 647                i = 2;
 648        else
 649                i = 3;
 650
 651        sprintf(tmp_buf,
 652                "current power state: %d\n1 - D0\n2 - D3hot\n3 - Unknown\n", i);
 653        return simple_read_from_buffer(buf, count, ppos, tmp_buf,
 654                        strlen(tmp_buf));
 655}
 656
 657static ssize_t hl_set_power_state(struct file *f, const char __user *buf,
 658                                        size_t count, loff_t *ppos)
 659{
 660        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 661        struct hl_device *hdev = entry->hdev;
 662        u32 value;
 663        ssize_t rc;
 664
 665        rc = kstrtouint_from_user(buf, count, 10, &value);
 666        if (rc)
 667                return rc;
 668
 669        if (value == 1) {
 670                pci_set_power_state(hdev->pdev, PCI_D0);
 671                pci_restore_state(hdev->pdev);
 672                rc = pci_enable_device(hdev->pdev);
 673        } else if (value == 2) {
 674                pci_save_state(hdev->pdev);
 675                pci_disable_device(hdev->pdev);
 676                pci_set_power_state(hdev->pdev, PCI_D3hot);
 677        } else {
 678                dev_dbg(hdev->dev, "invalid power state value %u\n", value);
 679                return -EINVAL;
 680        }
 681
 682        return count;
 683}
 684
 685static ssize_t hl_i2c_data_read(struct file *f, char __user *buf,
 686                                        size_t count, loff_t *ppos)
 687{
 688        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 689        struct hl_device *hdev = entry->hdev;
 690        char tmp_buf[32];
 691        u32 val;
 692        ssize_t rc;
 693
 694        if (*ppos)
 695                return 0;
 696
 697        rc = hl_debugfs_i2c_read(hdev, entry->i2c_bus, entry->i2c_addr,
 698                        entry->i2c_reg, &val);
 699        if (rc) {
 700                dev_err(hdev->dev,
 701                        "Failed to read from I2C bus %d, addr %d, reg %d\n",
 702                        entry->i2c_bus, entry->i2c_addr, entry->i2c_reg);
 703                return rc;
 704        }
 705
 706        sprintf(tmp_buf, "0x%02x\n", val);
 707        rc = simple_read_from_buffer(buf, count, ppos, tmp_buf,
 708                        strlen(tmp_buf));
 709
 710        return rc;
 711}
 712
 713static ssize_t hl_i2c_data_write(struct file *f, const char __user *buf,
 714                                        size_t count, loff_t *ppos)
 715{
 716        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 717        struct hl_device *hdev = entry->hdev;
 718        u32 value;
 719        ssize_t rc;
 720
 721        rc = kstrtouint_from_user(buf, count, 16, &value);
 722        if (rc)
 723                return rc;
 724
 725        rc = hl_debugfs_i2c_write(hdev, entry->i2c_bus, entry->i2c_addr,
 726                        entry->i2c_reg, value);
 727        if (rc) {
 728                dev_err(hdev->dev,
 729                        "Failed to write 0x%02x to I2C bus %d, addr %d, reg %d\n",
 730                        value, entry->i2c_bus, entry->i2c_addr, entry->i2c_reg);
 731                return rc;
 732        }
 733
 734        return count;
 735}
 736
 737static ssize_t hl_led0_write(struct file *f, const char __user *buf,
 738                                        size_t count, loff_t *ppos)
 739{
 740        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 741        struct hl_device *hdev = entry->hdev;
 742        u32 value;
 743        ssize_t rc;
 744
 745        rc = kstrtouint_from_user(buf, count, 10, &value);
 746        if (rc)
 747                return rc;
 748
 749        value = value ? 1 : 0;
 750
 751        hl_debugfs_led_set(hdev, 0, value);
 752
 753        return count;
 754}
 755
 756static ssize_t hl_led1_write(struct file *f, const char __user *buf,
 757                                        size_t count, loff_t *ppos)
 758{
 759        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 760        struct hl_device *hdev = entry->hdev;
 761        u32 value;
 762        ssize_t rc;
 763
 764        rc = kstrtouint_from_user(buf, count, 10, &value);
 765        if (rc)
 766                return rc;
 767
 768        value = value ? 1 : 0;
 769
 770        hl_debugfs_led_set(hdev, 1, value);
 771
 772        return count;
 773}
 774
 775static ssize_t hl_led2_write(struct file *f, const char __user *buf,
 776                                        size_t count, loff_t *ppos)
 777{
 778        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 779        struct hl_device *hdev = entry->hdev;
 780        u32 value;
 781        ssize_t rc;
 782
 783        rc = kstrtouint_from_user(buf, count, 10, &value);
 784        if (rc)
 785                return rc;
 786
 787        value = value ? 1 : 0;
 788
 789        hl_debugfs_led_set(hdev, 2, value);
 790
 791        return count;
 792}
 793
 794static ssize_t hl_device_read(struct file *f, char __user *buf,
 795                                        size_t count, loff_t *ppos)
 796{
 797        static const char *help =
 798                "Valid values: disable, enable, suspend, resume, cpu_timeout\n";
 799        return simple_read_from_buffer(buf, count, ppos, help, strlen(help));
 800}
 801
 802static ssize_t hl_device_write(struct file *f, const char __user *buf,
 803                                     size_t count, loff_t *ppos)
 804{
 805        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 806        struct hl_device *hdev = entry->hdev;
 807        char data[30] = {0};
 808
 809        /* don't allow partial writes */
 810        if (*ppos != 0)
 811                return 0;
 812
 813        simple_write_to_buffer(data, 29, ppos, buf, count);
 814
 815        if (strncmp("disable", data, strlen("disable")) == 0) {
 816                hdev->disabled = true;
 817        } else if (strncmp("enable", data, strlen("enable")) == 0) {
 818                hdev->disabled = false;
 819        } else if (strncmp("suspend", data, strlen("suspend")) == 0) {
 820                hdev->asic_funcs->suspend(hdev);
 821        } else if (strncmp("resume", data, strlen("resume")) == 0) {
 822                hdev->asic_funcs->resume(hdev);
 823        } else if (strncmp("cpu_timeout", data, strlen("cpu_timeout")) == 0) {
 824                hdev->device_cpu_disabled = true;
 825        } else {
 826                dev_err(hdev->dev,
 827                        "Valid values: disable, enable, suspend, resume, cpu_timeout\n");
 828                count = -EINVAL;
 829        }
 830
 831        return count;
 832}
 833
 834static const struct file_operations hl_data32b_fops = {
 835        .owner = THIS_MODULE,
 836        .read = hl_data_read32,
 837        .write = hl_data_write32
 838};
 839
 840static const struct file_operations hl_i2c_data_fops = {
 841        .owner = THIS_MODULE,
 842        .read = hl_i2c_data_read,
 843        .write = hl_i2c_data_write
 844};
 845
 846static const struct file_operations hl_power_fops = {
 847        .owner = THIS_MODULE,
 848        .read = hl_get_power_state,
 849        .write = hl_set_power_state
 850};
 851
 852static const struct file_operations hl_led0_fops = {
 853        .owner = THIS_MODULE,
 854        .write = hl_led0_write
 855};
 856
 857static const struct file_operations hl_led1_fops = {
 858        .owner = THIS_MODULE,
 859        .write = hl_led1_write
 860};
 861
 862static const struct file_operations hl_led2_fops = {
 863        .owner = THIS_MODULE,
 864        .write = hl_led2_write
 865};
 866
 867static const struct file_operations hl_device_fops = {
 868        .owner = THIS_MODULE,
 869        .read = hl_device_read,
 870        .write = hl_device_write
 871};
 872
 873static const struct hl_info_list hl_debugfs_list[] = {
 874        {"command_buffers", command_buffers_show, NULL},
 875        {"command_submission", command_submission_show, NULL},
 876        {"command_submission_jobs", command_submission_jobs_show, NULL},
 877        {"userptr", userptr_show, NULL},
 878        {"vm", vm_show, NULL},
 879        {"mmu", mmu_show, mmu_write},
 880};
 881
 882static int hl_debugfs_open(struct inode *inode, struct file *file)
 883{
 884        struct hl_debugfs_entry *node = inode->i_private;
 885
 886        return single_open(file, node->info_ent->show, node);
 887}
 888
 889static ssize_t hl_debugfs_write(struct file *file, const char __user *buf,
 890                size_t count, loff_t *f_pos)
 891{
 892        struct hl_debugfs_entry *node = file->f_inode->i_private;
 893
 894        if (node->info_ent->write)
 895                return node->info_ent->write(file, buf, count, f_pos);
 896        else
 897                return -EINVAL;
 898
 899}
 900
 901static const struct file_operations hl_debugfs_fops = {
 902        .owner = THIS_MODULE,
 903        .open = hl_debugfs_open,
 904        .read = seq_read,
 905        .write = hl_debugfs_write,
 906        .llseek = seq_lseek,
 907        .release = single_release,
 908};
 909
 910void hl_debugfs_add_device(struct hl_device *hdev)
 911{
 912        struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs;
 913        int count = ARRAY_SIZE(hl_debugfs_list);
 914        struct hl_debugfs_entry *entry;
 915        struct dentry *ent;
 916        int i;
 917
 918        dev_entry->hdev = hdev;
 919        dev_entry->entry_arr = kmalloc_array(count,
 920                                        sizeof(struct hl_debugfs_entry),
 921                                        GFP_KERNEL);
 922        if (!dev_entry->entry_arr)
 923                return;
 924
 925        INIT_LIST_HEAD(&dev_entry->file_list);
 926        INIT_LIST_HEAD(&dev_entry->cb_list);
 927        INIT_LIST_HEAD(&dev_entry->cs_list);
 928        INIT_LIST_HEAD(&dev_entry->cs_job_list);
 929        INIT_LIST_HEAD(&dev_entry->userptr_list);
 930        INIT_LIST_HEAD(&dev_entry->ctx_mem_hash_list);
 931        mutex_init(&dev_entry->file_mutex);
 932        spin_lock_init(&dev_entry->cb_spinlock);
 933        spin_lock_init(&dev_entry->cs_spinlock);
 934        spin_lock_init(&dev_entry->cs_job_spinlock);
 935        spin_lock_init(&dev_entry->userptr_spinlock);
 936        spin_lock_init(&dev_entry->ctx_mem_hash_spinlock);
 937
 938        dev_entry->root = debugfs_create_dir(dev_name(hdev->dev),
 939                                                hl_debug_root);
 940
 941        debugfs_create_x64("addr",
 942                                0644,
 943                                dev_entry->root,
 944                                &dev_entry->addr);
 945
 946        debugfs_create_file("data32",
 947                                0644,
 948                                dev_entry->root,
 949                                dev_entry,
 950                                &hl_data32b_fops);
 951
 952        debugfs_create_file("set_power_state",
 953                                0200,
 954                                dev_entry->root,
 955                                dev_entry,
 956                                &hl_power_fops);
 957
 958        debugfs_create_u8("i2c_bus",
 959                                0644,
 960                                dev_entry->root,
 961                                &dev_entry->i2c_bus);
 962
 963        debugfs_create_u8("i2c_addr",
 964                                0644,
 965                                dev_entry->root,
 966                                &dev_entry->i2c_addr);
 967
 968        debugfs_create_u8("i2c_reg",
 969                                0644,
 970                                dev_entry->root,
 971                                &dev_entry->i2c_reg);
 972
 973        debugfs_create_file("i2c_data",
 974                                0644,
 975                                dev_entry->root,
 976                                dev_entry,
 977                                &hl_i2c_data_fops);
 978
 979        debugfs_create_file("led0",
 980                                0200,
 981                                dev_entry->root,
 982                                dev_entry,
 983                                &hl_led0_fops);
 984
 985        debugfs_create_file("led1",
 986                                0200,
 987                                dev_entry->root,
 988                                dev_entry,
 989                                &hl_led1_fops);
 990
 991        debugfs_create_file("led2",
 992                                0200,
 993                                dev_entry->root,
 994                                dev_entry,
 995                                &hl_led2_fops);
 996
 997        debugfs_create_file("device",
 998                                0200,
 999                                dev_entry->root,
1000                                dev_entry,
1001                                &hl_device_fops);
1002
1003        for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) {
1004
1005                ent = debugfs_create_file(hl_debugfs_list[i].name,
1006                                        0444,
1007                                        dev_entry->root,
1008                                        entry,
1009                                        &hl_debugfs_fops);
1010                entry->dent = ent;
1011                entry->info_ent = &hl_debugfs_list[i];
1012                entry->dev_entry = dev_entry;
1013        }
1014}
1015
1016void hl_debugfs_remove_device(struct hl_device *hdev)
1017{
1018        struct hl_dbg_device_entry *entry = &hdev->hl_debugfs;
1019
1020        debugfs_remove_recursive(entry->root);
1021
1022        mutex_destroy(&entry->file_mutex);
1023        kfree(entry->entry_arr);
1024}
1025
1026void hl_debugfs_add_file(struct hl_fpriv *hpriv)
1027{
1028        struct hl_dbg_device_entry *dev_entry = &hpriv->hdev->hl_debugfs;
1029
1030        mutex_lock(&dev_entry->file_mutex);
1031        list_add(&hpriv->debugfs_list, &dev_entry->file_list);
1032        mutex_unlock(&dev_entry->file_mutex);
1033}
1034
1035void hl_debugfs_remove_file(struct hl_fpriv *hpriv)
1036{
1037        struct hl_dbg_device_entry *dev_entry = &hpriv->hdev->hl_debugfs;
1038
1039        mutex_lock(&dev_entry->file_mutex);
1040        list_del(&hpriv->debugfs_list);
1041        mutex_unlock(&dev_entry->file_mutex);
1042}
1043
1044void hl_debugfs_add_cb(struct hl_cb *cb)
1045{
1046        struct hl_dbg_device_entry *dev_entry = &cb->hdev->hl_debugfs;
1047
1048        spin_lock(&dev_entry->cb_spinlock);
1049        list_add(&cb->debugfs_list, &dev_entry->cb_list);
1050        spin_unlock(&dev_entry->cb_spinlock);
1051}
1052
1053void hl_debugfs_remove_cb(struct hl_cb *cb)
1054{
1055        struct hl_dbg_device_entry *dev_entry = &cb->hdev->hl_debugfs;
1056
1057        spin_lock(&dev_entry->cb_spinlock);
1058        list_del(&cb->debugfs_list);
1059        spin_unlock(&dev_entry->cb_spinlock);
1060}
1061
1062void hl_debugfs_add_cs(struct hl_cs *cs)
1063{
1064        struct hl_dbg_device_entry *dev_entry = &cs->ctx->hdev->hl_debugfs;
1065
1066        spin_lock(&dev_entry->cs_spinlock);
1067        list_add(&cs->debugfs_list, &dev_entry->cs_list);
1068        spin_unlock(&dev_entry->cs_spinlock);
1069}
1070
1071void hl_debugfs_remove_cs(struct hl_cs *cs)
1072{
1073        struct hl_dbg_device_entry *dev_entry = &cs->ctx->hdev->hl_debugfs;
1074
1075        spin_lock(&dev_entry->cs_spinlock);
1076        list_del(&cs->debugfs_list);
1077        spin_unlock(&dev_entry->cs_spinlock);
1078}
1079
1080void hl_debugfs_add_job(struct hl_device *hdev, struct hl_cs_job *job)
1081{
1082        struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs;
1083
1084        spin_lock(&dev_entry->cs_job_spinlock);
1085        list_add(&job->debugfs_list, &dev_entry->cs_job_list);
1086        spin_unlock(&dev_entry->cs_job_spinlock);
1087}
1088
1089void hl_debugfs_remove_job(struct hl_device *hdev, struct hl_cs_job *job)
1090{
1091        struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs;
1092
1093        spin_lock(&dev_entry->cs_job_spinlock);
1094        list_del(&job->debugfs_list);
1095        spin_unlock(&dev_entry->cs_job_spinlock);
1096}
1097
1098void hl_debugfs_add_userptr(struct hl_device *hdev, struct hl_userptr *userptr)
1099{
1100        struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs;
1101
1102        spin_lock(&dev_entry->userptr_spinlock);
1103        list_add(&userptr->debugfs_list, &dev_entry->userptr_list);
1104        spin_unlock(&dev_entry->userptr_spinlock);
1105}
1106
1107void hl_debugfs_remove_userptr(struct hl_device *hdev,
1108                                struct hl_userptr *userptr)
1109{
1110        struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs;
1111
1112        spin_lock(&dev_entry->userptr_spinlock);
1113        list_del(&userptr->debugfs_list);
1114        spin_unlock(&dev_entry->userptr_spinlock);
1115}
1116
1117void hl_debugfs_add_ctx_mem_hash(struct hl_device *hdev, struct hl_ctx *ctx)
1118{
1119        struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs;
1120
1121        spin_lock(&dev_entry->ctx_mem_hash_spinlock);
1122        list_add(&ctx->debugfs_list, &dev_entry->ctx_mem_hash_list);
1123        spin_unlock(&dev_entry->ctx_mem_hash_spinlock);
1124}
1125
1126void hl_debugfs_remove_ctx_mem_hash(struct hl_device *hdev, struct hl_ctx *ctx)
1127{
1128        struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs;
1129
1130        spin_lock(&dev_entry->ctx_mem_hash_spinlock);
1131        list_del(&ctx->debugfs_list);
1132        spin_unlock(&dev_entry->ctx_mem_hash_spinlock);
1133}
1134
1135void __init hl_debugfs_init(void)
1136{
1137        hl_debug_root = debugfs_create_dir("habanalabs", NULL);
1138}
1139
1140void hl_debugfs_fini(void)
1141{
1142        debugfs_remove_recursive(hl_debug_root);
1143}
1144