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