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