Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/accel/habanalabs/common/decoder.c
26436 views
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
143