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