Loading...
Note: File does not exist in v3.1.
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
20static 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
46static void dec_error_intr_work(struct hl_device *hdev, u32 base_addr, u32 core_id)
47{
48 bool reset_required = false;
49 u32 irq_status;
50
51 irq_status = RREG32(base_addr + VCMD_IRQ_STATUS_OFFSET);
52
53 dev_err(hdev->dev, "Decoder abnormal interrupt %#x, core %d\n", irq_status, core_id);
54
55 dec_print_abnrm_intr_source(hdev, irq_status);
56
57 if (irq_status & VCMD_IRQ_STATUS_TIMEOUT_MASK)
58 reset_required = true;
59
60 /* Clear the interrupt */
61 WREG32(base_addr + VCMD_IRQ_STATUS_OFFSET, irq_status);
62
63 /* Flush the interrupt clear */
64 RREG32(base_addr + VCMD_IRQ_STATUS_OFFSET);
65
66 if (reset_required)
67 hl_device_reset(hdev, HL_DRV_RESET_HARD);
68}
69
70static void dec_completion_abnrm(struct work_struct *work)
71{
72 struct hl_dec *dec = container_of(work, struct hl_dec, completion_abnrm_work);
73 struct hl_device *hdev = dec->hdev;
74
75 dec_error_intr_work(hdev, dec->base_addr, dec->core_id);
76}
77
78void hl_dec_fini(struct hl_device *hdev)
79{
80 kfree(hdev->dec);
81}
82
83int hl_dec_init(struct hl_device *hdev)
84{
85 struct asic_fixed_properties *prop = &hdev->asic_prop;
86 struct hl_dec *dec;
87 int rc, j;
88
89 /* if max core is 0, nothing to do*/
90 if (!prop->max_dec)
91 return 0;
92
93 hdev->dec = kcalloc(prop->max_dec, sizeof(struct hl_dec), GFP_KERNEL);
94 if (!hdev->dec)
95 return -ENOMEM;
96
97 for (j = 0 ; j < prop->max_dec ; j++) {
98 dec = hdev->dec + j;
99
100 dec->hdev = hdev;
101 INIT_WORK(&dec->completion_abnrm_work, dec_completion_abnrm);
102 dec->core_id = j;
103 dec->base_addr = hdev->asic_funcs->get_dec_base_addr(hdev, j);
104 if (!dec->base_addr) {
105 dev_err(hdev->dev, "Invalid base address of decoder %d\n", j);
106 rc = -EINVAL;
107 goto err_dec_fini;
108 }
109 }
110
111 return 0;
112
113err_dec_fini:
114 hl_dec_fini(hdev);
115
116 return rc;
117}
118
119void hl_dec_ctx_fini(struct hl_ctx *ctx)
120{
121 struct hl_device *hdev = ctx->hdev;
122 struct asic_fixed_properties *prop = &hdev->asic_prop;
123 struct hl_dec *dec;
124 int j;
125
126 for (j = 0 ; j < prop->max_dec ; j++) {
127 if (!!(prop->decoder_enabled_mask & BIT(j))) {
128 dec = hdev->dec + j;
129 /* Stop the decoder */
130 WREG32(dec->base_addr + VCMD_CONTROL_OFFSET, 0);
131 }
132 }
133}