xref: /openbmc/linux/drivers/edac/edac_pci.c (revision 3bb16560)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * EDAC PCI component
4  *
5  * Author: Dave Jiang <djiang@mvista.com>
6  *
7  * 2007 (c) MontaVista Software, Inc.
8  */
9 #include <asm/page.h>
10 #include <linux/uaccess.h>
11 #include <linux/ctype.h>
12 #include <linux/highmem.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/smp.h>
17 #include <linux/spinlock.h>
18 #include <linux/sysctl.h>
19 #include <linux/timer.h>
20 
21 #include "edac_pci.h"
22 #include "edac_module.h"
23 
24 static DEFINE_MUTEX(edac_pci_ctls_mutex);
25 static LIST_HEAD(edac_pci_list);
26 static atomic_t pci_indexes = ATOMIC_INIT(0);
27 
edac_pci_alloc_ctl_info(unsigned int sz_pvt,const char * edac_pci_name)28 struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
29 						  const char *edac_pci_name)
30 {
31 	struct edac_pci_ctl_info *pci;
32 
33 	edac_dbg(1, "\n");
34 
35 	pci = kzalloc(sizeof(struct edac_pci_ctl_info), GFP_KERNEL);
36 	if (!pci)
37 		return NULL;
38 
39 	if (sz_pvt) {
40 		pci->pvt_info = kzalloc(sz_pvt, GFP_KERNEL);
41 		if (!pci->pvt_info)
42 			goto free;
43 	}
44 
45 	pci->op_state = OP_ALLOC;
46 
47 	snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name);
48 
49 	return pci;
50 
51 free:
52 	kfree(pci);
53 	return NULL;
54 }
55 EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
56 
edac_pci_free_ctl_info(struct edac_pci_ctl_info * pci)57 void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
58 {
59 	edac_dbg(1, "\n");
60 
61 	edac_pci_remove_sysfs(pci);
62 }
63 EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info);
64 
65 /*
66  * find_edac_pci_by_dev()
67  * 	scans the edac_pci list for a specific 'struct device *'
68  *
69  *	return NULL if not found, or return control struct pointer
70  */
find_edac_pci_by_dev(struct device * dev)71 static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
72 {
73 	struct edac_pci_ctl_info *pci;
74 	struct list_head *item;
75 
76 	edac_dbg(1, "\n");
77 
78 	list_for_each(item, &edac_pci_list) {
79 		pci = list_entry(item, struct edac_pci_ctl_info, link);
80 
81 		if (pci->dev == dev)
82 			return pci;
83 	}
84 
85 	return NULL;
86 }
87 
88 /*
89  * add_edac_pci_to_global_list
90  * 	Before calling this function, caller must assign a unique value to
91  * 	edac_dev->pci_idx.
92  * 	Return:
93  * 		0 on success
94  * 		1 on failure
95  */
add_edac_pci_to_global_list(struct edac_pci_ctl_info * pci)96 static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
97 {
98 	struct list_head *item, *insert_before;
99 	struct edac_pci_ctl_info *rover;
100 
101 	edac_dbg(1, "\n");
102 
103 	insert_before = &edac_pci_list;
104 
105 	/* Determine if already on the list */
106 	rover = find_edac_pci_by_dev(pci->dev);
107 	if (unlikely(rover != NULL))
108 		goto fail0;
109 
110 	/* Insert in ascending order by 'pci_idx', so find position */
111 	list_for_each(item, &edac_pci_list) {
112 		rover = list_entry(item, struct edac_pci_ctl_info, link);
113 
114 		if (rover->pci_idx >= pci->pci_idx) {
115 			if (unlikely(rover->pci_idx == pci->pci_idx))
116 				goto fail1;
117 
118 			insert_before = item;
119 			break;
120 		}
121 	}
122 
123 	list_add_tail_rcu(&pci->link, insert_before);
124 	return 0;
125 
126 fail0:
127 	edac_printk(KERN_WARNING, EDAC_PCI,
128 		"%s (%s) %s %s already assigned %d\n",
129 		dev_name(rover->dev), edac_dev_name(rover),
130 		rover->mod_name, rover->ctl_name, rover->pci_idx);
131 	return 1;
132 
133 fail1:
134 	edac_printk(KERN_WARNING, EDAC_PCI,
135 		"but in low-level driver: attempt to assign\n"
136 		"\tduplicate pci_idx %d in %s()\n", rover->pci_idx,
137 		__func__);
138 	return 1;
139 }
140 
141 /*
142  * del_edac_pci_from_global_list
143  *
144  *	remove the PCI control struct from the global list
145  */
del_edac_pci_from_global_list(struct edac_pci_ctl_info * pci)146 static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
147 {
148 	list_del_rcu(&pci->link);
149 
150 	/* these are for safe removal of devices from global list while
151 	 * NMI handlers may be traversing list
152 	 */
153 	synchronize_rcu();
154 	INIT_LIST_HEAD(&pci->link);
155 }
156 
157 /*
158  * edac_pci_workq_function()
159  *
160  * 	periodic function that performs the operation
161  *	scheduled by a workq request, for a given PCI control struct
162  */
edac_pci_workq_function(struct work_struct * work_req)163 static void edac_pci_workq_function(struct work_struct *work_req)
164 {
165 	struct delayed_work *d_work = to_delayed_work(work_req);
166 	struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work);
167 	int msec;
168 	unsigned long delay;
169 
170 	edac_dbg(3, "checking\n");
171 
172 	mutex_lock(&edac_pci_ctls_mutex);
173 
174 	if (pci->op_state != OP_RUNNING_POLL) {
175 		mutex_unlock(&edac_pci_ctls_mutex);
176 		return;
177 	}
178 
179 	if (edac_pci_get_check_errors())
180 		pci->edac_check(pci);
181 
182 	/* if we are on a one second period, then use round */
183 	msec = edac_pci_get_poll_msec();
184 	if (msec == 1000)
185 		delay = round_jiffies_relative(msecs_to_jiffies(msec));
186 	else
187 		delay = msecs_to_jiffies(msec);
188 
189 	edac_queue_work(&pci->work, delay);
190 
191 	mutex_unlock(&edac_pci_ctls_mutex);
192 }
193 
edac_pci_alloc_index(void)194 int edac_pci_alloc_index(void)
195 {
196 	return atomic_inc_return(&pci_indexes) - 1;
197 }
198 EXPORT_SYMBOL_GPL(edac_pci_alloc_index);
199 
edac_pci_add_device(struct edac_pci_ctl_info * pci,int edac_idx)200 int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
201 {
202 	edac_dbg(0, "\n");
203 
204 	pci->pci_idx = edac_idx;
205 	pci->start_time = jiffies;
206 
207 	mutex_lock(&edac_pci_ctls_mutex);
208 
209 	if (add_edac_pci_to_global_list(pci))
210 		goto fail0;
211 
212 	if (edac_pci_create_sysfs(pci)) {
213 		edac_pci_printk(pci, KERN_WARNING,
214 				"failed to create sysfs pci\n");
215 		goto fail1;
216 	}
217 
218 	if (pci->edac_check) {
219 		pci->op_state = OP_RUNNING_POLL;
220 
221 		INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
222 		edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec()));
223 
224 	} else {
225 		pci->op_state = OP_RUNNING_INTERRUPT;
226 	}
227 
228 	edac_pci_printk(pci, KERN_INFO,
229 		"Giving out device to module %s controller %s: DEV %s (%s)\n",
230 		pci->mod_name, pci->ctl_name, pci->dev_name,
231 		edac_op_state_to_string(pci->op_state));
232 
233 	mutex_unlock(&edac_pci_ctls_mutex);
234 	return 0;
235 
236 	/* error unwind stack */
237 fail1:
238 	del_edac_pci_from_global_list(pci);
239 fail0:
240 	mutex_unlock(&edac_pci_ctls_mutex);
241 	return 1;
242 }
243 EXPORT_SYMBOL_GPL(edac_pci_add_device);
244 
edac_pci_del_device(struct device * dev)245 struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
246 {
247 	struct edac_pci_ctl_info *pci;
248 
249 	edac_dbg(0, "\n");
250 
251 	mutex_lock(&edac_pci_ctls_mutex);
252 
253 	/* ensure the control struct is on the global list
254 	 * if not, then leave
255 	 */
256 	pci = find_edac_pci_by_dev(dev);
257 	if (pci  == NULL) {
258 		mutex_unlock(&edac_pci_ctls_mutex);
259 		return NULL;
260 	}
261 
262 	pci->op_state = OP_OFFLINE;
263 
264 	del_edac_pci_from_global_list(pci);
265 
266 	mutex_unlock(&edac_pci_ctls_mutex);
267 
268 	if (pci->edac_check)
269 		edac_stop_work(&pci->work);
270 
271 	edac_printk(KERN_INFO, EDAC_PCI,
272 		"Removed device %d for %s %s: DEV %s\n",
273 		pci->pci_idx, pci->mod_name, pci->ctl_name, edac_dev_name(pci));
274 
275 	return pci;
276 }
277 EXPORT_SYMBOL_GPL(edac_pci_del_device);
278 
279 /*
280  * edac_pci_generic_check
281  *
282  *	a Generic parity check API
283  */
edac_pci_generic_check(struct edac_pci_ctl_info * pci)284 static void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
285 {
286 	edac_dbg(4, "\n");
287 	edac_pci_do_parity_check();
288 }
289 
290 /* free running instance index counter */
291 static int edac_pci_idx;
292 #define EDAC_PCI_GENCTL_NAME	"EDAC PCI controller"
293 
294 struct edac_pci_gen_data {
295 	int edac_idx;
296 };
297 
edac_pci_create_generic_ctl(struct device * dev,const char * mod_name)298 struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
299 						const char *mod_name)
300 {
301 	struct edac_pci_ctl_info *pci;
302 	struct edac_pci_gen_data *pdata;
303 
304 	pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME);
305 	if (!pci)
306 		return NULL;
307 
308 	pdata = pci->pvt_info;
309 	pci->dev = dev;
310 	dev_set_drvdata(pci->dev, pci);
311 	pci->dev_name = pci_name(to_pci_dev(dev));
312 
313 	pci->mod_name = mod_name;
314 	pci->ctl_name = EDAC_PCI_GENCTL_NAME;
315 	if (edac_op_state == EDAC_OPSTATE_POLL)
316 		pci->edac_check = edac_pci_generic_check;
317 
318 	pdata->edac_idx = edac_pci_idx++;
319 
320 	if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
321 		edac_dbg(3, "failed edac_pci_add_device()\n");
322 		edac_pci_free_ctl_info(pci);
323 		return NULL;
324 	}
325 
326 	return pci;
327 }
328 EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
329 
edac_pci_release_generic_ctl(struct edac_pci_ctl_info * pci)330 void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
331 {
332 	edac_dbg(0, "pci mod=%s\n", pci->mod_name);
333 
334 	edac_pci_del_device(pci->dev);
335 	edac_pci_free_ctl_info(pci);
336 }
337 EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);
338