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