1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright 2022 HabanaLabs, Ltd.
8 #include "habanalabs.h"
10 #define VCMD_CONTROL_OFFSET 0x40 /* SWREG16 */
11 #define VCMD_IRQ_STATUS_OFFSET 0x44 /* SWREG17 */
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
20 static void dec_print_abnrm_intr_source(struct hl_device *hdev, u32 irq_status)
22 const char *format = "abnormal interrupt source:%s%s%s%s%s%s\n";
23 char *intr_source[6] = {"Unknown", "", "", "", "", ""};
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";
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]);
46 static void dec_abnrm_intr_work(struct work_struct *work)
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;
53 irq_status = RREG32(dec->base_addr + VCMD_IRQ_STATUS_OFFSET);
55 dev_err(hdev->dev, "Decoder abnormal interrupt %#x, core %d\n", irq_status, dec->core_id);
57 dec_print_abnrm_intr_source(hdev, irq_status);
59 /* Clear the interrupt */
60 WREG32(dec->base_addr + VCMD_IRQ_STATUS_OFFSET, irq_status);
62 /* Flush the interrupt clear */
63 RREG32(dec->base_addr + VCMD_IRQ_STATUS_OFFSET);
65 if (irq_status & VCMD_IRQ_STATUS_TIMEOUT_MASK) {
66 reset_required = true;
67 event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
70 if (irq_status & VCMD_IRQ_STATUS_CMDERR_MASK)
71 event_mask |= HL_NOTIFIER_EVENT_UNDEFINED_OPCODE;
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;
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);
86 void hl_dec_fini(struct hl_device *hdev)
91 int hl_dec_init(struct hl_device *hdev)
93 struct asic_fixed_properties *prop = &hdev->asic_prop;
97 /* if max core is 0, nothing to do*/
101 hdev->dec = kcalloc(prop->max_dec, sizeof(struct hl_dec), GFP_KERNEL);
105 for (j = 0 ; j < prop->max_dec ; j++) {
109 INIT_WORK(&dec->abnrm_intr_work, dec_abnrm_intr_work);
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);
127 void hl_dec_ctx_fini(struct hl_ctx *ctx)
129 struct hl_device *hdev = ctx->hdev;
130 struct asic_fixed_properties *prop = &hdev->asic_prop;
134 for (j = 0 ; j < prop->max_dec ; j++) {
135 if (!!(prop->decoder_enabled_mask & BIT(j))) {
137 /* Stop the decoder */
138 WREG32(dec->base_addr + VCMD_CONTROL_OFFSET, 0);