edac_mc.c revision 9110540f7f2bbcc3577d2580a696fbb7af68c892
1da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 2da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * edac_mc kernel module 3da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * (C) 2005 Linux Networx (http://lnxi.com) 4da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * This file may be distributed under the terms of the 5da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * GNU General Public License. 6da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 7da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Written by Thayne Harbaugh 8da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Based on work by Dan Hollis <goemon at anime dot net> and others. 9da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * http://www.anime.net/~goemon/linux-ecc/ 10da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 11da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Modified by Dave Peterson and Doug Thompson 12da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 13da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 14da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 15da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/config.h> 16da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/module.h> 17da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/proc_fs.h> 18da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/kernel.h> 19da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/types.h> 20da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/smp.h> 21da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/init.h> 22da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/sysctl.h> 23da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/highmem.h> 24da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/timer.h> 25da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/slab.h> 26da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/jiffies.h> 27da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/spinlock.h> 28da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/list.h> 29da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/sysdev.h> 30da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/ctype.h> 31f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson#include <linux/kthread.h> 32da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <asm/uaccess.h> 33da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <asm/page.h> 34da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <asm/edac.h> 35da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include "edac_mc.h" 36da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 37e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson#define EDAC_MC_VERSION "Ver: 2.0.0 " __DATE__ 38da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 39ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson/* For now, disable the EDAC sysfs code. The sysfs interface that EDAC 40ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson * presents to user space needs more thought, and is likely to change 41ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson * substantially. 42ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson */ 43ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#define DISABLE_EDAC_SYSFS 44ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson 45da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#ifdef CONFIG_EDAC_DEBUG 46da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Values of 0 to 4 will generate output */ 47da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxint edac_debug_level = 1; 489110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_debug_level); 49da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#endif 50da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 51da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* EDAC Controls, setable by module parameter, and sysfs */ 52da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int log_ue = 1; 53da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int log_ce = 1; 54ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Petersonstatic int panic_on_ue; 55da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int poll_msec = 1000; 56da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 57da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int check_pci_parity = 0; /* default YES check PCI parity */ 58da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int panic_on_pci_parity; /* default no panic on PCI Parity */ 59da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic atomic_t pci_parity_count = ATOMIC_INIT(0); 60da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 61da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* lock to memory controller's control array */ 62da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic DECLARE_MUTEX(mem_ctls_mutex); 63da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); 64da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 65f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Petersonstatic struct task_struct *edac_thread; 66f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson 67da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Structure of the whitelist and blacklist arrays */ 68da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct edac_pci_device_list { 69da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned int vendor; /* Vendor ID */ 70da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned int device; /* Deviice ID */ 71da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 72da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 73da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define MAX_LISTED_PCI_DEVICES 32 74da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 75da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* List of PCI devices (vendor-id:device-id) that should be skipped */ 76da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct edac_pci_device_list pci_blacklist[MAX_LISTED_PCI_DEVICES]; 77da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int pci_blacklist_count; 78da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 79da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* List of PCI devices (vendor-id:device-id) that should be scanned */ 80da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct edac_pci_device_list pci_whitelist[MAX_LISTED_PCI_DEVICES]; 81da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int pci_whitelist_count ; 82da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 83da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* START sysfs data and methods */ 84da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 85ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifndef DISABLE_EDAC_SYSFS 86ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson 87da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic const char *mem_types[] = { 88da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_EMPTY] = "Empty", 89da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_RESERVED] = "Reserved", 90da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_UNKNOWN] = "Unknown", 91da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_FPM] = "FPM", 92da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_EDO] = "EDO", 93da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_BEDO] = "BEDO", 94da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_SDR] = "Unbuffered-SDR", 95da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_RDR] = "Registered-SDR", 96da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_DDR] = "Unbuffered-DDR", 97da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_RDDR] = "Registered-DDR", 98da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [MEM_RMBS] = "RMBS" 99da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 100da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 101da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic const char *dev_types[] = { 102da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [DEV_UNKNOWN] = "Unknown", 103da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [DEV_X1] = "x1", 104da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [DEV_X2] = "x2", 105da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [DEV_X4] = "x4", 106da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [DEV_X8] = "x8", 107da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [DEV_X16] = "x16", 108da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [DEV_X32] = "x32", 109da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [DEV_X64] = "x64" 110da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 111da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 112da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic const char *edac_caps[] = { 113da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_UNKNOWN] = "Unknown", 114da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_NONE] = "None", 115da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_RESERVED] = "Reserved", 116da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_PARITY] = "PARITY", 117da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_EC] = "EC", 118da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_SECDED] = "SECDED", 119da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_S2ECD2ED] = "S2ECD2ED", 120da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_S4ECD4ED] = "S4ECD4ED", 121da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_S8ECD8ED] = "S8ECD8ED", 122da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox [EDAC_S16ECD16ED] = "S16ECD16ED" 123da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 124da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 125da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* sysfs object: /sys/devices/system/edac */ 126da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct sysdev_class edac_class = { 127da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox set_kset_name("edac"), 128da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 129da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 130da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* sysfs objects: 131da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * /sys/devices/system/edac/mc 132da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * /sys/devices/system/edac/pci 133da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 134da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct kobject edac_memctrl_kobj; 135da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct kobject edac_pci_kobj; 136da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 137472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson/* We use these to wait for the reference counts on edac_memctrl_kobj and 138472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * edac_pci_kobj to reach 0. 139472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson */ 140472678ebd30d87cbe8d97562dcc0e46d1076040fDave Petersonstatic struct completion edac_memctrl_kobj_complete; 141472678ebd30d87cbe8d97562dcc0e46d1076040fDave Petersonstatic struct completion edac_pci_kobj_complete; 142472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson 143da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 144da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * /sys/devices/system/edac/mc; 145e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson * data structures and methods 146da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1474136cabff33d6d73b8daf2f2612670cc0296f844Arjan van de Ven#if 0 148da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t memctrl_string_show(void *ptr, char *buffer) 149da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 150da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *value = (char*) ptr; 151da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(buffer, "%s\n", value); 152da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1534136cabff33d6d73b8daf2f2612670cc0296f844Arjan van de Ven#endif 154da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 155da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t memctrl_int_show(void *ptr, char *buffer) 156da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 157da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int *value = (int*) ptr; 158da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(buffer, "%d\n", *value); 159da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 160da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 161da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count) 162da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 163da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int *value = (int*) ptr; 164da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 165da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (isdigit(*buffer)) 166da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox *value = simple_strtoul(buffer, NULL, 0); 167da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 168da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return count; 169da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 170da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 171da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct memctrl_dev_attribute { 172e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson struct attribute attr; 173e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson void *value; 174da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t (*show)(void *,char *); 175da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t (*store)(void *, const char *, size_t); 176da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 177da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 178da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Set of show/store abstract level functions for memory control object */ 179e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic ssize_t memctrl_dev_show(struct kobject *kobj, 180e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson struct attribute *attr, char *buffer) 181da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 182da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct memctrl_dev_attribute *memctrl_dev; 183da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox memctrl_dev = (struct memctrl_dev_attribute*)attr; 184da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 185da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (memctrl_dev->show) 186da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return memctrl_dev->show(memctrl_dev->value, buffer); 187e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 188da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -EIO; 189da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 190da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 191e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr, 192e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson const char *buffer, size_t count) 193da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 194da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct memctrl_dev_attribute *memctrl_dev; 195da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox memctrl_dev = (struct memctrl_dev_attribute*)attr; 196da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 197da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (memctrl_dev->store) 198da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return memctrl_dev->store(memctrl_dev->value, buffer, count); 199e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 200da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -EIO; 201da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 202da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 203da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct sysfs_ops memctrlfs_ops = { 204da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = memctrl_dev_show, 205da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = memctrl_dev_store 206da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 207da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 208da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define MEMCTRL_ATTR(_name,_mode,_show,_store) \ 209da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct memctrl_dev_attribute attr_##_name = { \ 210da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .attr = {.name = __stringify(_name), .mode = _mode }, \ 211da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .value = &_name, \ 212da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = _show, \ 213da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = _store, \ 214da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 215da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 216da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define MEMCTRL_STRING_ATTR(_name,_data,_mode,_show,_store) \ 217da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct memctrl_dev_attribute attr_##_name = { \ 218da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .attr = {.name = __stringify(_name), .mode = _mode }, \ 219da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .value = _data, \ 220da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = _show, \ 221da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = _store, \ 222da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 223da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 224da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* cwrow<id> attribute f*/ 2254136cabff33d6d73b8daf2f2612670cc0296f844Arjan van de Ven#if 0 226da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMEMCTRL_STRING_ATTR(mc_version,EDAC_MC_VERSION,S_IRUGO,memctrl_string_show,NULL); 2274136cabff33d6d73b8daf2f2612670cc0296f844Arjan van de Ven#endif 228da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 229da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* csrow<id> control files */ 230da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); 231da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); 232da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); 233da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); 234da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 235da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Base Attributes of the memory ECC object */ 236da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct memctrl_dev_attribute *memctrl_attr[] = { 237da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_panic_on_ue, 238da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_log_ue, 239da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_log_ce, 240da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_poll_msec, 241da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox NULL, 242da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 243da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 244da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Main MC kobject release() function */ 245da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void edac_memctrl_master_release(struct kobject *kobj) 246da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 247537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf1("%s()\n", __func__); 248472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson complete(&edac_memctrl_kobj_complete); 249da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 250da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 251da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct kobj_type ktype_memctrl = { 252e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .release = edac_memctrl_master_release, 253e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .sysfs_ops = &memctrlfs_ops, 254e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .default_attrs = (struct attribute **) memctrl_attr, 255da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 256da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 257ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif /* DISABLE_EDAC_SYSFS */ 258da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 259da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Initialize the main sysfs entries for edac: 260da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * /sys/devices/system/edac 261da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 262da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * and children 263da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 264da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Return: 0 SUCCESS 265da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * !0 FAILURE 266da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 267da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int edac_sysfs_memctrl_setup(void) 268ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifdef DISABLE_EDAC_SYSFS 269ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson{ 270ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson return 0; 271ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson} 272ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#else 273da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 274da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int err=0; 275da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 276537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf1("%s()\n", __func__); 277da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 278da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* create the /sys/devices/system/edac directory */ 279da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = sysdev_class_register(&edac_class); 280e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 281da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!err) { 282da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Init the MC's kobject */ 283da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); 284da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_memctrl_kobj.parent = &edac_class.kset.kobj; 285da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_memctrl_kobj.ktype = &ktype_memctrl; 286da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 287da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* generate sysfs "..../edac/mc" */ 288da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = kobject_set_name(&edac_memctrl_kobj,"mc"); 289e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 290da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!err) { 291da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* FIXME: maybe new sysdev_create_subdir() */ 292da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = kobject_register(&edac_memctrl_kobj); 293e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 294e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson if (err) 295da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf1("Failed to register '.../edac/mc'\n"); 296e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson else 297da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf1("Registered '.../edac/mc' kobject\n"); 298da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 299e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson } else 300537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf1("%s() error=%d\n", __func__, err); 301da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 302da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return err; 303da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 304ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif /* DISABLE_EDAC_SYSFS */ 305da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 306da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 307da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * MC teardown: 308da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * the '..../edac/mc' kobject followed by '..../edac' itself 309da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 310da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void edac_sysfs_memctrl_teardown(void) 311da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 312ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifndef DISABLE_EDAC_SYSFS 313da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf0("MC: " __FILE__ ": %s()\n", __func__); 314da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 315472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson /* Unregister the MC's kobject and wait for reference count to reach 316472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * 0. 317472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson */ 318472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson init_completion(&edac_memctrl_kobj_complete); 319da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox kobject_unregister(&edac_memctrl_kobj); 320472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson wait_for_completion(&edac_memctrl_kobj_complete); 321da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 322da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Unregister the 'edac' object */ 323da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox sysdev_class_unregister(&edac_class); 324ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif /* DISABLE_EDAC_SYSFS */ 325da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 326da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 327ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifndef DISABLE_EDAC_SYSFS 328ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson 329da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 330da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * /sys/devices/system/edac/pci; 331da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * data structures and methods 332da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 333da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 334da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct list_control { 335da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct edac_pci_device_list *list; 336da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int *count; 337da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 338da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 3394136cabff33d6d73b8daf2f2612670cc0296f844Arjan van de Ven#if 0 340da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Output the list as: vendor_id:device:id<,vendor_id:device_id> */ 341da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t edac_pci_list_string_show(void *ptr, char *buffer) 342da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 343da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct list_control *listctl; 344da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct edac_pci_device_list *list; 345da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *p = buffer; 346da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int len=0; 347da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int i; 348da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 349da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox listctl = ptr; 350da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list = listctl->list; 351da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 352da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (i = 0; i < *(listctl->count); i++, list++ ) { 353da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (len > 0) 354da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox len += snprintf(p + len, (PAGE_SIZE-len), ","); 355da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 356da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox len += snprintf(p + len, 357da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox (PAGE_SIZE-len), 358da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox "%x:%x", 359da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list->vendor,list->device); 360da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 361da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 362da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox len += snprintf(p + len,(PAGE_SIZE-len), "\n"); 363da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return (ssize_t) len; 364da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 365da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 366da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 367da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 368da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Scan string from **s to **e looking for one 'vendor:device' tuple 369da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * where each field is a hex value 370da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 371da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * return 0 if an entry is NOT found 372da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * return 1 if an entry is found 373da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * fill in *vendor_id and *device_id with values found 374da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 375da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * In both cases, make sure *s has been moved forward toward *e 376da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 377da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int parse_one_device(const char **s,const char **e, 378da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned int *vendor_id, unsigned int *device_id) 379da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 380da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox const char *runner, *p; 381da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 382da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* if null byte, we are done */ 383da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!**s) { 384e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson (*s)++; /* keep *s moving */ 385da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 386da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 387da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 388da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* skip over newlines & whitespace */ 389da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if ((**s == '\n') || isspace(**s)) { 390da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox (*s)++; 391da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 392da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 393da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 394da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!isxdigit(**s)) { 395da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox (*s)++; 396da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 397da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 398da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 399da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* parse vendor_id */ 400da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox runner = *s; 401e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 402da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox while (runner < *e) { 403da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* scan for vendor:device delimiter */ 404da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (*runner == ':') { 405da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox *vendor_id = simple_strtol((char*) *s, (char**) &p, 16); 406da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox runner = p + 1; 407da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox break; 408da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 409e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 410da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox runner++; 411da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 412da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 413da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!isxdigit(*runner)) { 414da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox *s = ++runner; 415da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 416da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 417da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 418da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* parse device_id */ 419da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (runner < *e) { 420da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox *device_id = simple_strtol((char*)runner, (char**)&p, 16); 421da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox runner = p; 422da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 423da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 424da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox *s = runner; 425da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 1; 426da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 427da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 428da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t edac_pci_list_string_store(void *ptr, const char *buffer, 429e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson size_t count) 430da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 431da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct list_control *listctl; 432da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct edac_pci_device_list *list; 433da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned int vendor_id, device_id; 434da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox const char *s, *e; 435da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int *index; 436da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 437da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox s = (char*)buffer; 438da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox e = s + count; 439da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox listctl = ptr; 440da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list = listctl->list; 441da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox index = listctl->count; 442da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox *index = 0; 443da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 444e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson while (*index < MAX_LISTED_PCI_DEVICES) { 445da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (parse_one_device(&s,&e,&vendor_id,&device_id)) { 446da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list[ *index ].vendor = vendor_id; 447da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list[ *index ].device = device_id; 448da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox (*index)++; 449da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 450da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 451da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* check for all data consume */ 452da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (s >= e) 453da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox break; 454da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 455da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 456da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return count; 457da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 458da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 4594136cabff33d6d73b8daf2f2612670cc0296f844Arjan van de Ven#endif 460da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t edac_pci_int_show(void *ptr, char *buffer) 461da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 462da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int *value = ptr; 463da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(buffer,"%d\n",*value); 464da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 465da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 466da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count) 467da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 468da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int *value = ptr; 469da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 470da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (isdigit(*buffer)) 471da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox *value = simple_strtoul(buffer,NULL,0); 472da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 473da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return count; 474da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 475da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 476da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct edac_pci_dev_attribute { 477e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson struct attribute attr; 478e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson void *value; 479da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t (*show)(void *,char *); 480da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t (*store)(void *, const char *,size_t); 481da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 482da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 483da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Set of show/store abstract level functions for PCI Parity object */ 484da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr, 485e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson char *buffer) 486da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 487da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct edac_pci_dev_attribute *edac_pci_dev; 488da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_dev= (struct edac_pci_dev_attribute*)attr; 489da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 490da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_pci_dev->show) 491da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return edac_pci_dev->show(edac_pci_dev->value, buffer); 492da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -EIO; 493da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 494da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 495e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic ssize_t edac_pci_dev_store(struct kobject *kobj, 496e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson struct attribute *attr, const char *buffer, size_t count) 497da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 498da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct edac_pci_dev_attribute *edac_pci_dev; 499da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_dev= (struct edac_pci_dev_attribute*)attr; 500da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 501da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_pci_dev->show) 502da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return edac_pci_dev->store(edac_pci_dev->value, buffer, count); 503da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -EIO; 504da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 505da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 506da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct sysfs_ops edac_pci_sysfs_ops = { 507da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = edac_pci_dev_show, 508da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = edac_pci_dev_store 509da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 510da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 511da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define EDAC_PCI_ATTR(_name,_mode,_show,_store) \ 512da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct edac_pci_dev_attribute edac_pci_attr_##_name = { \ 513da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .attr = {.name = __stringify(_name), .mode = _mode }, \ 514da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .value = &_name, \ 515da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = _show, \ 516da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = _store, \ 517da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 518da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 519da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store) \ 520da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct edac_pci_dev_attribute edac_pci_attr_##_name = { \ 521da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .attr = {.name = __stringify(_name), .mode = _mode }, \ 522da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .value = _data, \ 523da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = _show, \ 524da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = _store, \ 525da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 526da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 5274136cabff33d6d73b8daf2f2612670cc0296f844Arjan van de Ven#if 0 528da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct list_control pci_whitelist_control = { 529da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .list = pci_whitelist, 530da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .count = &pci_whitelist_count 531da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 532da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 533da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct list_control pci_blacklist_control = { 534da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .list = pci_blacklist, 535da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .count = &pci_blacklist_count 536da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 537da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 538da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* whitelist attribute */ 539da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxEDAC_PCI_STRING_ATTR(pci_parity_whitelist, 540da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &pci_whitelist_control, 541da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox S_IRUGO|S_IWUSR, 542da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_list_string_show, 543da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_list_string_store); 544da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 545da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxEDAC_PCI_STRING_ATTR(pci_parity_blacklist, 546da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &pci_blacklist_control, 547da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox S_IRUGO|S_IWUSR, 548da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_list_string_show, 549da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_list_string_store); 5504136cabff33d6d73b8daf2f2612670cc0296f844Arjan van de Ven#endif 551da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 552da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* PCI Parity control files */ 553e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave PetersonEDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, 554e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson edac_pci_int_store); 555e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave PetersonEDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, 556e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson edac_pci_int_store); 557e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave PetersonEDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL); 558da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 559da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Base Attributes of the memory ECC object */ 560da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct edac_pci_dev_attribute *edac_pci_attr[] = { 561da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &edac_pci_attr_check_pci_parity, 562da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &edac_pci_attr_panic_on_pci_parity, 563da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &edac_pci_attr_pci_parity_count, 564da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox NULL, 565da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 566da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 567da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* No memory to release */ 568da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void edac_pci_release(struct kobject *kobj) 569da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 570537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf1("%s()\n", __func__); 571472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson complete(&edac_pci_kobj_complete); 572da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 573da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 574da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct kobj_type ktype_edac_pci = { 575e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .release = edac_pci_release, 576e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .sysfs_ops = &edac_pci_sysfs_ops, 577e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .default_attrs = (struct attribute **) edac_pci_attr, 578da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 579da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 580ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif /* DISABLE_EDAC_SYSFS */ 581ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson 582da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 583da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * edac_sysfs_pci_setup() 584da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 585da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 586da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int edac_sysfs_pci_setup(void) 587ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifdef DISABLE_EDAC_SYSFS 588ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson{ 589ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson return 0; 590ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson} 591ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#else 592da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 593da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int err; 594da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 595537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf1("%s()\n", __func__); 596da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 597da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj)); 598da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_kobj.parent = &edac_class.kset.kobj; 599da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_kobj.ktype = &ktype_edac_pci; 600da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = kobject_set_name(&edac_pci_kobj, "pci"); 601e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 602da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!err) { 603da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Instanstiate the csrow object */ 604da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* FIXME: maybe new sysdev_create_subdir() */ 605da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = kobject_register(&edac_pci_kobj); 606e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 607da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (err) 608da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf1("Failed to register '.../edac/pci'\n"); 609da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else 610da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf1("Registered '.../edac/pci' kobject\n"); 611da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 612e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 613da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return err; 614da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 615ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif /* DISABLE_EDAC_SYSFS */ 616da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 617da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void edac_sysfs_pci_teardown(void) 618da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 619ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifndef DISABLE_EDAC_SYSFS 620537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf0("%s()\n", __func__); 621472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson init_completion(&edac_pci_kobj_complete); 622da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox kobject_unregister(&edac_pci_kobj); 623472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson wait_for_completion(&edac_pci_kobj_complete); 624ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif 625da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 626da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 627ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifndef DISABLE_EDAC_SYSFS 628ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson 629da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* EDAC sysfs CSROW data structures and methods */ 630da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 631da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Set of more detailed csrow<id> attribute show/store functions */ 632da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_ch0_dimm_label_show(struct csrow_info *csrow, char *data) 633da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 634da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t size = 0; 635da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 636da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_channels > 0) { 637da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox size = snprintf(data, EDAC_MC_LABEL_LEN,"%s\n", 638da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->channels[0].label); 639da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 640e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 641da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return size; 642da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 643da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 644da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_ch1_dimm_label_show(struct csrow_info *csrow, char *data) 645da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 646da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t size = 0; 647da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 648da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_channels > 0) { 649da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox size = snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", 650da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->channels[1].label); 651da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 652e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 653da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return size; 654da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 655da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 656da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow, 657e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson const char *data, size_t size) 658da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 659da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t max_size = 0; 660da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 661da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_channels > 0) { 662da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1); 663da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox strncpy(csrow->channels[0].label, data, max_size); 664da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->channels[0].label[max_size] = '\0'; 665da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 666e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 667da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return size; 668da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 669da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 670da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow, 671e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson const char *data, size_t size) 672da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 673da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t max_size = 0; 674da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 675da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_channels > 1) { 676da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1); 677da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox strncpy(csrow->channels[1].label, data, max_size); 678da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->channels[1].label[max_size] = '\0'; 679da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 680e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 681da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return max_size; 682da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 683da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 684da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data) 685da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 686da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%u\n", csrow->ue_count); 687da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 688da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 689da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data) 690da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 691da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%u\n", csrow->ce_count); 692da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 693da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 694da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_ch0_ce_count_show(struct csrow_info *csrow, char *data) 695da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 696da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t size = 0; 697da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 698da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_channels > 0) { 699da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox size = sprintf(data,"%u\n", csrow->channels[0].ce_count); 700da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 701e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 702da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return size; 703da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 704da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 705da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_ch1_ce_count_show(struct csrow_info *csrow, char *data) 706da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 707da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t size = 0; 708da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 709da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_channels > 1) { 710da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox size = sprintf(data,"%u\n", csrow->channels[1].ce_count); 711da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 712e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 713da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return size; 714da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 715da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 716da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_size_show(struct csrow_info *csrow, char *data) 717da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 718da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages)); 719da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 720da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 721da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data) 722da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 723da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%s\n", mem_types[csrow->mtype]); 724da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 725da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 726da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data) 727da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 728da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%s\n", dev_types[csrow->dtype]); 729da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 730da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 731da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data) 732da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 733da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]); 734da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 735da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 736da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct csrowdev_attribute { 737e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson struct attribute attr; 738da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t (*show)(struct csrow_info *,char *); 739da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t (*store)(struct csrow_info *, const char *,size_t); 740da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 741da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 742da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define to_csrow(k) container_of(k, struct csrow_info, kobj) 743da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr) 744da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 745da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Set of show/store higher level functions for csrow objects */ 746da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrowdev_show(struct kobject *kobj, struct attribute *attr, 747e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson char *buffer) 748da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 749da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csrow = to_csrow(kobj); 750da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr); 751da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 752da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrowdev_attr->show) 753da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return csrowdev_attr->show(csrow, buffer); 754e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 755da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -EIO; 756da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 757da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 758da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, 759e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson const char *buffer, size_t count) 760da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 761da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csrow = to_csrow(kobj); 762da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr); 763da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 764da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrowdev_attr->store) 765da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return csrowdev_attr->store(csrow, buffer, count); 766e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 767da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -EIO; 768da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 769da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 770da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct sysfs_ops csrowfs_ops = { 771da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = csrowdev_show, 772da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = csrowdev_store 773da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 774da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 775da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define CSROWDEV_ATTR(_name,_mode,_show,_store) \ 776da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct csrowdev_attribute attr_##_name = { \ 777da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .attr = {.name = __stringify(_name), .mode = _mode }, \ 778da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = _show, \ 779da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = _store, \ 780da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 781da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 782da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* cwrow<id>/attribute files */ 783da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL); 784da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL); 785da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL); 786da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL); 787da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL); 788da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL); 789da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(ch0_ce_count,S_IRUGO,csrow_ch0_ce_count_show,NULL); 790da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(ch1_ce_count,S_IRUGO,csrow_ch1_ce_count_show,NULL); 791da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 792da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* control/attribute files */ 793da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR, 794da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow_ch0_dimm_label_show, 795da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow_ch0_dimm_label_store); 796da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxCSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR, 797da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow_ch1_dimm_label_show, 798da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow_ch1_dimm_label_store); 799da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 800da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Attributes of the CSROW<id> object */ 801da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct csrowdev_attribute *csrow_attr[] = { 802da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_dev_type, 803da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_mem_type, 804da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_edac_mode, 805da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_size_mb, 806da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_ue_count, 807da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_ce_count, 808da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_ch0_ce_count, 809da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_ch1_ce_count, 810da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_ch0_dimm_label, 811da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &attr_ch1_dimm_label, 812da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox NULL, 813da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 814da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 815da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* No memory to release */ 816da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void edac_csrow_instance_release(struct kobject *kobj) 817da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 818472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson struct csrow_info *cs; 819472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson 820537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf1("%s()\n", __func__); 821472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson cs = container_of(kobj, struct csrow_info, kobj); 822472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson complete(&cs->kobj_complete); 823da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 824da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 825da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct kobj_type ktype_csrow = { 826e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .release = edac_csrow_instance_release, 827e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .sysfs_ops = &csrowfs_ops, 828e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .default_attrs = (struct attribute **) csrow_attr, 829da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 830da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 831da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Create a CSROW object under specifed edac_mc_device */ 832da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int edac_create_csrow_object(struct kobject *edac_mci_kobj, 833e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson struct csrow_info *csrow, int index) 834da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 835da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int err = 0; 836da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 837537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf0("%s()\n", __func__); 838da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox memset(&csrow->kobj, 0, sizeof(csrow->kobj)); 839da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 840da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* generate ..../edac/mc/mc<id>/csrow<index> */ 841da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 842da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->kobj.parent = edac_mci_kobj; 843da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->kobj.ktype = &ktype_csrow; 844da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 845da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* name this instance of csrow<id> */ 846da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = kobject_set_name(&csrow->kobj,"csrow%d",index); 847e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 848da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!err) { 849da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Instanstiate the csrow object */ 850da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = kobject_register(&csrow->kobj); 851e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 852da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (err) 853da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf0("Failed to register CSROW%d\n",index); 854da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else 855da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf0("Registered CSROW%d\n",index); 856da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 857da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 858da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return err; 859da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 860da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 861da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* sysfs data structures and methods for the MCI kobjects */ 862da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 863e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, 864e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson const char *data, size_t count) 865da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 866da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int row, chan; 867da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 868da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ue_noinfo_count = 0; 869da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ce_noinfo_count = 0; 870da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ue_count = 0; 871da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ce_count = 0; 872e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 873da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (row = 0; row < mci->nr_csrows; row++) { 874da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *ri = &mci->csrows[row]; 875da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 876da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ri->ue_count = 0; 877da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ri->ce_count = 0; 878e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 879da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (chan = 0; chan < ri->nr_channels; chan++) 880da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ri->channels[chan].ce_count = 0; 881da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 882da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 883e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson mci->start_time = jiffies; 884da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return count; 885da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 886da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 887da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) 888da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 889da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%d\n", mci->ue_count); 890da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 891da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 892da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data) 893da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 894da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%d\n", mci->ce_count); 895da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 896da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 897da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data) 898da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 899da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%d\n", mci->ce_noinfo_count); 900da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 901da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 902da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data) 903da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 904da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%d\n", mci->ue_noinfo_count); 905da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 906da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 907da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data) 908da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 909da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ); 910da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 911da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 912da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_mod_name_show(struct mem_ctl_info *mci, char *data) 913da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 914da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%s %s\n", mci->mod_name, mci->mod_ver); 915da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 916da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 917da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data) 918da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 919da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%s\n", mci->ctl_name); 920da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 921da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 922da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int mci_output_edac_cap(char *buf, unsigned long edac_cap) 923da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 924da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *p = buf; 925da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int bit_idx; 926da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 927da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (bit_idx = 0; bit_idx < 8 * sizeof(edac_cap); bit_idx++) { 928da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if ((edac_cap >> bit_idx) & 0x1) 929da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p += sprintf(p, "%s ", edac_caps[bit_idx]); 930da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 931da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 932da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return p - buf; 933da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 934da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 935da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_edac_capability_show(struct mem_ctl_info *mci, char *data) 936da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 937da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *p = data; 938da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 939da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p += mci_output_edac_cap(p,mci->edac_ctl_cap); 940da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p += sprintf(p, "\n"); 941da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return p - data; 942da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 943da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 944da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_edac_current_capability_show(struct mem_ctl_info *mci, 945e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson char *data) 946da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 947da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *p = data; 948da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 949da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p += mci_output_edac_cap(p,mci->edac_cap); 950da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p += sprintf(p, "\n"); 951da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return p - data; 952da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 953da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 954da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int mci_output_mtype_cap(char *buf, unsigned long mtype_cap) 955da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 956da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *p = buf; 957da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int bit_idx; 958da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 959da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (bit_idx = 0; bit_idx < 8 * sizeof(mtype_cap); bit_idx++) { 960da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if ((mtype_cap >> bit_idx) & 0x1) 961da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p += sprintf(p, "%s ", mem_types[bit_idx]); 962da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 963da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 964da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return p - buf; 965da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 966da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 967e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci, 968e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson char *data) 969da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 970da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *p = data; 971da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 972da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p += mci_output_mtype_cap(p,mci->mtype_cap); 973da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p += sprintf(p, "\n"); 974da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return p - data; 975da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 976da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 977da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) 978da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 979da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int total_pages, csrow_idx; 980da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 981da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows; 982da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow_idx++) { 983da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csrow = &mci->csrows[csrow_idx]; 984da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 985da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!csrow->nr_pages) 986da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox continue; 987e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 988da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox total_pages += csrow->nr_pages; 989da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 990da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 991da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return sprintf(data,"%u\n", PAGES_TO_MiB(total_pages)); 992da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 993da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 994da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct mcidev_attribute { 995e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson struct attribute attr; 996da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t (*show)(struct mem_ctl_info *,char *); 997da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); 998da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 999da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1000da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj) 1001da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr) 1002da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1003da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, 1004e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson char *buffer) 1005da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1006da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *mem_ctl_info = to_mci(kobj); 1007da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); 1008da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1009da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (mcidev_attr->show) 1010da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return mcidev_attr->show(mem_ctl_info, buffer); 1011e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1012da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -EIO; 1013da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1014da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1015da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, 1016e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson const char *buffer, size_t count) 1017da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1018da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *mem_ctl_info = to_mci(kobj); 1019da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); 1020da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1021da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (mcidev_attr->store) 1022da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return mcidev_attr->store(mem_ctl_info, buffer, count); 1023e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1024da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -EIO; 1025da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1026da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1027da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct sysfs_ops mci_ops = { 1028e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .show = mcidev_show, 1029e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .store = mcidev_store 1030da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 1031da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1032da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define MCIDEV_ATTR(_name,_mode,_show,_store) \ 1033da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct mcidev_attribute mci_attr_##_name = { \ 1034da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .attr = {.name = __stringify(_name), .mode = _mode }, \ 1035da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .show = _show, \ 1036da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox .store = _store, \ 1037da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 1038da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1039da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Control file */ 1040da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store); 1041da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1042da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Attribute files */ 1043da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL); 1044da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(module_name,S_IRUGO,mci_mod_name_show,NULL); 1045da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(edac_capability,S_IRUGO,mci_edac_capability_show,NULL); 1046da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL); 1047da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL); 1048da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL); 1049da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL); 1050da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL); 1051da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); 1052da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(edac_current_capability,S_IRUGO, 1053da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci_edac_current_capability_show,NULL); 1054da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMCIDEV_ATTR(supported_mem_type,S_IRUGO, 1055da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci_supported_mem_type_show,NULL); 1056da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1057da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct mcidev_attribute *mci_attr[] = { 1058da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_reset_counters, 1059da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_module_name, 1060da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_mc_name, 1061da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_edac_capability, 1062da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_edac_current_capability, 1063da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_supported_mem_type, 1064da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_size_mb, 1065da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_seconds_since_reset, 1066da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_ue_noinfo_count, 1067da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_ce_noinfo_count, 1068da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_ue_count, 1069da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox &mci_attr_ce_count, 1070da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox NULL 1071da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 1072da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1073da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 1074da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Release of a MC controlling instance 1075da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1076da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void edac_mci_instance_release(struct kobject *kobj) 1077da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1078da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *mci; 1079da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1080472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson mci = to_mci(kobj); 1081472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson debugf0("%s() idx=%d\n", __func__, mci->mc_idx); 1082472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson complete(&mci->kobj_complete); 1083da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1084da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1085da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic struct kobj_type ktype_mci = { 1086e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .release = edac_mci_instance_release, 1087e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .sysfs_ops = &mci_ops, 1088e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson .default_attrs = (struct attribute **) mci_attr, 1089da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox}; 1090da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1091ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif /* DISABLE_EDAC_SYSFS */ 1092ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson 1093da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#define EDAC_DEVICE_SYMLINK "device" 1094da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1095da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 1096da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Create a new Memory Controller kobject instance, 1097da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * mc<id> under the 'mc' directory 1098da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1099da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Return: 1100da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 0 Success 1101da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * !0 Failure 1102da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1103da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) 1104ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifdef DISABLE_EDAC_SYSFS 1105ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson{ 1106ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson return 0; 1107ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson} 1108ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#else 1109da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1110da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int i; 1111da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int err; 1112da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csrow; 1113da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct kobject *edac_mci_kobj=&mci->edac_mci_kobj; 1114da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1115537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf0("%s() idx=%d\n", __func__, mci->mc_idx); 1116da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj)); 1117da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1118da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* set the name of the mc<id> object */ 1119da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx); 1120e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1121da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (err) 1122da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return err; 1123da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1124da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* link to our parent the '..../edac/mc' object */ 1125da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mci_kobj->parent = &edac_memctrl_kobj; 1126da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mci_kobj->ktype = &ktype_mci; 1127da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1128da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* register the mc<id> kobject */ 1129da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = kobject_register(edac_mci_kobj); 1130e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1131da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (err) 1132da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return err; 1133da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1134da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* create a symlink for the device */ 1135da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = sysfs_create_link(edac_mci_kobj, &mci->pdev->dev.kobj, 1136da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox EDAC_DEVICE_SYMLINK); 1137e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 11386e5a8748507dea83386d1d76c58aeaed1ff5a1ecDave Peterson if (err) 11396e5a8748507dea83386d1d76c58aeaed1ff5a1ecDave Peterson goto fail0; 1140da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1141da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Make directories for each CSROW object 1142da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * under the mc<id> kobject 1143da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1144da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (i = 0; i < mci->nr_csrows; i++) { 1145da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow = &mci->csrows[i]; 1146da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1147da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Only expose populated CSROWs */ 1148da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_pages > 0) { 1149da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox err = edac_create_csrow_object(edac_mci_kobj,csrow,i); 1150e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1151da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (err) 11526e5a8748507dea83386d1d76c58aeaed1ff5a1ecDave Peterson goto fail1; 1153da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1154da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1155da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1156da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 1157da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1158da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* CSROW error: backout what has already been registered, */ 11596e5a8748507dea83386d1d76c58aeaed1ff5a1ecDave Petersonfail1: 1160da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for ( i--; i >= 0; i--) { 1161472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson if (csrow->nr_pages > 0) { 1162472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson init_completion(&csrow->kobj_complete); 1163da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox kobject_unregister(&mci->csrows[i].kobj); 1164472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson wait_for_completion(&csrow->kobj_complete); 1165472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson } 1166da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1167da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 11686e5a8748507dea83386d1d76c58aeaed1ff5a1ecDave Petersonfail0: 1169472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson init_completion(&mci->kobj_complete); 1170da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox kobject_unregister(edac_mci_kobj); 1171472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson wait_for_completion(&mci->kobj_complete); 1172da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return err; 1173da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1174ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif /* DISABLE_EDAC_SYSFS */ 1175da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1176da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 1177da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * remove a Memory Controller instance 1178da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1179da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) 1180da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1181ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#ifndef DISABLE_EDAC_SYSFS 1182da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int i; 1183da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1184537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf0("%s()\n", __func__); 1185da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1186da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* remove all csrow kobjects */ 1187da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (i = 0; i < mci->nr_csrows; i++) { 1188472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson if (mci->csrows[i].nr_pages > 0) { 1189472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson init_completion(&mci->csrows[i].kobj_complete); 1190da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox kobject_unregister(&mci->csrows[i].kobj); 1191472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson wait_for_completion(&mci->csrows[i].kobj_complete); 1192472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson } 1193da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1194da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1195da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); 1196472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson init_completion(&mci->kobj_complete); 1197da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox kobject_unregister(&mci->edac_mci_kobj); 1198472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson wait_for_completion(&mci->kobj_complete); 1199ceb2ca9cb0bfd885127fa9a2c27127b3fe1c8f28Dave Peterson#endif /* DISABLE_EDAC_SYSFS */ 1200da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1201da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1202da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* END OF sysfs data and methods */ 1203da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1204da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#ifdef CONFIG_EDAC_DEBUG 1205da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1206da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_dump_channel(struct channel_info *chan) 1207da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1208da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel = %p\n", chan); 1209da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx); 1210da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel->ce_count = %d\n", chan->ce_count); 1211da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel->label = '%s'\n", chan->label); 1212da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel->csrow = %p\n\n", chan->csrow); 1213da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 12149110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_dump_channel); 1215da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1216da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_dump_csrow(struct csrow_info *csrow) 1217da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1218da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow = %p\n", csrow); 1219da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx); 1220da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->first_page = 0x%lx\n", 1221da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->first_page); 1222da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page); 1223da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask); 1224da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages); 1225da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->nr_channels = %d\n", 1226da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->nr_channels); 1227da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->channels = %p\n", csrow->channels); 1228da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->mci = %p\n\n", csrow->mci); 1229da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 12309110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_dump_csrow); 1231da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1232da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_dump_mci(struct mem_ctl_info *mci) 1233da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1234da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci = %p\n", mci); 1235da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap); 1236da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap); 1237da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci->edac_cap = %lx\n", mci->edac_cap); 1238da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tmci->edac_check = %p\n", mci->edac_check); 1239da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci->nr_csrows = %d, csrows = %p\n", 1240da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->nr_csrows, mci->csrows); 1241da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tpdev = %p\n", mci->pdev); 1242da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmod_name:ctl_name = %s:%s\n", 1243da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->mod_name, mci->ctl_name); 1244da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tpvt_info = %p\n\n", mci->pvt_info); 1245da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 12469110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_dump_mci); 1247da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1248e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson#endif /* CONFIG_EDAC_DEBUG */ 1249da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1250da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'. 1251da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Adjust 'ptr' so that its alignment is at least as stringent as what the 1252da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * compiler would provide for X and return the aligned result. 1253da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1254da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * If 'size' is a constant, the compiler will optimize this whole function 1255da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * down to either a no-op or the addition of a constant to the value of 'ptr'. 1256da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1257e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic inline char * align_ptr(void *ptr, unsigned size) 1258da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1259da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned align, r; 1260da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1261da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Here we assume that the alignment of a "long long" is the most 1262da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * stringent alignment that the compiler will ever provide by default. 1263da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * As far as I know, this is a reasonable assumption. 1264da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1265da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (size > sizeof(long)) 1266da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align = sizeof(long long); 1267da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else if (size > sizeof(int)) 1268da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align = sizeof(long); 1269da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else if (size > sizeof(short)) 1270da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align = sizeof(int); 1271da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else if (size > sizeof(char)) 1272da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align = sizeof(short); 1273da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else 1274da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return (char *) ptr; 1275da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1276da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox r = size % align; 1277da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1278da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (r == 0) 1279da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return (char *) ptr; 1280da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1281da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return (char *) (((unsigned long) ptr) + align - r); 1282da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1283da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1284da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 1285da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * edac_mc_alloc: Allocate a struct mem_ctl_info structure 1286da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @size_pvt: size of private storage needed 1287da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @nr_csrows: Number of CWROWS needed for this MC 1288da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @nr_chans: Number of channels for the MC 1289da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1290da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Everything is kmalloc'ed as one big chunk - more efficient. 1291da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Only can be used if all structures have the same lifetime - otherwise 1292da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * you have to allocate and initialize your own structures. 1293da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1294da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Use edac_mc_free() to free mc structures allocated by this function. 1295da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1296da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Returns: 1297da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * NULL allocation failed 1298da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * struct mem_ctl_info pointer 1299da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1300da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, 1301e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson unsigned nr_chans) 1302da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1303da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *mci; 1304da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csi, *csrow; 1305da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct channel_info *chi, *chp, *chan; 1306da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox void *pvt; 1307da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned size; 1308da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int row, chn; 1309da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1310da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Figure out the offsets of the various items from the start of an mc 1311da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * structure. We want the alignment of each item to be at least as 1312da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * stringent as what the compiler would provide if we could simply 1313da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * hardcode everything into a single struct. 1314da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1315da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci = (struct mem_ctl_info *) 0; 1316da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csi = (struct csrow_info *)align_ptr(&mci[1], sizeof(*csi)); 1317da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chi = (struct channel_info *) 1318da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align_ptr(&csi[nr_csrows], sizeof(*chi)); 1319da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pvt = align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); 1320da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox size = ((unsigned long) pvt) + sz_pvt; 1321da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1322da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if ((mci = kmalloc(size, GFP_KERNEL)) == NULL) 1323da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return NULL; 1324da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1325da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Adjust pointers so they point within the memory we just allocated 1326da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * rather than an imaginary chunk of memory located at address 0. 1327da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1328da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csi = (struct csrow_info *) (((char *) mci) + ((unsigned long) csi)); 1329da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi)); 1330da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL; 1331da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1332e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson memset(mci, 0, size); /* clear all fields */ 1333da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->csrows = csi; 1334da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->pvt_info = pvt; 1335da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->nr_csrows = nr_csrows; 1336da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1337da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (row = 0; row < nr_csrows; row++) { 1338da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow = &csi[row]; 1339da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->csrow_idx = row; 1340da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->mci = mci; 1341da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->nr_channels = nr_chans; 1342da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chp = &chi[row * nr_chans]; 1343da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->channels = chp; 1344da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1345da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (chn = 0; chn < nr_chans; chn++) { 1346da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chan = &chp[chn]; 1347da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chan->chan_idx = chn; 1348da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chan->csrow = csrow; 1349da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1350da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1351da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1352da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return mci; 1353da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 13549110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_alloc); 1355da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1356da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 1357da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * edac_mc_free: Free a previously allocated 'mci' structure 1358da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @mci: pointer to a struct mem_ctl_info structure 1359da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1360da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_free(struct mem_ctl_info *mci) 1361da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1362472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson kfree(mci); 1363da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 13649110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_free); 1365da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 136618dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Petersonstatic struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev) 1367da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1368da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *mci; 1369da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct list_head *item; 1370da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1371537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("%s()\n", __func__); 1372da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1373da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list_for_each(item, &mc_devices) { 1374da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci = list_entry(item, struct mem_ctl_info, link); 1375da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1376da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (mci->pdev == pdev) 1377da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return mci; 1378da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1379da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1380da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return NULL; 1381da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1382da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1383e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic int add_mc_to_global_list(struct mem_ctl_info *mci) 1384da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1385da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct list_head *item, *insert_before; 1386da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *p; 1387da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int i; 1388da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1389da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (list_empty(&mc_devices)) { 1390da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->mc_idx = 0; 1391da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox insert_before = &mc_devices; 1392da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } else { 139318dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson if (find_mci_by_pdev(mci->pdev)) { 1394537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_WARNING, EDAC_MC, 1395537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "%s (%s) %s %s already assigned %d\n", 1396537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson mci->pdev->dev.bus_id, 1397537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson pci_name(mci->pdev), mci->mod_name, 1398537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson mci->ctl_name, mci->mc_idx); 1399da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 1; 1400da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1401da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1402da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox insert_before = NULL; 1403da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox i = 0; 1404da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1405da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list_for_each(item, &mc_devices) { 1406da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox p = list_entry(item, struct mem_ctl_info, link); 1407da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1408da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (p->mc_idx != i) { 1409da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox insert_before = item; 1410da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox break; 1411da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1412da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1413da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox i++; 1414da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1415da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1416da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->mc_idx = i; 1417da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1418da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (insert_before == NULL) 1419da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox insert_before = &mc_devices; 1420da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1421da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1422da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list_add_tail_rcu(&mci->link, insert_before); 1423da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 1424da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1425da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1426e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic void complete_mc_list_del(struct rcu_head *head) 1427a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson{ 1428a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson struct mem_ctl_info *mci; 1429a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson 1430a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson mci = container_of(head, struct mem_ctl_info, rcu); 1431a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson INIT_LIST_HEAD(&mci->link); 1432a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson complete(&mci->complete); 1433a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson} 1434a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson 1435e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic void del_mc_from_global_list(struct mem_ctl_info *mci) 1436a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson{ 1437a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson list_del_rcu(&mci->link); 1438a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson init_completion(&mci->complete); 1439a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson call_rcu(&mci->rcu, complete_mc_list_del); 1440a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson wait_for_completion(&mci->complete); 1441a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson} 1442a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson 1443da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 1444472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and 1445472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * create sysfs entries associated with mci structure 1446da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @mci: pointer to the mci structure to be added to the list 1447da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1448da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Return: 1449da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 0 Success 1450da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * !0 Failure 1451da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1452da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1453da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* FIXME - should a warning be printed if no error detection? correction? */ 1454da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxint edac_mc_add_mc(struct mem_ctl_info *mci) 1455da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1456537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf0("%s()\n", __func__); 1457da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#ifdef CONFIG_EDAC_DEBUG 1458da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_debug_level >= 3) 1459da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_dump_mci(mci); 1460e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1461da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_debug_level >= 4) { 1462da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int i; 1463da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1464da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (i = 0; i < mci->nr_csrows; i++) { 1465da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int j; 1466e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1467da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_dump_csrow(&mci->csrows[i]); 1468da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (j = 0; j < mci->csrows[i].nr_channels; j++) 1469e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson edac_mc_dump_channel( 1470e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson &mci->csrows[i].channels[j]); 1471da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1472da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1473da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#endif 1474da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox down(&mem_ctls_mutex); 1475da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1476da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (add_mc_to_global_list(mci)) 1477028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson goto fail0; 1478da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1479da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* set load time so that error rate can be tracked */ 1480da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->start_time = jiffies; 1481da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1482da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_create_sysfs_mci_device(mci)) { 1483537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_WARNING, 1484537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "failed to create sysfs device\n"); 1485028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson goto fail1; 1486da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1487da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1488da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Report action taken */ 1489537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: PCI %s\n", 1490537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson mci->mod_name, mci->ctl_name, pci_name(mci->pdev)); 1491da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1492028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson up(&mem_ctls_mutex); 1493028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson return 0; 1494da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1495028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Petersonfail1: 1496028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson del_mc_from_global_list(mci); 1497028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson 1498028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Petersonfail0: 1499da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox up(&mem_ctls_mutex); 1500028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson return 1; 1501da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 15029110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_add_mc); 1503da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1504da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 1505472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * edac_mc_del_mc: Remove sysfs entries for specified mci structure and 1506472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * remove mci structure from global list 150718dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson * @pdev: Pointer to 'struct pci_dev' representing mci structure to remove. 1508da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 150918dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson * Return pointer to removed mci structure, or NULL if device not found. 1510da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 151118dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Petersonstruct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev) 1512da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 151318dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson struct mem_ctl_info *mci; 1514da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 151518dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson debugf0("MC: %s()\n", __func__); 1516da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox down(&mem_ctls_mutex); 151718dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson 151818dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson if ((mci = find_mci_by_pdev(pdev)) == NULL) { 151918dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson up(&mem_ctls_mutex); 152018dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson return NULL; 152118dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson } 152218dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson 152318dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson edac_remove_sysfs_mci_device(mci); 1524da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox del_mc_from_global_list(mci); 152518dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson up(&mem_ctls_mutex); 1526537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_INFO, EDAC_MC, 1527537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "Removed device %d for %s %s: PCI %s\n", mci->mc_idx, 1528537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson mci->mod_name, mci->ctl_name, pci_name(mci->pdev)); 152918dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson return mci; 1530da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 15319110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_del_mc); 1532da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1533e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonvoid edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size) 1534da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1535da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct page *pg; 1536da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox void *virt_addr; 1537da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned long flags = 0; 1538da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1539537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("%s()\n", __func__); 1540da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1541da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* ECC error page was not in our memory. Ignore it. */ 1542da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if(!pfn_valid(page)) 1543da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 1544da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1545da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Find the actual page structure then map it and fix */ 1546da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pg = pfn_to_page(page); 1547da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1548da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (PageHighMem(pg)) 1549da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox local_irq_save(flags); 1550da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1551da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox virt_addr = kmap_atomic(pg, KM_BOUNCE_READ); 1552da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1553da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Perform architecture specific atomic scrub operation */ 1554da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox atomic_scrub(virt_addr + offset, size); 1555da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1556da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Unmap and complete */ 1557da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox kunmap_atomic(virt_addr, KM_BOUNCE_READ); 1558da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1559da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (PageHighMem(pg)) 1560da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox local_irq_restore(flags); 1561da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 15629110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_scrub_block); 1563da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1564da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* FIXME - should return -1 */ 1565e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonint edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) 1566da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1567da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csrows = mci->csrows; 1568da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int row, i; 1569da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1570537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page); 1571da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox row = -1; 1572da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1573da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (i = 0; i < mci->nr_csrows; i++) { 1574da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csrow = &csrows[i]; 1575da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1576da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_pages == 0) 1577da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox continue; 1578da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1579537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) " 1580537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "mask(0x%lx)\n", mci->mc_idx, __func__, 1581537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson csrow->first_page, page, csrow->last_page, 1582537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson csrow->page_mask); 1583da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1584da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if ((page >= csrow->first_page) && 1585da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox (page <= csrow->last_page) && 1586da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ((page & csrow->page_mask) == 1587da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox (csrow->first_page & csrow->page_mask))) { 1588da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox row = i; 1589da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox break; 1590da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1591da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1592da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1593da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (row == -1) 1594537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_ERR, 1595537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "could not look up page error address %lx\n", 1596537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson (unsigned long) page); 1597da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1598da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return row; 1599da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 16009110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page); 1601da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1602da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* FIXME - setable log (warning/emerg) levels */ 1603da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */ 1604da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_handle_ce(struct mem_ctl_info *mci, 1605e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson unsigned long page_frame_number, unsigned long offset_in_page, 1606e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson unsigned long syndrome, int row, int channel, const char *msg) 1607da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1608da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned long remapped_page; 1609da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1610537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("MC%d: %s()\n", mci->mc_idx, __func__); 1611da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1612da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* FIXME - maybe make panic on INTERNAL ERROR an option */ 1613da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (row >= mci->nr_csrows || row < 0) { 1614da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* something is wrong */ 1615537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_ERR, 1616537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "INTERNAL ERROR: row out of range " 1617537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "(%d >= %d)\n", row, mci->nr_csrows); 1618da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); 1619da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 1620da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1621e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1622da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (channel >= mci->csrows[row].nr_channels || channel < 0) { 1623da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* something is wrong */ 1624537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_ERR, 1625537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "INTERNAL ERROR: channel out of range " 1626537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "(%d >= %d)\n", channel, 1627537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson mci->csrows[row].nr_channels); 1628da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); 1629da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 1630da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1631da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1632da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (log_ce) 1633da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* FIXME - put in DIMM location */ 1634537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_WARNING, 1635537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "CE page 0x%lx, offset 0x%lx, grain %d, syndrome " 1636537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "0x%lx, row %d, channel %d, label \"%s\": %s\n", 1637537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson page_frame_number, offset_in_page, 1638537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson mci->csrows[row].grain, syndrome, row, channel, 1639537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson mci->csrows[row].channels[channel].label, msg); 1640da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1641da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ce_count++; 1642da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->csrows[row].ce_count++; 1643da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->csrows[row].channels[channel].ce_count++; 1644da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1645da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (mci->scrub_mode & SCRUB_SW_SRC) { 1646da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* 1647da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Some MC's can remap memory so that it is still available 1648da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * at a different address when PCI devices map into memory. 1649da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * MC's that can't do this lose the memory where PCI devices 1650da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * are mapped. This mapping is MC dependant and so we call 1651da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * back into the MC driver for it to map the MC page to 1652da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * a physical (CPU) page which can then be mapped to a virtual 1653da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * page - which can then be scrubbed. 1654da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1655da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox remapped_page = mci->ctl_page_to_phys ? 1656da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ctl_page_to_phys(mci, page_frame_number) : 1657da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox page_frame_number; 1658da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1659da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_scrub_block(remapped_page, offset_in_page, 1660e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson mci->csrows[row].grain); 1661da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1662da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 16639110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_handle_ce); 1664da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1665e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonvoid edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) 1666da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1667da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (log_ce) 1668537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_WARNING, 1669537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "CE - no information available: %s\n", msg); 1670e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1671da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ce_noinfo_count++; 1672da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ce_count++; 1673da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 16749110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info); 1675da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1676da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_handle_ue(struct mem_ctl_info *mci, 1677e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson unsigned long page_frame_number, unsigned long offset_in_page, 1678e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson int row, const char *msg) 1679da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1680da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int len = EDAC_MC_LABEL_LEN * 4; 1681da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char labels[len + 1]; 1682da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *pos = labels; 1683da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int chan; 1684da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int chars; 1685da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1686537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("MC%d: %s()\n", mci->mc_idx, __func__); 1687da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1688da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* FIXME - maybe make panic on INTERNAL ERROR an option */ 1689da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (row >= mci->nr_csrows || row < 0) { 1690da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* something is wrong */ 1691537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_ERR, 1692537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "INTERNAL ERROR: row out of range " 1693537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "(%d >= %d)\n", row, mci->nr_csrows); 1694da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); 1695da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 1696da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1697da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1698da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chars = snprintf(pos, len + 1, "%s", 1699e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson mci->csrows[row].channels[0].label); 1700da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox len -= chars; 1701da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pos += chars; 1702e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1703da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0); 1704da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chan++) { 1705da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chars = snprintf(pos, len + 1, ":%s", 1706e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson mci->csrows[row].channels[chan].label); 1707da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox len -= chars; 1708da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pos += chars; 1709da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1710da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1711da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (log_ue) 1712537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_EMERG, 1713537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "UE page 0x%lx, offset 0x%lx, grain %d, row %d, " 1714537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "labels \"%s\": %s\n", page_frame_number, 1715537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson offset_in_page, mci->csrows[row].grain, row, labels, 1716537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson msg); 1717da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1718da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (panic_on_ue) 1719e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, " 1720e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson "row %d, labels \"%s\": %s\n", mci->mc_idx, 1721e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson page_frame_number, offset_in_page, 1722e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson mci->csrows[row].grain, row, labels, msg); 1723da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1724da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ue_count++; 1725da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->csrows[row].ue_count++; 1726da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 17279110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_handle_ue); 1728da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1729e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonvoid edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) 1730da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1731da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (panic_on_ue) 1732da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox panic("EDAC MC%d: Uncorrected Error", mci->mc_idx); 1733da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1734da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (log_ue) 1735537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_WARNING, 1736537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "UE - no information available: %s\n", msg); 1737da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ue_noinfo_count++; 1738da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ue_count++; 1739da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 17409110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); 1741da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1742da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#ifdef CONFIG_PCI 1743da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1744da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic u16 get_pci_parity_status(struct pci_dev *dev, int secondary) 1745da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1746da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int where; 1747da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox u16 status; 1748da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1749da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox where = secondary ? PCI_SEC_STATUS : PCI_STATUS; 1750da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pci_read_config_word(dev, where, &status); 1751da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1752e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson /* If we get back 0xFFFF then we must suspect that the card has been 1753e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson * pulled but the Linux PCI layer has not yet finished cleaning up. 1754e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson * We don't want to report on such devices 1755e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson */ 1756da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1757da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status == 0xFFFF) { 1758da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox u32 sanity; 1759e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1760da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pci_read_config_dword(dev, 0, &sanity); 1761e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1762da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (sanity == 0xFFFFFFFF) 1763da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 1764da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1765e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1766da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | 1767e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson PCI_STATUS_PARITY; 1768da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1769da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status) 1770da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* reset only the bits we are interested in */ 1771da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pci_write_config_word(dev, where, status); 1772da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1773da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return status; 1774da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1775da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1776da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxtypedef void (*pci_parity_check_fn_t) (struct pci_dev *dev); 1777da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1778da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* Clear any PCI parity errors logged by this device. */ 1779e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic void edac_pci_dev_parity_clear(struct pci_dev *dev) 1780da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1781da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox u8 header_type; 1782da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1783da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox get_pci_parity_status(dev, 0); 1784da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1785da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* read the device TYPE, looking for bridges */ 1786da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); 1787da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1788da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) 1789da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox get_pci_parity_status(dev, 1); 1790da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1791da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1792da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 1793da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * PCI Parity polling 1794da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1795da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1796da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void edac_pci_dev_parity_test(struct pci_dev *dev) 1797da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1798da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox u16 status; 1799da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox u8 header_type; 1800da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1801da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* read the STATUS register on this device 1802da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1803da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox status = get_pci_parity_status(dev, 0); 1804da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1805da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id ); 1806da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1807da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* check the status reg for errors */ 1808da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status) { 1809da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) 1810537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_CRIT, EDAC_PCI, 1811da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox "Signaled System Error on %s\n", 1812537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson pci_name(dev)); 1813da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1814da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status & (PCI_STATUS_PARITY)) { 1815537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_CRIT, EDAC_PCI, 1816da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox "Master Data Parity Error on %s\n", 1817537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson pci_name(dev)); 1818da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1819da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox atomic_inc(&pci_parity_count); 1820da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1821da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1822da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status & (PCI_STATUS_DETECTED_PARITY)) { 1823537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_CRIT, EDAC_PCI, 1824da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox "Detected Parity Error on %s\n", 1825537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson pci_name(dev)); 1826da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1827da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox atomic_inc(&pci_parity_count); 1828da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1829da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1830da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1831da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* read the device TYPE, looking for bridges */ 1832da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); 1833da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1834da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id ); 1835da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1836da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { 1837da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* On bridges, need to examine secondary status register */ 1838da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox status = get_pci_parity_status(dev, 1); 1839da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1840da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf2("PCI SEC_STATUS= 0x%04x %s\n", 1841da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox status, dev->dev.bus_id ); 1842da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1843da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* check the secondary status reg for errors */ 1844da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status) { 1845da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) 1846537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " 1847da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox "Signaled System Error on %s\n", 1848537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson pci_name(dev)); 1849da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1850da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status & (PCI_STATUS_PARITY)) { 1851537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " 1852537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "Master Data Parity Error on " 1853537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "%s\n", pci_name(dev)); 1854da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1855da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox atomic_inc(&pci_parity_count); 1856da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1857da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1858da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (status & (PCI_STATUS_DETECTED_PARITY)) { 1859537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " 1860da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox "Detected Parity Error on %s\n", 1861537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson pci_name(dev)); 1862da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1863da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox atomic_inc(&pci_parity_count); 1864da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1865da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1866da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1867da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1868da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1869da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 1870da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * check_dev_on_list: Scan for a PCI device on a white/black list 1871da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @list: an EDAC &edac_pci_device_list white/black list pointer 1872da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @free_index: index of next free entry on the list 1873da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @pci_dev: PCI Device pointer 1874da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1875da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * see if list contains the device. 1876da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1877da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Returns: 0 not found 1878da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 1 found on list 1879da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1880e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic int check_dev_on_list(struct edac_pci_device_list *list, 1881e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson int free_index, struct pci_dev *dev) 1882e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson{ 1883e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson int i; 1884e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson int rc = 0; /* Assume not found */ 1885e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson unsigned short vendor=dev->vendor; 1886e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson unsigned short device=dev->device; 1887e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 1888e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson /* Scan the list, looking for a vendor/device match */ 1889e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson for (i = 0; i < free_index; i++, list++ ) { 1890e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson if ((list->vendor == vendor ) && (list->device == device )) { 1891e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson rc = 1; 1892e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson break; 1893e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson } 1894e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson } 1895da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1896e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson return rc; 1897da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1898da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1899da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 1900da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * pci_dev parity list iterator 1901e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson * Scan the PCI device list for one iteration, looking for SERRORs 1902da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Master Parity ERRORS or Parity ERRORs on primary or secondary devices 1903da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1904da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) 1905da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1906e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson struct pci_dev *dev = NULL; 1907da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1908da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* request for kernel access to the next PCI device, if any, 1909da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * and while we are looking at it have its reference count 1910da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * bumped until we are done with it 1911da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1912da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { 1913e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson /* if whitelist exists then it has priority, so only scan 1914e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson * those devices on the whitelist 1915e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson */ 1916e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson if (pci_whitelist_count > 0 ) { 1917e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson if (check_dev_on_list(pci_whitelist, 1918da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pci_whitelist_count, dev)) 1919da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox fn(dev); 1920e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson } else { 1921da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* 1922da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * if no whitelist, then check if this devices is 1923da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * blacklisted 1924da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1925e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson if (!check_dev_on_list(pci_blacklist, 1926da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pci_blacklist_count, dev)) 1927da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox fn(dev); 1928e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson } 1929da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1930da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1931da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1932da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void do_pci_parity_check(void) 1933da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1934da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned long flags; 1935da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int before_count; 1936da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1937537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("%s()\n", __func__); 1938da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1939da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (!check_pci_parity) 1940da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 1941da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1942da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox before_count = atomic_read(&pci_parity_count); 1943da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1944da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* scan all PCI devices looking for a Parity Error on devices and 1945da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * bridges 1946da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1947da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox local_irq_save(flags); 1948da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_dev_parity_iterator(edac_pci_dev_parity_test); 1949da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox local_irq_restore(flags); 1950da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1951da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Only if operator has selected panic on PCI Error */ 1952da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (panic_on_pci_parity) { 1953da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* If the count is different 'after' from 'before' */ 1954da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (before_count != atomic_read(&pci_parity_count)) 1955da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox panic("EDAC: PCI Parity Error"); 1956da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1957da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1958da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1959da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic inline void clear_pci_parity_errors(void) 1960da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1961da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Clear any PCI bus parity errors that devices initially have logged 1962da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * in their registers. 1963da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1964da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); 1965da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1966da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1967da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#else /* CONFIG_PCI */ 1968da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1969da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic inline void do_pci_parity_check(void) 1970da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1971da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* no-op */ 1972da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1973da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1974da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic inline void clear_pci_parity_errors(void) 1975da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1976da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* no-op */ 1977da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 1978da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1979da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#endif /* CONFIG_PCI */ 1980da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1981da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 1982da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Iterate over all MC instances and check for ECC, et al, errors 1983da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1984e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic inline void check_mc_devices(void) 1985da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 1986da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct list_head *item; 1987da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *mci; 1988da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1989537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("%s()\n", __func__); 199018dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson down(&mem_ctls_mutex); 1991da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1992da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list_for_each(item, &mc_devices) { 1993da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci = list_entry(item, struct mem_ctl_info, link); 1994da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1995da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (mci->edac_check != NULL) 1996da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->edac_check(mci); 1997da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 1998da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 199918dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson up(&mem_ctls_mutex); 2000da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 2001da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2002da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 2003da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Check MC status every poll_msec. 2004da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Check PCI status every poll_msec as well. 2005da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 2006da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * This where the work gets done for edac. 2007da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 2008da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * SMP safe, doesn't use NMI, and auto-rate-limits. 2009da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 2010da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void do_edac_check(void) 2011da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 2012537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("%s()\n", __func__); 2013da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox check_mc_devices(); 2014da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox do_pci_parity_check(); 2015da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 2016da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2017da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int edac_kernel_thread(void *arg) 2018da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 2019f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson while (!kthread_should_stop()) { 2020f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson do_edac_check(); 2021da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2022da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* goto sleep for the interval */ 2023f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson schedule_timeout_interruptible((HZ * poll_msec) / 1000); 2024da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox try_to_freeze(); 2025da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 2026da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2027da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 2028da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 2029da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2030da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 2031da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * edac_mc_init 2032da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * module initialization entry point 2033da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 2034da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int __init edac_mc_init(void) 2035da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 2036537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n"); 2037da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2038da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* 2039da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Harvest and clear any boot/initialization PCI parity errors 2040da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 2041da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * FIXME: This only clears errors logged by devices present at time of 2042da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * module initialization. We should also do an initial clear 2043da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * of each newly hotplugged device. 2044da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 2045da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox clear_pci_parity_errors(); 2046da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2047da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Create the MC sysfs entires */ 2048da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_sysfs_memctrl_setup()) { 2049537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_ERR, EDAC_MC, 2050537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "Error initializing sysfs code\n"); 2051da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -ENODEV; 2052da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 2053da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2054da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Create the PCI parity sysfs entries */ 2055da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_sysfs_pci_setup()) { 2056da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_sysfs_memctrl_teardown(); 2057537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_ERR, EDAC_MC, 2058537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "EDAC PCI: Error initializing sysfs code\n"); 2059da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return -ENODEV; 2060da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 2061da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2062da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* create our kernel thread */ 2063f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac"); 2064e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 2065f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson if (IS_ERR(edac_thread)) { 2066da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* remove the sysfs entries */ 2067da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_sysfs_memctrl_teardown(); 2068da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_sysfs_pci_teardown(); 2069f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson return PTR_ERR(edac_thread); 2070da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 2071da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2072da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 2073da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 2074da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2075da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 2076da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * edac_mc_exit() 2077da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * module exit/termination functioni 2078da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 2079da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic void __exit edac_mc_exit(void) 2080da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 2081537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf0("%s()\n", __func__); 2082f2fe42abbf0d99a8c4b96f1cc55db10ac35d2fb9Dave Peterson kthread_stop(edac_thread); 2083da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2084da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* tear down the sysfs device */ 2085da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_sysfs_memctrl_teardown(); 2086da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_sysfs_pci_teardown(); 2087da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 2088da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2089da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_init(edac_mc_init); 2090da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_exit(edac_mc_exit); 2091da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2092da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_LICENSE("GPL"); 2093da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" 2094e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson "Based on work by Dan Hollis et al"); 2095da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_DESCRIPTION("Core library routines for MC reporting"); 2096da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 2097da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_param(panic_on_ue, int, 0644); 2098da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on"); 2099da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_param(check_pci_parity, int, 0644); 2100da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on"); 2101da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_param(panic_on_pci_parity, int, 0644); 2102da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on"); 2103da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_param(log_ue, int, 0644); 2104da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on"); 2105da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_param(log_ce, int, 0644); 2106da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on"); 2107da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_param(poll_msec, int, 0644); 2108da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_PARM_DESC(poll_msec, "Polling period in milliseconds"); 2109da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#ifdef CONFIG_EDAC_DEBUG 2110da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxmodule_param(edac_debug_level, int, 0644); 2111da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan CoxMODULE_PARM_DESC(edac_debug_level, "Debug level"); 2112da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#endif 2113