GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / accel / habanalabs / common / decoder.c
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 }