xref: /openbmc/linux/drivers/edac/edac_pci_sysfs.c (revision cb4a0bec)
120bcb7a8SDouglas Thompson /*
27c9281d7SDouglas Thompson  * (C) 2005, 2006 Linux Networx (http://lnxi.com)
37c9281d7SDouglas Thompson  * This file may be distributed under the terms of the
47c9281d7SDouglas Thompson  * GNU General Public License.
57c9281d7SDouglas Thompson  *
67c9281d7SDouglas Thompson  * Written Doug Thompson <norsk5@xmission.com>
77c9281d7SDouglas Thompson  *
87c9281d7SDouglas Thompson  */
97c9281d7SDouglas Thompson #include <linux/module.h>
1030e1f7a8SBorislav Petkov #include <linux/edac.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
127c9281d7SDouglas Thompson #include <linux/ctype.h>
137c9281d7SDouglas Thompson 
140b892c71SMauro Carvalho Chehab #include "edac_pci.h"
157c9281d7SDouglas Thompson #include "edac_module.h"
167c9281d7SDouglas Thompson 
1791b99041SDave Jiang #define EDAC_PCI_SYMLINK	"device"
1891b99041SDave Jiang 
19d4c1465bSDoug Thompson /* data variables exported via sysfs */
20d4c1465bSDoug Thompson static int check_pci_errors;		/* default NO check PCI parity */
21d4c1465bSDoug Thompson static int edac_pci_panic_on_pe;	/* default NO panic on PCI Parity */
224de78c68SDave Jiang static int edac_pci_log_pe = 1;		/* log PCI parity errors */
234de78c68SDave Jiang static int edac_pci_log_npe = 1;	/* log PCI non-parity error errors */
24d4c1465bSDoug Thompson static int edac_pci_poll_msec = 1000;	/* one second workq period */
25d4c1465bSDoug Thompson 
267c9281d7SDouglas Thompson static atomic_t pci_parity_count = ATOMIC_INIT(0);
2791b99041SDave Jiang static atomic_t pci_nonparity_count = ATOMIC_INIT(0);
287c9281d7SDouglas Thompson 
2914cc571bSArthur Jones static struct kobject *edac_pci_top_main_kobj;
3091b99041SDave Jiang static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);
317c9281d7SDouglas Thompson 
32d4c1465bSDoug Thompson /* getter functions for the data variables */
edac_pci_get_check_errors(void)334de78c68SDave Jiang int edac_pci_get_check_errors(void)
344de78c68SDave Jiang {
354de78c68SDave Jiang 	return check_pci_errors;
364de78c68SDave Jiang }
374de78c68SDave Jiang 
edac_pci_get_log_pe(void)381a45027dSAdrian Bunk static int edac_pci_get_log_pe(void)
394de78c68SDave Jiang {
404de78c68SDave Jiang 	return edac_pci_log_pe;
414de78c68SDave Jiang }
424de78c68SDave Jiang 
edac_pci_get_log_npe(void)431a45027dSAdrian Bunk static int edac_pci_get_log_npe(void)
444de78c68SDave Jiang {
454de78c68SDave Jiang 	return edac_pci_log_npe;
464de78c68SDave Jiang }
474de78c68SDave Jiang 
edac_pci_get_panic_on_pe(void)481a45027dSAdrian Bunk static int edac_pci_get_panic_on_pe(void)
494de78c68SDave Jiang {
504de78c68SDave Jiang 	return edac_pci_panic_on_pe;
514de78c68SDave Jiang }
524de78c68SDave Jiang 
edac_pci_get_poll_msec(void)534de78c68SDave Jiang int edac_pci_get_poll_msec(void)
544de78c68SDave Jiang {
554de78c68SDave Jiang 	return edac_pci_poll_msec;
564de78c68SDave Jiang }
574de78c68SDave Jiang 
5891b99041SDave Jiang /**************************** EDAC PCI sysfs instance *******************/
instance_pe_count_show(struct edac_pci_ctl_info * pci,char * data)5991b99041SDave Jiang static ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data)
6091b99041SDave Jiang {
6191b99041SDave Jiang 	return sprintf(data, "%u\n", atomic_read(&pci->counters.pe_count));
6291b99041SDave Jiang }
6391b99041SDave Jiang 
instance_npe_count_show(struct edac_pci_ctl_info * pci,char * data)6491b99041SDave Jiang static ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci,
6591b99041SDave Jiang 				char *data)
6691b99041SDave Jiang {
6791b99041SDave Jiang 	return sprintf(data, "%u\n", atomic_read(&pci->counters.npe_count));
6891b99041SDave Jiang }
6991b99041SDave Jiang 
7091b99041SDave Jiang #define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj)
7191b99041SDave Jiang #define to_instance_attr(a) container_of(a, struct instance_attribute, attr)
7291b99041SDave Jiang 
7391b99041SDave Jiang /* DEVICE instance kobject release() function */
edac_pci_instance_release(struct kobject * kobj)7491b99041SDave Jiang static void edac_pci_instance_release(struct kobject *kobj)
7591b99041SDave Jiang {
7691b99041SDave Jiang 	struct edac_pci_ctl_info *pci;
7791b99041SDave Jiang 
78956b9ba1SJoe Perches 	edac_dbg(0, "\n");
7991b99041SDave Jiang 
80d4c1465bSDoug Thompson 	/* Form pointer to containing struct, the pci control struct */
8191b99041SDave Jiang 	pci = to_instance(kobj);
82d4c1465bSDoug Thompson 
83d4c1465bSDoug Thompson 	/* decrement reference count on top main kobj */
8414cc571bSArthur Jones 	kobject_put(edac_pci_top_main_kobj);
85d4c1465bSDoug Thompson 
86d4c1465bSDoug Thompson 	kfree(pci);	/* Free the control struct */
8791b99041SDave Jiang }
8891b99041SDave Jiang 
8991b99041SDave Jiang /* instance specific attribute structure */
9091b99041SDave Jiang struct instance_attribute {
9191b99041SDave Jiang 	struct attribute attr;
9291b99041SDave Jiang 	ssize_t(*show) (struct edac_pci_ctl_info *, char *);
9391b99041SDave Jiang 	ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);
9491b99041SDave Jiang };
9591b99041SDave Jiang 
9691b99041SDave Jiang /* Function to 'show' fields from the edac_pci 'instance' structure */
edac_pci_instance_show(struct kobject * kobj,struct attribute * attr,char * buffer)9791b99041SDave Jiang static ssize_t edac_pci_instance_show(struct kobject *kobj,
98079708b9SDouglas Thompson 				struct attribute *attr, char *buffer)
9991b99041SDave Jiang {
10091b99041SDave Jiang 	struct edac_pci_ctl_info *pci = to_instance(kobj);
10191b99041SDave Jiang 	struct instance_attribute *instance_attr = to_instance_attr(attr);
10291b99041SDave Jiang 
10391b99041SDave Jiang 	if (instance_attr->show)
10491b99041SDave Jiang 		return instance_attr->show(pci, buffer);
10591b99041SDave Jiang 	return -EIO;
10691b99041SDave Jiang }
10791b99041SDave Jiang 
10891b99041SDave Jiang /* Function to 'store' fields into the edac_pci 'instance' structure */
edac_pci_instance_store(struct kobject * kobj,struct attribute * attr,const char * buffer,size_t count)10991b99041SDave Jiang static ssize_t edac_pci_instance_store(struct kobject *kobj,
11091b99041SDave Jiang 				struct attribute *attr,
11191b99041SDave Jiang 				const char *buffer, size_t count)
11291b99041SDave Jiang {
11391b99041SDave Jiang 	struct edac_pci_ctl_info *pci = to_instance(kobj);
11491b99041SDave Jiang 	struct instance_attribute *instance_attr = to_instance_attr(attr);
11591b99041SDave Jiang 
11691b99041SDave Jiang 	if (instance_attr->store)
11791b99041SDave Jiang 		return instance_attr->store(pci, buffer, count);
11891b99041SDave Jiang 	return -EIO;
11991b99041SDave Jiang }
12091b99041SDave Jiang 
121d4c1465bSDoug Thompson /* fs_ops table */
12252cf25d0SEmese Revfy static const struct sysfs_ops pci_instance_ops = {
12391b99041SDave Jiang 	.show = edac_pci_instance_show,
12491b99041SDave Jiang 	.store = edac_pci_instance_store
12591b99041SDave Jiang };
12691b99041SDave Jiang 
12791b99041SDave Jiang #define INSTANCE_ATTR(_name, _mode, _show, _store)	\
12891b99041SDave Jiang static struct instance_attribute attr_instance_##_name = {	\
12991b99041SDave Jiang 	.attr	= {.name = __stringify(_name), .mode = _mode },	\
13091b99041SDave Jiang 	.show	= _show,					\
13191b99041SDave Jiang 	.store	= _store,					\
13291b99041SDave Jiang };
13391b99041SDave Jiang 
13491b99041SDave Jiang INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL);
13591b99041SDave Jiang INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL);
13691b99041SDave Jiang 
13791b99041SDave Jiang /* pci instance attributes */
138625c6b55SGreg Kroah-Hartman static struct attribute *pci_instance_attrs[] = {
13911413893SGreg Kroah-Hartman 	&attr_instance_pe_count.attr,
14011413893SGreg Kroah-Hartman 	&attr_instance_npe_count.attr,
14191b99041SDave Jiang 	NULL
14291b99041SDave Jiang };
143625c6b55SGreg Kroah-Hartman ATTRIBUTE_GROUPS(pci_instance);
14491b99041SDave Jiang 
145d4c1465bSDoug Thompson /* the ktype for a pci instance */
14691b99041SDave Jiang static struct kobj_type ktype_pci_instance = {
14791b99041SDave Jiang 	.release = edac_pci_instance_release,
14891b99041SDave Jiang 	.sysfs_ops = &pci_instance_ops,
149625c6b55SGreg Kroah-Hartman 	.default_groups = pci_instance_groups,
15091b99041SDave Jiang };
15191b99041SDave Jiang 
152d4c1465bSDoug Thompson /*
153d4c1465bSDoug Thompson  * edac_pci_create_instance_kobj
154d4c1465bSDoug Thompson  *
155d4c1465bSDoug Thompson  *	construct one EDAC PCI instance's kobject for use
156d4c1465bSDoug Thompson  */
edac_pci_create_instance_kobj(struct edac_pci_ctl_info * pci,int idx)15791b99041SDave Jiang static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
15891b99041SDave Jiang {
159d4c1465bSDoug Thompson 	struct kobject *main_kobj;
16091b99041SDave Jiang 	int err;
16191b99041SDave Jiang 
162956b9ba1SJoe Perches 	edac_dbg(0, "\n");
163d4c1465bSDoug Thompson 
164d4c1465bSDoug Thompson 	/* First bump the ref count on the top main kobj, which will
165d4c1465bSDoug Thompson 	 * track the number of PCI instances we have, and thus nest
166d4c1465bSDoug Thompson 	 * properly on keeping the module loaded
167d4c1465bSDoug Thompson 	 */
16814cc571bSArthur Jones 	main_kobj = kobject_get(edac_pci_top_main_kobj);
169d4c1465bSDoug Thompson 	if (!main_kobj) {
170d4c1465bSDoug Thompson 		err = -ENODEV;
171d4c1465bSDoug Thompson 		goto error_out;
172d4c1465bSDoug Thompson 	}
173d4c1465bSDoug Thompson 
174d4c1465bSDoug Thompson 	/* And now register this new kobject under the main kobj */
175b2ed215aSGreg Kroah-Hartman 	err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance,
17614cc571bSArthur Jones 				   edac_pci_top_main_kobj, "pci%d", idx);
17791b99041SDave Jiang 	if (err != 0) {
178956b9ba1SJoe Perches 		edac_dbg(2, "failed to register instance pci%d\n", idx);
17914cc571bSArthur Jones 		kobject_put(edac_pci_top_main_kobj);
180d4c1465bSDoug Thompson 		goto error_out;
18191b99041SDave Jiang 	}
18291b99041SDave Jiang 
183b2ed215aSGreg Kroah-Hartman 	kobject_uevent(&pci->kobj, KOBJ_ADD);
184956b9ba1SJoe Perches 	edac_dbg(1, "Register instance 'pci%d' kobject\n", idx);
18591b99041SDave Jiang 
18691b99041SDave Jiang 	return 0;
187d4c1465bSDoug Thompson 
188d4c1465bSDoug Thompson 	/* Error unwind statck */
189d4c1465bSDoug Thompson error_out:
190d4c1465bSDoug Thompson 	return err;
19191b99041SDave Jiang }
19291b99041SDave Jiang 
193d4c1465bSDoug Thompson /*
194d4c1465bSDoug Thompson  * edac_pci_unregister_sysfs_instance_kobj
195d4c1465bSDoug Thompson  *
196d4c1465bSDoug Thompson  *	unregister the kobj for the EDAC PCI instance
197d4c1465bSDoug Thompson  */
edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info * pci)1981a45027dSAdrian Bunk static void edac_pci_unregister_sysfs_instance_kobj(
1991a45027dSAdrian Bunk 			struct edac_pci_ctl_info *pci)
20091b99041SDave Jiang {
201956b9ba1SJoe Perches 	edac_dbg(0, "\n");
202d4c1465bSDoug Thompson 
203d4c1465bSDoug Thompson 	/* Unregister the instance kobject and allow its release
204d4c1465bSDoug Thompson 	 * function release the main reference count and then
205d4c1465bSDoug Thompson 	 * kfree the memory
206d4c1465bSDoug Thompson 	 */
207c10997f6SGreg Kroah-Hartman 	kobject_put(&pci->kobj);
20891b99041SDave Jiang }
20991b99041SDave Jiang 
21091b99041SDave Jiang /***************************** EDAC PCI sysfs root **********************/
21191b99041SDave Jiang #define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj)
21291b99041SDave Jiang #define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr)
2137c9281d7SDouglas Thompson 
214d4c1465bSDoug Thompson /* simple show/store functions for attributes */
edac_pci_int_show(void * ptr,char * buffer)2157c9281d7SDouglas Thompson static ssize_t edac_pci_int_show(void *ptr, char *buffer)
2167c9281d7SDouglas Thompson {
2177c9281d7SDouglas Thompson 	int *value = ptr;
2187c9281d7SDouglas Thompson 	return sprintf(buffer, "%d\n", *value);
2197c9281d7SDouglas Thompson }
2207c9281d7SDouglas Thompson 
edac_pci_int_store(void * ptr,const char * buffer,size_t count)2217c9281d7SDouglas Thompson static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
2227c9281d7SDouglas Thompson {
2237c9281d7SDouglas Thompson 	int *value = ptr;
2247c9281d7SDouglas Thompson 
2257c9281d7SDouglas Thompson 	if (isdigit(*buffer))
2267c9281d7SDouglas Thompson 		*value = simple_strtoul(buffer, NULL, 0);
2277c9281d7SDouglas Thompson 
2287c9281d7SDouglas Thompson 	return count;
2297c9281d7SDouglas Thompson }
2307c9281d7SDouglas Thompson 
2317c9281d7SDouglas Thompson struct edac_pci_dev_attribute {
2327c9281d7SDouglas Thompson 	struct attribute attr;
2337c9281d7SDouglas Thompson 	void *value;
2347c9281d7SDouglas Thompson 	 ssize_t(*show) (void *, char *);
2357c9281d7SDouglas Thompson 	 ssize_t(*store) (void *, const char *, size_t);
2367c9281d7SDouglas Thompson };
2377c9281d7SDouglas Thompson 
2387c9281d7SDouglas Thompson /* Set of show/store abstract level functions for PCI Parity object */
edac_pci_dev_show(struct kobject * kobj,struct attribute * attr,char * buffer)2397c9281d7SDouglas Thompson static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
2407c9281d7SDouglas Thompson 				 char *buffer)
2417c9281d7SDouglas Thompson {
2427c9281d7SDouglas Thompson 	struct edac_pci_dev_attribute *edac_pci_dev;
2437c9281d7SDouglas Thompson 	edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
2447c9281d7SDouglas Thompson 
2457c9281d7SDouglas Thompson 	if (edac_pci_dev->show)
2467c9281d7SDouglas Thompson 		return edac_pci_dev->show(edac_pci_dev->value, buffer);
2477c9281d7SDouglas Thompson 	return -EIO;
2487c9281d7SDouglas Thompson }
2497c9281d7SDouglas Thompson 
edac_pci_dev_store(struct kobject * kobj,struct attribute * attr,const char * buffer,size_t count)2507c9281d7SDouglas Thompson static ssize_t edac_pci_dev_store(struct kobject *kobj,
251079708b9SDouglas Thompson 				struct attribute *attr, const char *buffer,
252079708b9SDouglas Thompson 				size_t count)
2537c9281d7SDouglas Thompson {
2547c9281d7SDouglas Thompson 	struct edac_pci_dev_attribute *edac_pci_dev;
2557c9281d7SDouglas Thompson 	edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
2567c9281d7SDouglas Thompson 
2578024c4c0SDan Carpenter 	if (edac_pci_dev->store)
2587c9281d7SDouglas Thompson 		return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
2597c9281d7SDouglas Thompson 	return -EIO;
2607c9281d7SDouglas Thompson }
2617c9281d7SDouglas Thompson 
26252cf25d0SEmese Revfy static const struct sysfs_ops edac_pci_sysfs_ops = {
2637c9281d7SDouglas Thompson 	.show = edac_pci_dev_show,
2647c9281d7SDouglas Thompson 	.store = edac_pci_dev_store
2657c9281d7SDouglas Thompson };
2667c9281d7SDouglas Thompson 
2677c9281d7SDouglas Thompson #define EDAC_PCI_ATTR(_name,_mode,_show,_store)			\
2687c9281d7SDouglas Thompson static struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
2697c9281d7SDouglas Thompson 	.attr = {.name = __stringify(_name), .mode = _mode },	\
2707c9281d7SDouglas Thompson 	.value  = &_name,					\
2717c9281d7SDouglas Thompson 	.show   = _show,					\
2727c9281d7SDouglas Thompson 	.store  = _store,					\
2737c9281d7SDouglas Thompson };
2747c9281d7SDouglas Thompson 
2757c9281d7SDouglas Thompson #define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store)	\
2767c9281d7SDouglas Thompson static struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
2777c9281d7SDouglas Thompson 	.attr = {.name = __stringify(_name), .mode = _mode },	\
2787c9281d7SDouglas Thompson 	.value  = _data,					\
2797c9281d7SDouglas Thompson 	.show   = _show,					\
2807c9281d7SDouglas Thompson 	.store  = _store,					\
2817c9281d7SDouglas Thompson };
2827c9281d7SDouglas Thompson 
2837c9281d7SDouglas Thompson /* PCI Parity control files */
28491b99041SDave Jiang EDAC_PCI_ATTR(check_pci_errors, S_IRUGO | S_IWUSR, edac_pci_int_show,
28591b99041SDave Jiang 	edac_pci_int_store);
2864de78c68SDave Jiang EDAC_PCI_ATTR(edac_pci_log_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
2877c9281d7SDouglas Thompson 	edac_pci_int_store);
2884de78c68SDave Jiang EDAC_PCI_ATTR(edac_pci_log_npe, S_IRUGO | S_IWUSR, edac_pci_int_show,
2894de78c68SDave Jiang 	edac_pci_int_store);
2904de78c68SDave Jiang EDAC_PCI_ATTR(edac_pci_panic_on_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
2917c9281d7SDouglas Thompson 	edac_pci_int_store);
2927c9281d7SDouglas Thompson EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
29391b99041SDave Jiang EDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL);
2947c9281d7SDouglas Thompson 
2957c9281d7SDouglas Thompson /* Base Attributes of the memory ECC object */
296625c6b55SGreg Kroah-Hartman static struct attribute *edac_pci_attrs[] = {
29711413893SGreg Kroah-Hartman 	&edac_pci_attr_check_pci_errors.attr,
29811413893SGreg Kroah-Hartman 	&edac_pci_attr_edac_pci_log_pe.attr,
29911413893SGreg Kroah-Hartman 	&edac_pci_attr_edac_pci_log_npe.attr,
30011413893SGreg Kroah-Hartman 	&edac_pci_attr_edac_pci_panic_on_pe.attr,
30111413893SGreg Kroah-Hartman 	&edac_pci_attr_pci_parity_count.attr,
30211413893SGreg Kroah-Hartman 	&edac_pci_attr_pci_nonparity_count.attr,
3037c9281d7SDouglas Thompson 	NULL,
3047c9281d7SDouglas Thompson };
305625c6b55SGreg Kroah-Hartman ATTRIBUTE_GROUPS(edac_pci);
3067c9281d7SDouglas Thompson 
307d4c1465bSDoug Thompson /*
308d4c1465bSDoug Thompson  * edac_pci_release_main_kobj
309d4c1465bSDoug Thompson  *
310d4c1465bSDoug Thompson  *	This release function is called when the reference count to the
311d4c1465bSDoug Thompson  *	passed kobj goes to zero.
312d4c1465bSDoug Thompson  *
313d4c1465bSDoug Thompson  *	This kobj is the 'main' kobject that EDAC PCI instances
314d4c1465bSDoug Thompson  *	link to, and thus provide for proper nesting counts
315d4c1465bSDoug Thompson  */
edac_pci_release_main_kobj(struct kobject * kobj)316d4c1465bSDoug Thompson static void edac_pci_release_main_kobj(struct kobject *kobj)
3177c9281d7SDouglas Thompson {
318956b9ba1SJoe Perches 	edac_dbg(0, "here to module_put(THIS_MODULE)\n");
31991b99041SDave Jiang 
32014cc571bSArthur Jones 	kfree(kobj);
32114cc571bSArthur Jones 
322d4c1465bSDoug Thompson 	/* last reference to top EDAC PCI kobject has been removed,
323d4c1465bSDoug Thompson 	 * NOW release our ref count on the core module
324d4c1465bSDoug Thompson 	 */
325d4c1465bSDoug Thompson 	module_put(THIS_MODULE);
3267c9281d7SDouglas Thompson }
3277c9281d7SDouglas Thompson 
328d4c1465bSDoug Thompson /* ktype struct for the EDAC PCI main kobj */
329d4c1465bSDoug Thompson static struct kobj_type ktype_edac_pci_main_kobj = {
330d4c1465bSDoug Thompson 	.release = edac_pci_release_main_kobj,
3317c9281d7SDouglas Thompson 	.sysfs_ops = &edac_pci_sysfs_ops,
332625c6b55SGreg Kroah-Hartman 	.default_groups = edac_pci_groups,
3337c9281d7SDouglas Thompson };
3347c9281d7SDouglas Thompson 
3357c9281d7SDouglas Thompson /**
336d4538000SBorislav Petkov  * edac_pci_main_kobj_setup: Setup the sysfs for EDAC PCI attributes.
3377c9281d7SDouglas Thompson  */
edac_pci_main_kobj_setup(void)3381a45027dSAdrian Bunk static int edac_pci_main_kobj_setup(void)
3397c9281d7SDouglas Thompson {
340*cb4a0becSGreg Kroah-Hartman 	int err = -ENODEV;
341fe5ff8b8SKay Sievers 	struct bus_type *edac_subsys;
342*cb4a0becSGreg Kroah-Hartman 	struct device *dev_root;
3437c9281d7SDouglas Thompson 
344956b9ba1SJoe Perches 	edac_dbg(0, "\n");
3457c9281d7SDouglas Thompson 
346d4c1465bSDoug Thompson 	/* check and count if we have already created the main kobject */
347d4c1465bSDoug Thompson 	if (atomic_inc_return(&edac_pci_sysfs_refcount) != 1)
348d4c1465bSDoug Thompson 		return 0;
349d4c1465bSDoug Thompson 
350d4c1465bSDoug Thompson 	/* First time, so create the main kobject and its
35125985edcSLucas De Marchi 	 * controls and attributes
352d4c1465bSDoug Thompson 	 */
353fe5ff8b8SKay Sievers 	edac_subsys = edac_get_sysfs_subsys();
3547c9281d7SDouglas Thompson 
355d4c1465bSDoug Thompson 	/* Bump the reference count on this module to ensure the
356d4c1465bSDoug Thompson 	 * modules isn't unloaded until we deconstruct the top
357d4c1465bSDoug Thompson 	 * level main kobj for EDAC PCI
358d4c1465bSDoug Thompson 	 */
359d4c1465bSDoug Thompson 	if (!try_module_get(THIS_MODULE)) {
360956b9ba1SJoe Perches 		edac_dbg(1, "try_module_get() failed\n");
361733476cfSBorislav Petkov 		goto decrement_count_fail;
362d4c1465bSDoug Thompson 	}
36391b99041SDave Jiang 
36414cc571bSArthur Jones 	edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
36514cc571bSArthur Jones 	if (!edac_pci_top_main_kobj) {
366956b9ba1SJoe Perches 		edac_dbg(1, "Failed to allocate\n");
36714cc571bSArthur Jones 		err = -ENOMEM;
36814cc571bSArthur Jones 		goto kzalloc_fail;
36914cc571bSArthur Jones 	}
37014cc571bSArthur Jones 
3717c9281d7SDouglas Thompson 	/* Instanstiate the pci object */
372*cb4a0becSGreg Kroah-Hartman 	dev_root = bus_get_dev_root(edac_subsys);
373*cb4a0becSGreg Kroah-Hartman 	if (dev_root) {
37414cc571bSArthur Jones 		err = kobject_init_and_add(edac_pci_top_main_kobj,
37514cc571bSArthur Jones 					   &ktype_edac_pci_main_kobj,
376*cb4a0becSGreg Kroah-Hartman 					   &dev_root->kobj, "pci");
377*cb4a0becSGreg Kroah-Hartman 		put_device(dev_root);
378*cb4a0becSGreg Kroah-Hartman 	}
37991b99041SDave Jiang 	if (err) {
380956b9ba1SJoe Perches 		edac_dbg(1, "Failed to register '.../edac/pci'\n");
381b2ed215aSGreg Kroah-Hartman 		goto kobject_init_and_add_fail;
3827c9281d7SDouglas Thompson 	}
3837c9281d7SDouglas Thompson 
384d4c1465bSDoug Thompson 	/* At this point, to 'release' the top level kobject
385d4c1465bSDoug Thompson 	 * for EDAC PCI, then edac_pci_main_kobj_teardown()
386d4c1465bSDoug Thompson 	 * must be used, for resources to be cleaned up properly
387d4c1465bSDoug Thompson 	 */
38814cc571bSArthur Jones 	kobject_uevent(edac_pci_top_main_kobj, KOBJ_ADD);
389956b9ba1SJoe Perches 	edac_dbg(1, "Registered '.../edac/pci' kobject\n");
39091b99041SDave Jiang 
39191b99041SDave Jiang 	return 0;
392d4c1465bSDoug Thompson 
393d4c1465bSDoug Thompson 	/* Error unwind statck */
394b2ed215aSGreg Kroah-Hartman kobject_init_and_add_fail:
39517ed808aSQiushi Wu 	kobject_put(edac_pci_top_main_kobj);
39614cc571bSArthur Jones 
39714cc571bSArthur Jones kzalloc_fail:
398d4c1465bSDoug Thompson 	module_put(THIS_MODULE);
399d4c1465bSDoug Thompson 
400d4c1465bSDoug Thompson decrement_count_fail:
401d4c1465bSDoug Thompson 	/* if are on this error exit, nothing to tear down */
402d4c1465bSDoug Thompson 	atomic_dec(&edac_pci_sysfs_refcount);
403d4c1465bSDoug Thompson 
404d4c1465bSDoug Thompson 	return err;
40591b99041SDave Jiang }
40691b99041SDave Jiang 
4077c9281d7SDouglas Thompson /*
408d4c1465bSDoug Thompson  * edac_pci_main_kobj_teardown()
4097c9281d7SDouglas Thompson  *
410d4c1465bSDoug Thompson  *	if no longer linked (needed) remove the top level EDAC PCI
411d4c1465bSDoug Thompson  *	kobject with its controls and attributes
4127c9281d7SDouglas Thompson  */
edac_pci_main_kobj_teardown(void)413d4c1465bSDoug Thompson static void edac_pci_main_kobj_teardown(void)
4147c9281d7SDouglas Thompson {
415956b9ba1SJoe Perches 	edac_dbg(0, "\n");
416d4c1465bSDoug Thompson 
417d4c1465bSDoug Thompson 	/* Decrement the count and only if no more controller instances
418d4c1465bSDoug Thompson 	 * are connected perform the unregisteration of the top level
419d4c1465bSDoug Thompson 	 * main kobj
420d4c1465bSDoug Thompson 	 */
421d4c1465bSDoug Thompson 	if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
422956b9ba1SJoe Perches 		edac_dbg(0, "called kobject_put on main kobj\n");
42314cc571bSArthur Jones 		kobject_put(edac_pci_top_main_kobj);
4247c9281d7SDouglas Thompson 	}
4251c069100SLans Zhang }
4267c9281d7SDouglas Thompson 
edac_pci_create_sysfs(struct edac_pci_ctl_info * pci)42791b99041SDave Jiang int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
42891b99041SDave Jiang {
42991b99041SDave Jiang 	int err;
43091b99041SDave Jiang 	struct kobject *edac_kobj = &pci->kobj;
4317c9281d7SDouglas Thompson 
432956b9ba1SJoe Perches 	edac_dbg(0, "idx=%d\n", pci->pci_idx);
43391b99041SDave Jiang 
434d4c1465bSDoug Thompson 	/* create the top main EDAC PCI kobject, IF needed */
435d4c1465bSDoug Thompson 	err = edac_pci_main_kobj_setup();
436d4c1465bSDoug Thompson 	if (err)
437d4c1465bSDoug Thompson 		return err;
438d4c1465bSDoug Thompson 
439d4c1465bSDoug Thompson 	/* Create this instance's kobject under the MAIN kobject */
440d4c1465bSDoug Thompson 	err = edac_pci_create_instance_kobj(pci, pci->pci_idx);
441d4c1465bSDoug Thompson 	if (err)
442d4c1465bSDoug Thompson 		goto unregister_cleanup;
443d4c1465bSDoug Thompson 
444079708b9SDouglas Thompson 	err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
44591b99041SDave Jiang 	if (err) {
446956b9ba1SJoe Perches 		edac_dbg(0, "sysfs_create_link() returned err= %d\n", err);
447d4c1465bSDoug Thompson 		goto symlink_fail;
44891b99041SDave Jiang 	}
44991b99041SDave Jiang 
45091b99041SDave Jiang 	return 0;
451d4c1465bSDoug Thompson 
452d4c1465bSDoug Thompson 	/* Error unwind stack */
453d4c1465bSDoug Thompson symlink_fail:
454d4c1465bSDoug Thompson 	edac_pci_unregister_sysfs_instance_kobj(pci);
455d4c1465bSDoug Thompson 
456d4c1465bSDoug Thompson unregister_cleanup:
457d4c1465bSDoug Thompson 	edac_pci_main_kobj_teardown();
458d4c1465bSDoug Thompson 
459d4c1465bSDoug Thompson 	return err;
46091b99041SDave Jiang }
46191b99041SDave Jiang 
edac_pci_remove_sysfs(struct edac_pci_ctl_info * pci)46291b99041SDave Jiang void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
46391b99041SDave Jiang {
464956b9ba1SJoe Perches 	edac_dbg(0, "index=%d\n", pci->pci_idx);
46591b99041SDave Jiang 
466d4c1465bSDoug Thompson 	/* Remove the symlink */
46791b99041SDave Jiang 	sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
46891b99041SDave Jiang 
469d4c1465bSDoug Thompson 	/* remove this PCI instance's sysfs entries */
470d4c1465bSDoug Thompson 	edac_pci_unregister_sysfs_instance_kobj(pci);
471d4c1465bSDoug Thompson 
472d4c1465bSDoug Thompson 	/* Call the main unregister function, which will determine
473d4c1465bSDoug Thompson 	 * if this 'pci' is the last instance.
474d4c1465bSDoug Thompson 	 * If it is, the main kobject will be unregistered as a result
475d4c1465bSDoug Thompson 	 */
476956b9ba1SJoe Perches 	edac_dbg(0, "calling edac_pci_main_kobj_teardown()\n");
477d4c1465bSDoug Thompson 	edac_pci_main_kobj_teardown();
47891b99041SDave Jiang }
47991b99041SDave Jiang 
48091b99041SDave Jiang /************************ PCI error handling *************************/
get_pci_parity_status(struct pci_dev * dev,int secondary)4817c9281d7SDouglas Thompson static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
4827c9281d7SDouglas Thompson {
4837c9281d7SDouglas Thompson 	int where;
4847c9281d7SDouglas Thompson 	u16 status;
4857c9281d7SDouglas Thompson 
4867c9281d7SDouglas Thompson 	where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
4877c9281d7SDouglas Thompson 	pci_read_config_word(dev, where, &status);
4887c9281d7SDouglas Thompson 
4897c9281d7SDouglas Thompson 	/* If we get back 0xFFFF then we must suspect that the card has been
4907c9281d7SDouglas Thompson 	 * pulled but the Linux PCI layer has not yet finished cleaning up.
4917c9281d7SDouglas Thompson 	 * We don't want to report on such devices
4927c9281d7SDouglas Thompson 	 */
4937c9281d7SDouglas Thompson 
4947c9281d7SDouglas Thompson 	if (status == 0xFFFF) {
4957c9281d7SDouglas Thompson 		u32 sanity;
4967c9281d7SDouglas Thompson 
4977c9281d7SDouglas Thompson 		pci_read_config_dword(dev, 0, &sanity);
4987c9281d7SDouglas Thompson 
4997c9281d7SDouglas Thompson 		if (sanity == 0xFFFFFFFF)
5007c9281d7SDouglas Thompson 			return 0;
5017c9281d7SDouglas Thompson 	}
5027c9281d7SDouglas Thompson 
5037c9281d7SDouglas Thompson 	status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
5047c9281d7SDouglas Thompson 		PCI_STATUS_PARITY;
5057c9281d7SDouglas Thompson 
5067c9281d7SDouglas Thompson 	if (status)
5077c9281d7SDouglas Thompson 		/* reset only the bits we are interested in */
5087c9281d7SDouglas Thompson 		pci_write_config_word(dev, where, status);
5097c9281d7SDouglas Thompson 
5107c9281d7SDouglas Thompson 	return status;
5117c9281d7SDouglas Thompson }
5127c9281d7SDouglas Thompson 
5137c9281d7SDouglas Thompson 
5147c9281d7SDouglas Thompson /* Clear any PCI parity errors logged by this device. */
edac_pci_dev_parity_clear(struct pci_dev * dev)5157c9281d7SDouglas Thompson static void edac_pci_dev_parity_clear(struct pci_dev *dev)
5167c9281d7SDouglas Thompson {
5177c9281d7SDouglas Thompson 	u8 header_type;
5187c9281d7SDouglas Thompson 
5197c9281d7SDouglas Thompson 	get_pci_parity_status(dev, 0);
5207c9281d7SDouglas Thompson 
5217c9281d7SDouglas Thompson 	/* read the device TYPE, looking for bridges */
5227c9281d7SDouglas Thompson 	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
5237c9281d7SDouglas Thompson 
5247c9281d7SDouglas Thompson 	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
5257c9281d7SDouglas Thompson 		get_pci_parity_status(dev, 1);
5267c9281d7SDouglas Thompson }
5277c9281d7SDouglas Thompson 
5287c9281d7SDouglas Thompson /*
5297c9281d7SDouglas Thompson  *  PCI Parity polling
5307c9281d7SDouglas Thompson  *
53125985edcSLucas De Marchi  *	Function to retrieve the current parity status
532d4c1465bSDoug Thompson  *	and decode it
533d4c1465bSDoug Thompson  *
5347c9281d7SDouglas Thompson  */
edac_pci_dev_parity_test(struct pci_dev * dev)5357c9281d7SDouglas Thompson static void edac_pci_dev_parity_test(struct pci_dev *dev)
5367c9281d7SDouglas Thompson {
537d4c1465bSDoug Thompson 	unsigned long flags;
5387c9281d7SDouglas Thompson 	u16 status;
5397c9281d7SDouglas Thompson 	u8 header_type;
5407c9281d7SDouglas Thompson 
541d4c1465bSDoug Thompson 	/* stop any interrupts until we can acquire the status */
542d4c1465bSDoug Thompson 	local_irq_save(flags);
543d4c1465bSDoug Thompson 
544d4c1465bSDoug Thompson 	/* read the STATUS register on this device */
5457c9281d7SDouglas Thompson 	status = get_pci_parity_status(dev, 0);
5467c9281d7SDouglas Thompson 
547d4c1465bSDoug Thompson 	/* read the device TYPE, looking for bridges */
548d4c1465bSDoug Thompson 	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
549d4c1465bSDoug Thompson 
550d4c1465bSDoug Thompson 	local_irq_restore(flags);
551d4c1465bSDoug Thompson 
552956b9ba1SJoe Perches 	edac_dbg(4, "PCI STATUS= 0x%04x %s\n", status, dev_name(&dev->dev));
5537c9281d7SDouglas Thompson 
5546b09ff9dSBryan Boatright 	/* check the status reg for errors on boards NOT marked as broken
5556b09ff9dSBryan Boatright 	 * if broken, we cannot trust any of the status bits
5566b09ff9dSBryan Boatright 	 */
5576b09ff9dSBryan Boatright 	if (status && !dev->broken_parity_status) {
55891b99041SDave Jiang 		if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
5597c9281d7SDouglas Thompson 			edac_printk(KERN_CRIT, EDAC_PCI,
5607c9281d7SDouglas Thompson 				"Signaled System Error on %s\n",
5617c9281d7SDouglas Thompson 				pci_name(dev));
56291b99041SDave Jiang 			atomic_inc(&pci_nonparity_count);
56391b99041SDave Jiang 		}
5647c9281d7SDouglas Thompson 
5657c9281d7SDouglas Thompson 		if (status & (PCI_STATUS_PARITY)) {
5667c9281d7SDouglas Thompson 			edac_printk(KERN_CRIT, EDAC_PCI,
5677c9281d7SDouglas Thompson 				"Master Data Parity Error on %s\n",
5687c9281d7SDouglas Thompson 				pci_name(dev));
5697c9281d7SDouglas Thompson 
5707c9281d7SDouglas Thompson 			atomic_inc(&pci_parity_count);
5717c9281d7SDouglas Thompson 		}
5727c9281d7SDouglas Thompson 
5737c9281d7SDouglas Thompson 		if (status & (PCI_STATUS_DETECTED_PARITY)) {
5747c9281d7SDouglas Thompson 			edac_printk(KERN_CRIT, EDAC_PCI,
5757c9281d7SDouglas Thompson 				"Detected Parity Error on %s\n",
5767c9281d7SDouglas Thompson 				pci_name(dev));
5777c9281d7SDouglas Thompson 
5787c9281d7SDouglas Thompson 			atomic_inc(&pci_parity_count);
5797c9281d7SDouglas Thompson 		}
5807c9281d7SDouglas Thompson 	}
5817c9281d7SDouglas Thompson 
5827c9281d7SDouglas Thompson 
583956b9ba1SJoe Perches 	edac_dbg(4, "PCI HEADER TYPE= 0x%02x %s\n",
584956b9ba1SJoe Perches 		 header_type, dev_name(&dev->dev));
5857c9281d7SDouglas Thompson 
5867c9281d7SDouglas Thompson 	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
5877c9281d7SDouglas Thompson 		/* On bridges, need to examine secondary status register  */
5887c9281d7SDouglas Thompson 		status = get_pci_parity_status(dev, 1);
5897c9281d7SDouglas Thompson 
590956b9ba1SJoe Perches 		edac_dbg(4, "PCI SEC_STATUS= 0x%04x %s\n",
591956b9ba1SJoe Perches 			 status, dev_name(&dev->dev));
5927c9281d7SDouglas Thompson 
5936b09ff9dSBryan Boatright 		/* check the secondary status reg for errors,
5946b09ff9dSBryan Boatright 		 * on NOT broken boards
5956b09ff9dSBryan Boatright 		 */
5966b09ff9dSBryan Boatright 		if (status && !dev->broken_parity_status) {
59791b99041SDave Jiang 			if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
5987c9281d7SDouglas Thompson 				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
5997c9281d7SDouglas Thompson 					"Signaled System Error on %s\n",
6007c9281d7SDouglas Thompson 					pci_name(dev));
60191b99041SDave Jiang 				atomic_inc(&pci_nonparity_count);
60291b99041SDave Jiang 			}
6037c9281d7SDouglas Thompson 
6047c9281d7SDouglas Thompson 			if (status & (PCI_STATUS_PARITY)) {
6057c9281d7SDouglas Thompson 				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
6067c9281d7SDouglas Thompson 					"Master Data Parity Error on "
6077c9281d7SDouglas Thompson 					"%s\n", pci_name(dev));
6087c9281d7SDouglas Thompson 
6097c9281d7SDouglas Thompson 				atomic_inc(&pci_parity_count);
6107c9281d7SDouglas Thompson 			}
6117c9281d7SDouglas Thompson 
6127c9281d7SDouglas Thompson 			if (status & (PCI_STATUS_DETECTED_PARITY)) {
6137c9281d7SDouglas Thompson 				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
6147c9281d7SDouglas Thompson 					"Detected Parity Error on %s\n",
6157c9281d7SDouglas Thompson 					pci_name(dev));
6167c9281d7SDouglas Thompson 
6177c9281d7SDouglas Thompson 				atomic_inc(&pci_parity_count);
6187c9281d7SDouglas Thompson 			}
6197c9281d7SDouglas Thompson 		}
6207c9281d7SDouglas Thompson 	}
6217c9281d7SDouglas Thompson }
6227c9281d7SDouglas Thompson 
623d4c1465bSDoug Thompson /* reduce some complexity in definition of the iterator */
624d4c1465bSDoug Thompson typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
625d4c1465bSDoug Thompson 
6267c9281d7SDouglas Thompson /*
6277c9281d7SDouglas Thompson  * pci_dev parity list iterator
6283bfe5aaeSWei Yongjun  *
6293bfe5aaeSWei Yongjun  *	Scan the PCI device list looking for SERRORs, Master Parity ERRORS or
6303bfe5aaeSWei Yongjun  *	Parity ERRORs on primary or secondary devices.
6317c9281d7SDouglas Thompson  */
edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)6327c9281d7SDouglas Thompson static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
6337c9281d7SDouglas Thompson {
6347c9281d7SDouglas Thompson 	struct pci_dev *dev = NULL;
6357c9281d7SDouglas Thompson 
6363bfe5aaeSWei Yongjun 	for_each_pci_dev(dev)
6377c9281d7SDouglas Thompson 		fn(dev);
6387c9281d7SDouglas Thompson }
6397c9281d7SDouglas Thompson 
6407c9281d7SDouglas Thompson /*
6417c9281d7SDouglas Thompson  * edac_pci_do_parity_check
6427c9281d7SDouglas Thompson  *
6437c9281d7SDouglas Thompson  *	performs the actual PCI parity check operation
6447c9281d7SDouglas Thompson  */
edac_pci_do_parity_check(void)6457c9281d7SDouglas Thompson void edac_pci_do_parity_check(void)
6467c9281d7SDouglas Thompson {
6477c9281d7SDouglas Thompson 	int before_count;
6487c9281d7SDouglas Thompson 
649956b9ba1SJoe Perches 	edac_dbg(3, "\n");
6507c9281d7SDouglas Thompson 
651d4c1465bSDoug Thompson 	/* if policy has PCI check off, leave now */
65291b99041SDave Jiang 	if (!check_pci_errors)
6537c9281d7SDouglas Thompson 		return;
6547c9281d7SDouglas Thompson 
6557c9281d7SDouglas Thompson 	before_count = atomic_read(&pci_parity_count);
6567c9281d7SDouglas Thompson 
6577c9281d7SDouglas Thompson 	/* scan all PCI devices looking for a Parity Error on devices and
658d4c1465bSDoug Thompson 	 * bridges.
659d4c1465bSDoug Thompson 	 * The iterator calls pci_get_device() which might sleep, thus
660d4c1465bSDoug Thompson 	 * we cannot disable interrupts in this scan.
6617c9281d7SDouglas Thompson 	 */
6627c9281d7SDouglas Thompson 	edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
6637c9281d7SDouglas Thompson 
6647c9281d7SDouglas Thompson 	/* Only if operator has selected panic on PCI Error */
6654de78c68SDave Jiang 	if (edac_pci_get_panic_on_pe()) {
6667c9281d7SDouglas Thompson 		/* If the count is different 'after' from 'before' */
6677c9281d7SDouglas Thompson 		if (before_count != atomic_read(&pci_parity_count))
6687c9281d7SDouglas Thompson 			panic("EDAC: PCI Parity Error");
6697c9281d7SDouglas Thompson 	}
6707c9281d7SDouglas Thompson }
6717c9281d7SDouglas Thompson 
672d4c1465bSDoug Thompson /*
673d4c1465bSDoug Thompson  * edac_pci_clear_parity_errors
674d4c1465bSDoug Thompson  *
675d4c1465bSDoug Thompson  *	function to perform an iteration over the PCI devices
676d4c1465bSDoug Thompson  *	and clearn their current status
677d4c1465bSDoug Thompson  */
edac_pci_clear_parity_errors(void)6787c9281d7SDouglas Thompson void edac_pci_clear_parity_errors(void)
6797c9281d7SDouglas Thompson {
6807c9281d7SDouglas Thompson 	/* Clear any PCI bus parity errors that devices initially have logged
6817c9281d7SDouglas Thompson 	 * in their registers.
6827c9281d7SDouglas Thompson 	 */
6837c9281d7SDouglas Thompson 	edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
6847c9281d7SDouglas Thompson }
685d4c1465bSDoug Thompson 
686d4c1465bSDoug Thompson /*
687d4c1465bSDoug Thompson  * edac_pci_handle_pe
688d4c1465bSDoug Thompson  *
689d4c1465bSDoug Thompson  *	Called to handle a PARITY ERROR event
690d4c1465bSDoug Thompson  */
edac_pci_handle_pe(struct edac_pci_ctl_info * pci,const char * msg)69191b99041SDave Jiang void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg)
69291b99041SDave Jiang {
6937c9281d7SDouglas Thompson 
69491b99041SDave Jiang 	/* global PE counter incremented by edac_pci_do_parity_check() */
69591b99041SDave Jiang 	atomic_inc(&pci->counters.pe_count);
69691b99041SDave Jiang 
6974de78c68SDave Jiang 	if (edac_pci_get_log_pe())
69891b99041SDave Jiang 		edac_pci_printk(pci, KERN_WARNING,
69991b99041SDave Jiang 				"Parity Error ctl: %s %d: %s\n",
70091b99041SDave Jiang 				pci->ctl_name, pci->pci_idx, msg);
70191b99041SDave Jiang 
70291b99041SDave Jiang 	/*
70391b99041SDave Jiang 	 * poke all PCI devices and see which one is the troublemaker
70491b99041SDave Jiang 	 * panic() is called if set
70591b99041SDave Jiang 	 */
70691b99041SDave Jiang 	edac_pci_do_parity_check();
70791b99041SDave Jiang }
70891b99041SDave Jiang EXPORT_SYMBOL_GPL(edac_pci_handle_pe);
70991b99041SDave Jiang 
710d4c1465bSDoug Thompson 
711d4c1465bSDoug Thompson /*
712d4c1465bSDoug Thompson  * edac_pci_handle_npe
713d4c1465bSDoug Thompson  *
714d4c1465bSDoug Thompson  *	Called to handle a NON-PARITY ERROR event
715d4c1465bSDoug Thompson  */
edac_pci_handle_npe(struct edac_pci_ctl_info * pci,const char * msg)71691b99041SDave Jiang void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg)
71791b99041SDave Jiang {
71891b99041SDave Jiang 
71991b99041SDave Jiang 	/* global NPE counter incremented by edac_pci_do_parity_check() */
72091b99041SDave Jiang 	atomic_inc(&pci->counters.npe_count);
72191b99041SDave Jiang 
7224de78c68SDave Jiang 	if (edac_pci_get_log_npe())
72391b99041SDave Jiang 		edac_pci_printk(pci, KERN_WARNING,
72491b99041SDave Jiang 				"Non-Parity Error ctl: %s %d: %s\n",
72591b99041SDave Jiang 				pci->ctl_name, pci->pci_idx, msg);
72691b99041SDave Jiang 
72791b99041SDave Jiang 	/*
72891b99041SDave Jiang 	 * poke all PCI devices and see which one is the troublemaker
72991b99041SDave Jiang 	 * panic() is called if set
73091b99041SDave Jiang 	 */
73191b99041SDave Jiang 	edac_pci_do_parity_check();
73291b99041SDave Jiang }
73391b99041SDave Jiang EXPORT_SYMBOL_GPL(edac_pci_handle_npe);
7347c9281d7SDouglas Thompson 
7357c9281d7SDouglas Thompson /*
7367c9281d7SDouglas Thompson  * Define the PCI parameter to the module
7377c9281d7SDouglas Thompson  */
73891b99041SDave Jiang module_param(check_pci_errors, int, 0644);
7394de78c68SDave Jiang MODULE_PARM_DESC(check_pci_errors,
7404de78c68SDave Jiang 		 "Check for PCI bus parity errors: 0=off 1=on");
7414de78c68SDave Jiang module_param(edac_pci_panic_on_pe, int, 0644);
7424de78c68SDave Jiang MODULE_PARM_DESC(edac_pci_panic_on_pe,
7434de78c68SDave Jiang 		 "Panic on PCI Bus Parity error: 0=off 1=on");
744