decoder.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2022 HabanaLabs, Ltd.
  4. * All Rights Reserved.
  5. */
  6. #include "habanalabs.h"
  7. #define VCMD_CONTROL_OFFSET 0x40 /* SWREG16 */
  8. #define VCMD_IRQ_STATUS_OFFSET 0x44 /* SWREG17 */
  9. #define VCMD_IRQ_STATUS_ENDCMD_MASK 0x1
  10. #define VCMD_IRQ_STATUS_BUSERR_MASK 0x2
  11. #define VCMD_IRQ_STATUS_TIMEOUT_MASK 0x4
  12. #define VCMD_IRQ_STATUS_CMDERR_MASK 0x8
  13. #define VCMD_IRQ_STATUS_ABORT_MASK 0x10
  14. #define VCMD_IRQ_STATUS_RESET_MASK 0x20
  15. static void dec_print_abnrm_intr_source(struct hl_device *hdev, u32 irq_status)
  16. {
  17. const char *format = "abnormal interrupt source:%s%s%s%s%s%s\n";
  18. char *intr_source[6] = {"Unknown", "", "", "", "", ""};
  19. int i = 0;
  20. if (!irq_status)
  21. return;
  22. if (irq_status & VCMD_IRQ_STATUS_ENDCMD_MASK)
  23. intr_source[i++] = " ENDCMD";
  24. if (irq_status & VCMD_IRQ_STATUS_BUSERR_MASK)
  25. intr_source[i++] = " BUSERR";
  26. if (irq_status & VCMD_IRQ_STATUS_TIMEOUT_MASK)
  27. intr_source[i++] = " TIMEOUT";
  28. if (irq_status & VCMD_IRQ_STATUS_CMDERR_MASK)
  29. intr_source[i++] = " CMDERR";
  30. if (irq_status & VCMD_IRQ_STATUS_ABORT_MASK)
  31. intr_source[i++] = " ABORT";
  32. if (irq_status & VCMD_IRQ_STATUS_RESET_MASK)
  33. intr_source[i++] = " RESET";
  34. dev_err(hdev->dev, format, intr_source[0], intr_source[1],
  35. intr_source[2], intr_source[3], intr_source[4], intr_source[5]);
  36. }
  37. static void dec_error_intr_work(struct hl_device *hdev, u32 base_addr, u32 core_id)
  38. {
  39. bool reset_required = false;
  40. u32 irq_status;
  41. irq_status = RREG32(base_addr + VCMD_IRQ_STATUS_OFFSET);
  42. dev_err(hdev->dev, "Decoder abnormal interrupt %#x, core %d\n", irq_status, core_id);
  43. dec_print_abnrm_intr_source(hdev, irq_status);
  44. if (irq_status & VCMD_IRQ_STATUS_TIMEOUT_MASK)
  45. reset_required = true;
  46. /* Clear the interrupt */
  47. WREG32(base_addr + VCMD_IRQ_STATUS_OFFSET, irq_status);
  48. /* Flush the interrupt clear */
  49. RREG32(base_addr + VCMD_IRQ_STATUS_OFFSET);
  50. if (reset_required)
  51. hl_device_reset(hdev, HL_DRV_RESET_HARD);
  52. }
  53. static void dec_completion_abnrm(struct work_struct *work)
  54. {
  55. struct hl_dec *dec = container_of(work, struct hl_dec, completion_abnrm_work);
  56. struct hl_device *hdev = dec->hdev;
  57. dec_error_intr_work(hdev, dec->base_addr, dec->core_id);
  58. }
  59. void hl_dec_fini(struct hl_device *hdev)
  60. {
  61. kfree(hdev->dec);
  62. }
  63. int hl_dec_init(struct hl_device *hdev)
  64. {
  65. struct asic_fixed_properties *prop = &hdev->asic_prop;
  66. struct hl_dec *dec;
  67. int rc, j;
  68. /* if max core is 0, nothing to do*/
  69. if (!prop->max_dec)
  70. return 0;
  71. hdev->dec = kcalloc(prop->max_dec, sizeof(struct hl_dec), GFP_KERNEL);
  72. if (!hdev->dec)
  73. return -ENOMEM;
  74. for (j = 0 ; j < prop->max_dec ; j++) {
  75. dec = hdev->dec + j;
  76. dec->hdev = hdev;
  77. INIT_WORK(&dec->completion_abnrm_work, dec_completion_abnrm);
  78. dec->core_id = j;
  79. dec->base_addr = hdev->asic_funcs->get_dec_base_addr(hdev, j);
  80. if (!dec->base_addr) {
  81. dev_err(hdev->dev, "Invalid base address of decoder %d\n", j);
  82. rc = -EINVAL;
  83. goto err_dec_fini;
  84. }
  85. }
  86. return 0;
  87. err_dec_fini:
  88. hl_dec_fini(hdev);
  89. return rc;
  90. }
  91. void hl_dec_ctx_fini(struct hl_ctx *ctx)
  92. {
  93. struct hl_device *hdev = ctx->hdev;
  94. struct asic_fixed_properties *prop = &hdev->asic_prop;
  95. struct hl_dec *dec;
  96. int j;
  97. for (j = 0 ; j < prop->max_dec ; j++) {
  98. if (!!(prop->decoder_enabled_mask & BIT(j))) {
  99. dec = hdev->dec + j;
  100. /* Stop the decoder */
  101. WREG32(dec->base_addr + VCMD_CONTROL_OFFSET, 0);
  102. }
  103. }
  104. }