xref: /linux/drivers/gpu/drm/xe/xe_drm_ras.c (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2026 Intel Corporation
4  */
5 
6 #include <linux/bitmap.h>
7 
8 #include <drm/drm_managed.h>
9 #include <drm/drm_print.h>
10 #include <drm/drm_ras.h>
11 
12 #include "xe_device_types.h"
13 #include "xe_drm_ras.h"
14 #include "xe_ras.h"
15 
16 static const char * const error_components[] = DRM_XE_RAS_ERROR_COMPONENT_NAMES;
17 static const char * const error_severity[] = DRM_XE_RAS_ERROR_SEVERITY_NAMES;
18 
19 static int query_error_counter(struct xe_device *xe,
20 			       enum drm_xe_ras_error_severity severity,
21 			       u32 error_id, const char **name, u32 *val)
22 {
23 	struct xe_drm_ras *ras = &xe->ras;
24 	struct xe_drm_ras_counter *info = ras->info[severity];
25 
26 	if (!info || !info[error_id].name)
27 		return -ENOENT;
28 
29 	*name = info[error_id].name;
30 
31 	/* Fetch counter from system controller if supported */
32 	if (xe->info.has_sysctrl)
33 		return xe_ras_get_counter(xe, severity, error_id, val);
34 
35 	*val = atomic_read(&info[error_id].counter);
36 
37 	return 0;
38 }
39 
40 static int clear_error_counter(struct xe_device *xe,
41 			       enum drm_xe_ras_error_severity severity,
42 			       u32 error_id)
43 {
44 	struct xe_drm_ras *ras = &xe->ras;
45 	struct xe_drm_ras_counter *info = ras->info[severity];
46 
47 	if (!info || !info[error_id].name)
48 		return -ENOENT;
49 
50 	/* Clear counter from system controller if supported */
51 	if (xe->info.has_sysctrl)
52 		return xe_ras_clear_counter(xe, severity, error_id);
53 
54 	atomic_set(&info[error_id].counter, 0);
55 
56 	return 0;
57 }
58 
59 static int query_uncorrectable_error_counter(struct drm_ras_node *ep, u32 error_id,
60 					     const char **name, u32 *val)
61 {
62 	struct xe_device *xe = ep->priv;
63 
64 	return query_error_counter(xe, DRM_XE_RAS_ERR_SEV_UNCORRECTABLE, error_id, name, val);
65 }
66 
67 static int clear_uncorrectable_error_counter(struct drm_ras_node *node, u32 error_id)
68 {
69 	struct xe_device *xe = node->priv;
70 
71 	return clear_error_counter(xe, DRM_XE_RAS_ERR_SEV_UNCORRECTABLE, error_id);
72 }
73 
74 static int query_correctable_error_counter(struct drm_ras_node *ep, u32 error_id,
75 					   const char **name, u32 *val)
76 {
77 	struct xe_device *xe = ep->priv;
78 
79 	return query_error_counter(xe, DRM_XE_RAS_ERR_SEV_CORRECTABLE, error_id, name, val);
80 }
81 
82 static int clear_correctable_error_counter(struct drm_ras_node *node, u32 error_id)
83 {
84 	struct xe_device *xe = node->priv;
85 
86 	return clear_error_counter(xe, DRM_XE_RAS_ERR_SEV_CORRECTABLE, error_id);
87 }
88 
89 static struct xe_drm_ras_counter *allocate_and_copy_counters(struct xe_device *xe)
90 {
91 	struct xe_drm_ras_counter *counter;
92 	int i;
93 
94 	counter = drmm_kcalloc(&xe->drm, DRM_XE_RAS_ERR_COMP_MAX, sizeof(*counter), GFP_KERNEL);
95 	if (!counter)
96 		return ERR_PTR(-ENOMEM);
97 
98 	for (i = DRM_XE_RAS_ERR_COMP_CORE_COMPUTE; i < DRM_XE_RAS_ERR_COMP_MAX; i++) {
99 		if (!error_components[i])
100 			continue;
101 
102 		counter[i].name = error_components[i];
103 		atomic_set(&counter[i].counter, 0);
104 	}
105 
106 	return counter;
107 }
108 
109 static int assign_node_params(struct xe_device *xe, struct drm_ras_node *node,
110 			      const enum drm_xe_ras_error_severity severity)
111 {
112 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
113 	struct xe_drm_ras *ras = &xe->ras;
114 	const char *device_name;
115 
116 	device_name = kasprintf(GFP_KERNEL, "%04x:%02x:%02x.%d",
117 				pci_domain_nr(pdev->bus), pdev->bus->number,
118 				PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
119 
120 	if (!device_name)
121 		return -ENOMEM;
122 
123 	node->device_name = device_name;
124 	node->node_name = error_severity[severity];
125 	node->type = DRM_RAS_NODE_TYPE_ERROR_COUNTER;
126 	node->error_counter_range.first = DRM_XE_RAS_ERR_COMP_CORE_COMPUTE;
127 	node->error_counter_range.last = DRM_XE_RAS_ERR_COMP_MAX - 1;
128 	node->priv = xe;
129 
130 	ras->info[severity] = allocate_and_copy_counters(xe);
131 	if (IS_ERR(ras->info[severity]))
132 		return PTR_ERR(ras->info[severity]);
133 
134 	if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE) {
135 		node->query_error_counter = query_correctable_error_counter;
136 		node->clear_error_counter = clear_correctable_error_counter;
137 	} else {
138 		node->query_error_counter = query_uncorrectable_error_counter;
139 		node->clear_error_counter = clear_uncorrectable_error_counter;
140 	}
141 
142 	return 0;
143 }
144 
145 static void cleanup_node_param(struct drm_ras_node *node)
146 {
147 	kfree(node->device_name);
148 	node->device_name = NULL;
149 }
150 
151 static void cleanup_node(struct drm_device *drm, void *node)
152 {
153 	drm_ras_node_unregister(node);
154 	cleanup_node_param(node);
155 }
156 
157 static int register_nodes(struct xe_device *xe)
158 {
159 	struct xe_drm_ras *ras = &xe->ras;
160 	struct drm_ras_node *node;
161 	int i, ret;
162 
163 	for_each_error_severity(i) {
164 		node = &ras->node[i];
165 
166 		ret = assign_node_params(xe, node, i);
167 		if (ret)
168 			goto free_param;
169 
170 		ret = drm_ras_node_register(node);
171 		if (ret)
172 			goto free_param;
173 
174 		ret = drmm_add_action_or_reset(&xe->drm, cleanup_node, node);
175 		if (ret)
176 			goto null_info;
177 	}
178 
179 	return 0;
180 
181 free_param:
182 	cleanup_node_param(node);
183 null_info:
184 	ras->info[i] = NULL;
185 	return ret;
186 }
187 
188 /**
189  * xe_drm_ras_init() - Initialize DRM RAS
190  * @xe: xe device instance
191  *
192  * Allocate and register DRM RAS nodes per device
193  *
194  * Return: 0 on success, negative error code otherwise.
195  */
196 int xe_drm_ras_init(struct xe_device *xe)
197 {
198 	struct xe_drm_ras *ras = &xe->ras;
199 	struct drm_ras_node *node;
200 	int err;
201 
202 	if (!xe->info.has_drm_ras)
203 		return 0;
204 
205 	node = drmm_kcalloc(&xe->drm, DRM_XE_RAS_ERR_SEV_MAX, sizeof(*node), GFP_KERNEL);
206 	if (!node)
207 		return -ENOMEM;
208 
209 	ras->node = node;
210 
211 	err = register_nodes(xe);
212 	if (err) {
213 		drm_err(&xe->drm, "Failed to register DRM RAS nodes (%pe)\n", ERR_PTR(err));
214 		return err;
215 	}
216 
217 	return 0;
218 }
219