18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * (C) 2005, 2006 Linux Networx (http://lnxi.com)
38c2ecf20Sopenharmony_ci * This file may be distributed under the terms of the
48c2ecf20Sopenharmony_ci * GNU General Public License.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Written Doug Thompson <norsk5@xmission.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/edac.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/ctype.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "edac_pci.h"
158c2ecf20Sopenharmony_ci#include "edac_module.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define EDAC_PCI_SYMLINK	"device"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* data variables exported via sysfs */
208c2ecf20Sopenharmony_cistatic int check_pci_errors;		/* default NO check PCI parity */
218c2ecf20Sopenharmony_cistatic int edac_pci_panic_on_pe;	/* default NO panic on PCI Parity */
228c2ecf20Sopenharmony_cistatic int edac_pci_log_pe = 1;		/* log PCI parity errors */
238c2ecf20Sopenharmony_cistatic int edac_pci_log_npe = 1;	/* log PCI non-parity error errors */
248c2ecf20Sopenharmony_cistatic int edac_pci_poll_msec = 1000;	/* one second workq period */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic atomic_t pci_parity_count = ATOMIC_INIT(0);
278c2ecf20Sopenharmony_cistatic atomic_t pci_nonparity_count = ATOMIC_INIT(0);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic struct kobject *edac_pci_top_main_kobj;
308c2ecf20Sopenharmony_cistatic atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/* getter functions for the data variables */
338c2ecf20Sopenharmony_ciint edac_pci_get_check_errors(void)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	return check_pci_errors;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic int edac_pci_get_log_pe(void)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	return edac_pci_log_pe;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic int edac_pci_get_log_npe(void)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	return edac_pci_log_npe;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int edac_pci_get_panic_on_pe(void)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	return edac_pci_panic_on_pe;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ciint edac_pci_get_poll_msec(void)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	return edac_pci_poll_msec;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/**************************** EDAC PCI sysfs instance *******************/
598c2ecf20Sopenharmony_cistatic ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	return sprintf(data, "%u\n", atomic_read(&pci->counters.pe_count));
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci,
658c2ecf20Sopenharmony_ci				char *data)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	return sprintf(data, "%u\n", atomic_read(&pci->counters.npe_count));
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj)
718c2ecf20Sopenharmony_ci#define to_instance_attr(a) container_of(a, struct instance_attribute, attr)
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/* DEVICE instance kobject release() function */
748c2ecf20Sopenharmony_cistatic void edac_pci_instance_release(struct kobject *kobj)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct edac_pci_ctl_info *pci;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	edac_dbg(0, "\n");
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* Form pointer to containing struct, the pci control struct */
818c2ecf20Sopenharmony_ci	pci = to_instance(kobj);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* decrement reference count on top main kobj */
848c2ecf20Sopenharmony_ci	kobject_put(edac_pci_top_main_kobj);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	kfree(pci);	/* Free the control struct */
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/* instance specific attribute structure */
908c2ecf20Sopenharmony_cistruct instance_attribute {
918c2ecf20Sopenharmony_ci	struct attribute attr;
928c2ecf20Sopenharmony_ci	ssize_t(*show) (struct edac_pci_ctl_info *, char *);
938c2ecf20Sopenharmony_ci	ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* Function to 'show' fields from the edac_pci 'instance' structure */
978c2ecf20Sopenharmony_cistatic ssize_t edac_pci_instance_show(struct kobject *kobj,
988c2ecf20Sopenharmony_ci				struct attribute *attr, char *buffer)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct edac_pci_ctl_info *pci = to_instance(kobj);
1018c2ecf20Sopenharmony_ci	struct instance_attribute *instance_attr = to_instance_attr(attr);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (instance_attr->show)
1048c2ecf20Sopenharmony_ci		return instance_attr->show(pci, buffer);
1058c2ecf20Sopenharmony_ci	return -EIO;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/* Function to 'store' fields into the edac_pci 'instance' structure */
1098c2ecf20Sopenharmony_cistatic ssize_t edac_pci_instance_store(struct kobject *kobj,
1108c2ecf20Sopenharmony_ci				struct attribute *attr,
1118c2ecf20Sopenharmony_ci				const char *buffer, size_t count)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct edac_pci_ctl_info *pci = to_instance(kobj);
1148c2ecf20Sopenharmony_ci	struct instance_attribute *instance_attr = to_instance_attr(attr);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (instance_attr->store)
1178c2ecf20Sopenharmony_ci		return instance_attr->store(pci, buffer, count);
1188c2ecf20Sopenharmony_ci	return -EIO;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/* fs_ops table */
1228c2ecf20Sopenharmony_cistatic const struct sysfs_ops pci_instance_ops = {
1238c2ecf20Sopenharmony_ci	.show = edac_pci_instance_show,
1248c2ecf20Sopenharmony_ci	.store = edac_pci_instance_store
1258c2ecf20Sopenharmony_ci};
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define INSTANCE_ATTR(_name, _mode, _show, _store)	\
1288c2ecf20Sopenharmony_cistatic struct instance_attribute attr_instance_##_name = {	\
1298c2ecf20Sopenharmony_ci	.attr	= {.name = __stringify(_name), .mode = _mode },	\
1308c2ecf20Sopenharmony_ci	.show	= _show,					\
1318c2ecf20Sopenharmony_ci	.store	= _store,					\
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ciINSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL);
1358c2ecf20Sopenharmony_ciINSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* pci instance attributes */
1388c2ecf20Sopenharmony_cistatic struct instance_attribute *pci_instance_attr[] = {
1398c2ecf20Sopenharmony_ci	&attr_instance_pe_count,
1408c2ecf20Sopenharmony_ci	&attr_instance_npe_count,
1418c2ecf20Sopenharmony_ci	NULL
1428c2ecf20Sopenharmony_ci};
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/* the ktype for a pci instance */
1458c2ecf20Sopenharmony_cistatic struct kobj_type ktype_pci_instance = {
1468c2ecf20Sopenharmony_ci	.release = edac_pci_instance_release,
1478c2ecf20Sopenharmony_ci	.sysfs_ops = &pci_instance_ops,
1488c2ecf20Sopenharmony_ci	.default_attrs = (struct attribute **)pci_instance_attr,
1498c2ecf20Sopenharmony_ci};
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/*
1528c2ecf20Sopenharmony_ci * edac_pci_create_instance_kobj
1538c2ecf20Sopenharmony_ci *
1548c2ecf20Sopenharmony_ci *	construct one EDAC PCI instance's kobject for use
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_cistatic int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct kobject *main_kobj;
1598c2ecf20Sopenharmony_ci	int err;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	edac_dbg(0, "\n");
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* First bump the ref count on the top main kobj, which will
1648c2ecf20Sopenharmony_ci	 * track the number of PCI instances we have, and thus nest
1658c2ecf20Sopenharmony_ci	 * properly on keeping the module loaded
1668c2ecf20Sopenharmony_ci	 */
1678c2ecf20Sopenharmony_ci	main_kobj = kobject_get(edac_pci_top_main_kobj);
1688c2ecf20Sopenharmony_ci	if (!main_kobj) {
1698c2ecf20Sopenharmony_ci		err = -ENODEV;
1708c2ecf20Sopenharmony_ci		goto error_out;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* And now register this new kobject under the main kobj */
1748c2ecf20Sopenharmony_ci	err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance,
1758c2ecf20Sopenharmony_ci				   edac_pci_top_main_kobj, "pci%d", idx);
1768c2ecf20Sopenharmony_ci	if (err != 0) {
1778c2ecf20Sopenharmony_ci		edac_dbg(2, "failed to register instance pci%d\n", idx);
1788c2ecf20Sopenharmony_ci		kobject_put(edac_pci_top_main_kobj);
1798c2ecf20Sopenharmony_ci		goto error_out;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	kobject_uevent(&pci->kobj, KOBJ_ADD);
1838c2ecf20Sopenharmony_ci	edac_dbg(1, "Register instance 'pci%d' kobject\n", idx);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return 0;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* Error unwind statck */
1888c2ecf20Sopenharmony_cierror_out:
1898c2ecf20Sopenharmony_ci	return err;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/*
1938c2ecf20Sopenharmony_ci * edac_pci_unregister_sysfs_instance_kobj
1948c2ecf20Sopenharmony_ci *
1958c2ecf20Sopenharmony_ci *	unregister the kobj for the EDAC PCI instance
1968c2ecf20Sopenharmony_ci */
1978c2ecf20Sopenharmony_cistatic void edac_pci_unregister_sysfs_instance_kobj(
1988c2ecf20Sopenharmony_ci			struct edac_pci_ctl_info *pci)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	edac_dbg(0, "\n");
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/* Unregister the instance kobject and allow its release
2038c2ecf20Sopenharmony_ci	 * function release the main reference count and then
2048c2ecf20Sopenharmony_ci	 * kfree the memory
2058c2ecf20Sopenharmony_ci	 */
2068c2ecf20Sopenharmony_ci	kobject_put(&pci->kobj);
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/***************************** EDAC PCI sysfs root **********************/
2108c2ecf20Sopenharmony_ci#define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj)
2118c2ecf20Sopenharmony_ci#define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr)
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/* simple show/store functions for attributes */
2148c2ecf20Sopenharmony_cistatic ssize_t edac_pci_int_show(void *ptr, char *buffer)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	int *value = ptr;
2178c2ecf20Sopenharmony_ci	return sprintf(buffer, "%d\n", *value);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	int *value = ptr;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (isdigit(*buffer))
2258c2ecf20Sopenharmony_ci		*value = simple_strtoul(buffer, NULL, 0);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return count;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistruct edac_pci_dev_attribute {
2318c2ecf20Sopenharmony_ci	struct attribute attr;
2328c2ecf20Sopenharmony_ci	void *value;
2338c2ecf20Sopenharmony_ci	 ssize_t(*show) (void *, char *);
2348c2ecf20Sopenharmony_ci	 ssize_t(*store) (void *, const char *, size_t);
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/* Set of show/store abstract level functions for PCI Parity object */
2388c2ecf20Sopenharmony_cistatic ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
2398c2ecf20Sopenharmony_ci				 char *buffer)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct edac_pci_dev_attribute *edac_pci_dev;
2428c2ecf20Sopenharmony_ci	edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (edac_pci_dev->show)
2458c2ecf20Sopenharmony_ci		return edac_pci_dev->show(edac_pci_dev->value, buffer);
2468c2ecf20Sopenharmony_ci	return -EIO;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic ssize_t edac_pci_dev_store(struct kobject *kobj,
2508c2ecf20Sopenharmony_ci				struct attribute *attr, const char *buffer,
2518c2ecf20Sopenharmony_ci				size_t count)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct edac_pci_dev_attribute *edac_pci_dev;
2548c2ecf20Sopenharmony_ci	edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (edac_pci_dev->store)
2578c2ecf20Sopenharmony_ci		return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
2588c2ecf20Sopenharmony_ci	return -EIO;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic const struct sysfs_ops edac_pci_sysfs_ops = {
2628c2ecf20Sopenharmony_ci	.show = edac_pci_dev_show,
2638c2ecf20Sopenharmony_ci	.store = edac_pci_dev_store
2648c2ecf20Sopenharmony_ci};
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci#define EDAC_PCI_ATTR(_name,_mode,_show,_store)			\
2678c2ecf20Sopenharmony_cistatic struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
2688c2ecf20Sopenharmony_ci	.attr = {.name = __stringify(_name), .mode = _mode },	\
2698c2ecf20Sopenharmony_ci	.value  = &_name,					\
2708c2ecf20Sopenharmony_ci	.show   = _show,					\
2718c2ecf20Sopenharmony_ci	.store  = _store,					\
2728c2ecf20Sopenharmony_ci};
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store)	\
2758c2ecf20Sopenharmony_cistatic struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
2768c2ecf20Sopenharmony_ci	.attr = {.name = __stringify(_name), .mode = _mode },	\
2778c2ecf20Sopenharmony_ci	.value  = _data,					\
2788c2ecf20Sopenharmony_ci	.show   = _show,					\
2798c2ecf20Sopenharmony_ci	.store  = _store,					\
2808c2ecf20Sopenharmony_ci};
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci/* PCI Parity control files */
2838c2ecf20Sopenharmony_ciEDAC_PCI_ATTR(check_pci_errors, S_IRUGO | S_IWUSR, edac_pci_int_show,
2848c2ecf20Sopenharmony_ci	edac_pci_int_store);
2858c2ecf20Sopenharmony_ciEDAC_PCI_ATTR(edac_pci_log_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
2868c2ecf20Sopenharmony_ci	edac_pci_int_store);
2878c2ecf20Sopenharmony_ciEDAC_PCI_ATTR(edac_pci_log_npe, S_IRUGO | S_IWUSR, edac_pci_int_show,
2888c2ecf20Sopenharmony_ci	edac_pci_int_store);
2898c2ecf20Sopenharmony_ciEDAC_PCI_ATTR(edac_pci_panic_on_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
2908c2ecf20Sopenharmony_ci	edac_pci_int_store);
2918c2ecf20Sopenharmony_ciEDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
2928c2ecf20Sopenharmony_ciEDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/* Base Attributes of the memory ECC object */
2958c2ecf20Sopenharmony_cistatic struct edac_pci_dev_attribute *edac_pci_attr[] = {
2968c2ecf20Sopenharmony_ci	&edac_pci_attr_check_pci_errors,
2978c2ecf20Sopenharmony_ci	&edac_pci_attr_edac_pci_log_pe,
2988c2ecf20Sopenharmony_ci	&edac_pci_attr_edac_pci_log_npe,
2998c2ecf20Sopenharmony_ci	&edac_pci_attr_edac_pci_panic_on_pe,
3008c2ecf20Sopenharmony_ci	&edac_pci_attr_pci_parity_count,
3018c2ecf20Sopenharmony_ci	&edac_pci_attr_pci_nonparity_count,
3028c2ecf20Sopenharmony_ci	NULL,
3038c2ecf20Sopenharmony_ci};
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci/*
3068c2ecf20Sopenharmony_ci * edac_pci_release_main_kobj
3078c2ecf20Sopenharmony_ci *
3088c2ecf20Sopenharmony_ci *	This release function is called when the reference count to the
3098c2ecf20Sopenharmony_ci *	passed kobj goes to zero.
3108c2ecf20Sopenharmony_ci *
3118c2ecf20Sopenharmony_ci *	This kobj is the 'main' kobject that EDAC PCI instances
3128c2ecf20Sopenharmony_ci *	link to, and thus provide for proper nesting counts
3138c2ecf20Sopenharmony_ci */
3148c2ecf20Sopenharmony_cistatic void edac_pci_release_main_kobj(struct kobject *kobj)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	edac_dbg(0, "here to module_put(THIS_MODULE)\n");
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	kfree(kobj);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/* last reference to top EDAC PCI kobject has been removed,
3218c2ecf20Sopenharmony_ci	 * NOW release our ref count on the core module
3228c2ecf20Sopenharmony_ci	 */
3238c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci/* ktype struct for the EDAC PCI main kobj */
3278c2ecf20Sopenharmony_cistatic struct kobj_type ktype_edac_pci_main_kobj = {
3288c2ecf20Sopenharmony_ci	.release = edac_pci_release_main_kobj,
3298c2ecf20Sopenharmony_ci	.sysfs_ops = &edac_pci_sysfs_ops,
3308c2ecf20Sopenharmony_ci	.default_attrs = (struct attribute **)edac_pci_attr,
3318c2ecf20Sopenharmony_ci};
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci/**
3348c2ecf20Sopenharmony_ci * edac_pci_main_kobj_setup: Setup the sysfs for EDAC PCI attributes.
3358c2ecf20Sopenharmony_ci */
3368c2ecf20Sopenharmony_cistatic int edac_pci_main_kobj_setup(void)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	int err;
3398c2ecf20Sopenharmony_ci	struct bus_type *edac_subsys;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	edac_dbg(0, "\n");
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/* check and count if we have already created the main kobject */
3448c2ecf20Sopenharmony_ci	if (atomic_inc_return(&edac_pci_sysfs_refcount) != 1)
3458c2ecf20Sopenharmony_ci		return 0;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* First time, so create the main kobject and its
3488c2ecf20Sopenharmony_ci	 * controls and attributes
3498c2ecf20Sopenharmony_ci	 */
3508c2ecf20Sopenharmony_ci	edac_subsys = edac_get_sysfs_subsys();
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* Bump the reference count on this module to ensure the
3538c2ecf20Sopenharmony_ci	 * modules isn't unloaded until we deconstruct the top
3548c2ecf20Sopenharmony_ci	 * level main kobj for EDAC PCI
3558c2ecf20Sopenharmony_ci	 */
3568c2ecf20Sopenharmony_ci	if (!try_module_get(THIS_MODULE)) {
3578c2ecf20Sopenharmony_ci		edac_dbg(1, "try_module_get() failed\n");
3588c2ecf20Sopenharmony_ci		err = -ENODEV;
3598c2ecf20Sopenharmony_ci		goto decrement_count_fail;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
3638c2ecf20Sopenharmony_ci	if (!edac_pci_top_main_kobj) {
3648c2ecf20Sopenharmony_ci		edac_dbg(1, "Failed to allocate\n");
3658c2ecf20Sopenharmony_ci		err = -ENOMEM;
3668c2ecf20Sopenharmony_ci		goto kzalloc_fail;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* Instanstiate the pci object */
3708c2ecf20Sopenharmony_ci	err = kobject_init_and_add(edac_pci_top_main_kobj,
3718c2ecf20Sopenharmony_ci				   &ktype_edac_pci_main_kobj,
3728c2ecf20Sopenharmony_ci				   &edac_subsys->dev_root->kobj, "pci");
3738c2ecf20Sopenharmony_ci	if (err) {
3748c2ecf20Sopenharmony_ci		edac_dbg(1, "Failed to register '.../edac/pci'\n");
3758c2ecf20Sopenharmony_ci		goto kobject_init_and_add_fail;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* At this point, to 'release' the top level kobject
3798c2ecf20Sopenharmony_ci	 * for EDAC PCI, then edac_pci_main_kobj_teardown()
3808c2ecf20Sopenharmony_ci	 * must be used, for resources to be cleaned up properly
3818c2ecf20Sopenharmony_ci	 */
3828c2ecf20Sopenharmony_ci	kobject_uevent(edac_pci_top_main_kobj, KOBJ_ADD);
3838c2ecf20Sopenharmony_ci	edac_dbg(1, "Registered '.../edac/pci' kobject\n");
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	return 0;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* Error unwind statck */
3888c2ecf20Sopenharmony_cikobject_init_and_add_fail:
3898c2ecf20Sopenharmony_ci	kobject_put(edac_pci_top_main_kobj);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cikzalloc_fail:
3928c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cidecrement_count_fail:
3958c2ecf20Sopenharmony_ci	/* if are on this error exit, nothing to tear down */
3968c2ecf20Sopenharmony_ci	atomic_dec(&edac_pci_sysfs_refcount);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return err;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci/*
4028c2ecf20Sopenharmony_ci * edac_pci_main_kobj_teardown()
4038c2ecf20Sopenharmony_ci *
4048c2ecf20Sopenharmony_ci *	if no longer linked (needed) remove the top level EDAC PCI
4058c2ecf20Sopenharmony_ci *	kobject with its controls and attributes
4068c2ecf20Sopenharmony_ci */
4078c2ecf20Sopenharmony_cistatic void edac_pci_main_kobj_teardown(void)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	edac_dbg(0, "\n");
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* Decrement the count and only if no more controller instances
4128c2ecf20Sopenharmony_ci	 * are connected perform the unregisteration of the top level
4138c2ecf20Sopenharmony_ci	 * main kobj
4148c2ecf20Sopenharmony_ci	 */
4158c2ecf20Sopenharmony_ci	if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
4168c2ecf20Sopenharmony_ci		edac_dbg(0, "called kobject_put on main kobj\n");
4178c2ecf20Sopenharmony_ci		kobject_put(edac_pci_top_main_kobj);
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ciint edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	int err;
4248c2ecf20Sopenharmony_ci	struct kobject *edac_kobj = &pci->kobj;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	edac_dbg(0, "idx=%d\n", pci->pci_idx);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* create the top main EDAC PCI kobject, IF needed */
4298c2ecf20Sopenharmony_ci	err = edac_pci_main_kobj_setup();
4308c2ecf20Sopenharmony_ci	if (err)
4318c2ecf20Sopenharmony_ci		return err;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/* Create this instance's kobject under the MAIN kobject */
4348c2ecf20Sopenharmony_ci	err = edac_pci_create_instance_kobj(pci, pci->pci_idx);
4358c2ecf20Sopenharmony_ci	if (err)
4368c2ecf20Sopenharmony_ci		goto unregister_cleanup;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
4398c2ecf20Sopenharmony_ci	if (err) {
4408c2ecf20Sopenharmony_ci		edac_dbg(0, "sysfs_create_link() returned err= %d\n", err);
4418c2ecf20Sopenharmony_ci		goto symlink_fail;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	return 0;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/* Error unwind stack */
4478c2ecf20Sopenharmony_cisymlink_fail:
4488c2ecf20Sopenharmony_ci	edac_pci_unregister_sysfs_instance_kobj(pci);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ciunregister_cleanup:
4518c2ecf20Sopenharmony_ci	edac_pci_main_kobj_teardown();
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	return err;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_civoid edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	edac_dbg(0, "index=%d\n", pci->pci_idx);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	/* Remove the symlink */
4618c2ecf20Sopenharmony_ci	sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/* remove this PCI instance's sysfs entries */
4648c2ecf20Sopenharmony_ci	edac_pci_unregister_sysfs_instance_kobj(pci);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* Call the main unregister function, which will determine
4678c2ecf20Sopenharmony_ci	 * if this 'pci' is the last instance.
4688c2ecf20Sopenharmony_ci	 * If it is, the main kobject will be unregistered as a result
4698c2ecf20Sopenharmony_ci	 */
4708c2ecf20Sopenharmony_ci	edac_dbg(0, "calling edac_pci_main_kobj_teardown()\n");
4718c2ecf20Sopenharmony_ci	edac_pci_main_kobj_teardown();
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci/************************ PCI error handling *************************/
4758c2ecf20Sopenharmony_cistatic u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	int where;
4788c2ecf20Sopenharmony_ci	u16 status;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
4818c2ecf20Sopenharmony_ci	pci_read_config_word(dev, where, &status);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/* If we get back 0xFFFF then we must suspect that the card has been
4848c2ecf20Sopenharmony_ci	 * pulled but the Linux PCI layer has not yet finished cleaning up.
4858c2ecf20Sopenharmony_ci	 * We don't want to report on such devices
4868c2ecf20Sopenharmony_ci	 */
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (status == 0xFFFF) {
4898c2ecf20Sopenharmony_ci		u32 sanity;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, 0, &sanity);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci		if (sanity == 0xFFFFFFFF)
4948c2ecf20Sopenharmony_ci			return 0;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
4988c2ecf20Sopenharmony_ci		PCI_STATUS_PARITY;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (status)
5018c2ecf20Sopenharmony_ci		/* reset only the bits we are interested in */
5028c2ecf20Sopenharmony_ci		pci_write_config_word(dev, where, status);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	return status;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci/* Clear any PCI parity errors logged by this device. */
5098c2ecf20Sopenharmony_cistatic void edac_pci_dev_parity_clear(struct pci_dev *dev)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	u8 header_type;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	get_pci_parity_status(dev, 0);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/* read the device TYPE, looking for bridges */
5168c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
5198c2ecf20Sopenharmony_ci		get_pci_parity_status(dev, 1);
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci/*
5238c2ecf20Sopenharmony_ci *  PCI Parity polling
5248c2ecf20Sopenharmony_ci *
5258c2ecf20Sopenharmony_ci *	Function to retrieve the current parity status
5268c2ecf20Sopenharmony_ci *	and decode it
5278c2ecf20Sopenharmony_ci *
5288c2ecf20Sopenharmony_ci */
5298c2ecf20Sopenharmony_cistatic void edac_pci_dev_parity_test(struct pci_dev *dev)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	unsigned long flags;
5328c2ecf20Sopenharmony_ci	u16 status;
5338c2ecf20Sopenharmony_ci	u8 header_type;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* stop any interrupts until we can acquire the status */
5368c2ecf20Sopenharmony_ci	local_irq_save(flags);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/* read the STATUS register on this device */
5398c2ecf20Sopenharmony_ci	status = get_pci_parity_status(dev, 0);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	/* read the device TYPE, looking for bridges */
5428c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	local_irq_restore(flags);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	edac_dbg(4, "PCI STATUS= 0x%04x %s\n", status, dev_name(&dev->dev));
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	/* check the status reg for errors on boards NOT marked as broken
5498c2ecf20Sopenharmony_ci	 * if broken, we cannot trust any of the status bits
5508c2ecf20Sopenharmony_ci	 */
5518c2ecf20Sopenharmony_ci	if (status && !dev->broken_parity_status) {
5528c2ecf20Sopenharmony_ci		if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
5538c2ecf20Sopenharmony_ci			edac_printk(KERN_CRIT, EDAC_PCI,
5548c2ecf20Sopenharmony_ci				"Signaled System Error on %s\n",
5558c2ecf20Sopenharmony_ci				pci_name(dev));
5568c2ecf20Sopenharmony_ci			atomic_inc(&pci_nonparity_count);
5578c2ecf20Sopenharmony_ci		}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci		if (status & (PCI_STATUS_PARITY)) {
5608c2ecf20Sopenharmony_ci			edac_printk(KERN_CRIT, EDAC_PCI,
5618c2ecf20Sopenharmony_ci				"Master Data Parity Error on %s\n",
5628c2ecf20Sopenharmony_ci				pci_name(dev));
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci			atomic_inc(&pci_parity_count);
5658c2ecf20Sopenharmony_ci		}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci		if (status & (PCI_STATUS_DETECTED_PARITY)) {
5688c2ecf20Sopenharmony_ci			edac_printk(KERN_CRIT, EDAC_PCI,
5698c2ecf20Sopenharmony_ci				"Detected Parity Error on %s\n",
5708c2ecf20Sopenharmony_ci				pci_name(dev));
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci			atomic_inc(&pci_parity_count);
5738c2ecf20Sopenharmony_ci		}
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	edac_dbg(4, "PCI HEADER TYPE= 0x%02x %s\n",
5788c2ecf20Sopenharmony_ci		 header_type, dev_name(&dev->dev));
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
5818c2ecf20Sopenharmony_ci		/* On bridges, need to examine secondary status register  */
5828c2ecf20Sopenharmony_ci		status = get_pci_parity_status(dev, 1);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		edac_dbg(4, "PCI SEC_STATUS= 0x%04x %s\n",
5858c2ecf20Sopenharmony_ci			 status, dev_name(&dev->dev));
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		/* check the secondary status reg for errors,
5888c2ecf20Sopenharmony_ci		 * on NOT broken boards
5898c2ecf20Sopenharmony_ci		 */
5908c2ecf20Sopenharmony_ci		if (status && !dev->broken_parity_status) {
5918c2ecf20Sopenharmony_ci			if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
5928c2ecf20Sopenharmony_ci				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
5938c2ecf20Sopenharmony_ci					"Signaled System Error on %s\n",
5948c2ecf20Sopenharmony_ci					pci_name(dev));
5958c2ecf20Sopenharmony_ci				atomic_inc(&pci_nonparity_count);
5968c2ecf20Sopenharmony_ci			}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci			if (status & (PCI_STATUS_PARITY)) {
5998c2ecf20Sopenharmony_ci				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
6008c2ecf20Sopenharmony_ci					"Master Data Parity Error on "
6018c2ecf20Sopenharmony_ci					"%s\n", pci_name(dev));
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci				atomic_inc(&pci_parity_count);
6048c2ecf20Sopenharmony_ci			}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci			if (status & (PCI_STATUS_DETECTED_PARITY)) {
6078c2ecf20Sopenharmony_ci				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
6088c2ecf20Sopenharmony_ci					"Detected Parity Error on %s\n",
6098c2ecf20Sopenharmony_ci					pci_name(dev));
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci				atomic_inc(&pci_parity_count);
6128c2ecf20Sopenharmony_ci			}
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci/* reduce some complexity in definition of the iterator */
6188c2ecf20Sopenharmony_citypedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci/*
6218c2ecf20Sopenharmony_ci * pci_dev parity list iterator
6228c2ecf20Sopenharmony_ci *
6238c2ecf20Sopenharmony_ci *	Scan the PCI device list looking for SERRORs, Master Parity ERRORS or
6248c2ecf20Sopenharmony_ci *	Parity ERRORs on primary or secondary devices.
6258c2ecf20Sopenharmony_ci */
6268c2ecf20Sopenharmony_cistatic inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	struct pci_dev *dev = NULL;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	for_each_pci_dev(dev)
6318c2ecf20Sopenharmony_ci		fn(dev);
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci/*
6358c2ecf20Sopenharmony_ci * edac_pci_do_parity_check
6368c2ecf20Sopenharmony_ci *
6378c2ecf20Sopenharmony_ci *	performs the actual PCI parity check operation
6388c2ecf20Sopenharmony_ci */
6398c2ecf20Sopenharmony_civoid edac_pci_do_parity_check(void)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	int before_count;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	edac_dbg(3, "\n");
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	/* if policy has PCI check off, leave now */
6468c2ecf20Sopenharmony_ci	if (!check_pci_errors)
6478c2ecf20Sopenharmony_ci		return;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	before_count = atomic_read(&pci_parity_count);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/* scan all PCI devices looking for a Parity Error on devices and
6528c2ecf20Sopenharmony_ci	 * bridges.
6538c2ecf20Sopenharmony_ci	 * The iterator calls pci_get_device() which might sleep, thus
6548c2ecf20Sopenharmony_ci	 * we cannot disable interrupts in this scan.
6558c2ecf20Sopenharmony_ci	 */
6568c2ecf20Sopenharmony_ci	edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	/* Only if operator has selected panic on PCI Error */
6598c2ecf20Sopenharmony_ci	if (edac_pci_get_panic_on_pe()) {
6608c2ecf20Sopenharmony_ci		/* If the count is different 'after' from 'before' */
6618c2ecf20Sopenharmony_ci		if (before_count != atomic_read(&pci_parity_count))
6628c2ecf20Sopenharmony_ci			panic("EDAC: PCI Parity Error");
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci/*
6678c2ecf20Sopenharmony_ci * edac_pci_clear_parity_errors
6688c2ecf20Sopenharmony_ci *
6698c2ecf20Sopenharmony_ci *	function to perform an iteration over the PCI devices
6708c2ecf20Sopenharmony_ci *	and clearn their current status
6718c2ecf20Sopenharmony_ci */
6728c2ecf20Sopenharmony_civoid edac_pci_clear_parity_errors(void)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	/* Clear any PCI bus parity errors that devices initially have logged
6758c2ecf20Sopenharmony_ci	 * in their registers.
6768c2ecf20Sopenharmony_ci	 */
6778c2ecf20Sopenharmony_ci	edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci/*
6818c2ecf20Sopenharmony_ci * edac_pci_handle_pe
6828c2ecf20Sopenharmony_ci *
6838c2ecf20Sopenharmony_ci *	Called to handle a PARITY ERROR event
6848c2ecf20Sopenharmony_ci */
6858c2ecf20Sopenharmony_civoid edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	/* global PE counter incremented by edac_pci_do_parity_check() */
6898c2ecf20Sopenharmony_ci	atomic_inc(&pci->counters.pe_count);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (edac_pci_get_log_pe())
6928c2ecf20Sopenharmony_ci		edac_pci_printk(pci, KERN_WARNING,
6938c2ecf20Sopenharmony_ci				"Parity Error ctl: %s %d: %s\n",
6948c2ecf20Sopenharmony_ci				pci->ctl_name, pci->pci_idx, msg);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	/*
6978c2ecf20Sopenharmony_ci	 * poke all PCI devices and see which one is the troublemaker
6988c2ecf20Sopenharmony_ci	 * panic() is called if set
6998c2ecf20Sopenharmony_ci	 */
7008c2ecf20Sopenharmony_ci	edac_pci_do_parity_check();
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(edac_pci_handle_pe);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci/*
7068c2ecf20Sopenharmony_ci * edac_pci_handle_npe
7078c2ecf20Sopenharmony_ci *
7088c2ecf20Sopenharmony_ci *	Called to handle a NON-PARITY ERROR event
7098c2ecf20Sopenharmony_ci */
7108c2ecf20Sopenharmony_civoid edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	/* global NPE counter incremented by edac_pci_do_parity_check() */
7148c2ecf20Sopenharmony_ci	atomic_inc(&pci->counters.npe_count);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	if (edac_pci_get_log_npe())
7178c2ecf20Sopenharmony_ci		edac_pci_printk(pci, KERN_WARNING,
7188c2ecf20Sopenharmony_ci				"Non-Parity Error ctl: %s %d: %s\n",
7198c2ecf20Sopenharmony_ci				pci->ctl_name, pci->pci_idx, msg);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	/*
7228c2ecf20Sopenharmony_ci	 * poke all PCI devices and see which one is the troublemaker
7238c2ecf20Sopenharmony_ci	 * panic() is called if set
7248c2ecf20Sopenharmony_ci	 */
7258c2ecf20Sopenharmony_ci	edac_pci_do_parity_check();
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(edac_pci_handle_npe);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci/*
7308c2ecf20Sopenharmony_ci * Define the PCI parameter to the module
7318c2ecf20Sopenharmony_ci */
7328c2ecf20Sopenharmony_cimodule_param(check_pci_errors, int, 0644);
7338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(check_pci_errors,
7348c2ecf20Sopenharmony_ci		 "Check for PCI bus parity errors: 0=off 1=on");
7358c2ecf20Sopenharmony_cimodule_param(edac_pci_panic_on_pe, int, 0644);
7368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(edac_pci_panic_on_pe,
7378c2ecf20Sopenharmony_ci		 "Panic on PCI Bus Parity error: 0=off 1=on");
738