edac_mc.c revision 24f9a7fe3f19f3fd310f556364d01a22911724b3
1da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 2da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * edac_mc kernel module 349c0dab7e6000888b616bedcbbc8cd4710331610Doug Thompson * (C) 2005, 2006 Linux Networx (http://lnxi.com) 4da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * This file may be distributed under the terms of the 5da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * GNU General Public License. 6da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 7da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Written by Thayne Harbaugh 8da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Based on work by Dan Hollis <goemon at anime dot net> and others. 9da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * http://www.anime.net/~goemon/linux-ecc/ 10da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 11da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Modified by Dave Peterson and Doug Thompson 12da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 13da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 14da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 15da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/module.h> 16da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/proc_fs.h> 17da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/kernel.h> 18da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/types.h> 19da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/smp.h> 20da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/init.h> 21da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/sysctl.h> 22da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/highmem.h> 23da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/timer.h> 24da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/slab.h> 25da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/jiffies.h> 26da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/spinlock.h> 27da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/list.h> 28da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/sysdev.h> 29da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <linux/ctype.h> 30c0d121720220584bba2876b032e58a076b843fa1Dave Jiang#include <linux/edac.h> 31da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <asm/uaccess.h> 32da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <asm/page.h> 33da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#include <asm/edac.h> 3420bcb7a81dee21bfa3408f03f46b2891c9b5c84bDouglas Thompson#include "edac_core.h" 357c9281d76c1c0b130f79d5fc021084e9749959d4Douglas Thompson#include "edac_module.h" 36da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 37da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* lock to memory controller's control array */ 3863b7df9101895d1f0a259c567b3bab949a23075fMatthias Kaehlckestatic DEFINE_MUTEX(mem_ctls_mutex); 39ff6ac2a616c85d1215899ffda815e29b699cbd3aRobert P. J. Daystatic LIST_HEAD(mc_devices); 40da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 41da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#ifdef CONFIG_EDAC_DEBUG 42da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 432da1c119fd999cb834b4fe0c1a5a8c36195df1cbAdrian Bunkstatic void edac_mc_dump_channel(struct channel_info *chan) 44da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 45da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel = %p\n", chan); 46da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx); 47da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel->ce_count = %d\n", chan->ce_count); 48da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel->label = '%s'\n", chan->label); 49da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tchannel->csrow = %p\n\n", chan->csrow); 50da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 51da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 522da1c119fd999cb834b4fe0c1a5a8c36195df1cbAdrian Bunkstatic void edac_mc_dump_csrow(struct csrow_info *csrow) 53da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 54da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow = %p\n", csrow); 55da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx); 56079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page); 57da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page); 58da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask); 59da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages); 60079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels); 61da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->channels = %p\n", csrow->channels); 62da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tcsrow->mci = %p\n\n", csrow->mci); 63da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 64da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 652da1c119fd999cb834b4fe0c1a5a8c36195df1cbAdrian Bunkstatic void edac_mc_dump_mci(struct mem_ctl_info *mci) 66da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 67da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci = %p\n", mci); 68da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap); 69da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap); 70da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci->edac_cap = %lx\n", mci->edac_cap); 71da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf4("\tmci->edac_check = %p\n", mci->edac_check); 72da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tmci->nr_csrows = %d, csrows = %p\n", 73da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->nr_csrows, mci->csrows); 7437f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson debugf3("\tdev = %p\n", mci->dev); 75079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name); 76da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox debugf3("\tpvt_info = %p\n\n", mci->pvt_info); 77da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 78da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 7924f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov#endif /* CONFIG_EDAC_DEBUG */ 8024f9a7fe3f19f3fd310f556364d01a22911724b3Borislav Petkov 81239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov/* 82239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov * keep those in sync with the enum mem_type 83239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov */ 84239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkovconst char *edac_mem_types[] = { 85239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Empty csrow", 86239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Reserved csrow type", 87239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Unknown csrow type", 88239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Fast page mode RAM", 89239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Extended data out RAM", 90239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Burst Extended data out RAM", 91239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Single data rate SDRAM", 92239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Registered single data rate SDRAM", 93239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Double data rate SDRAM", 94239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Registered Double data rate SDRAM", 95239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Rambus DRAM", 96239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Unbuffered DDR2 RAM", 97239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Fully buffered DDR2", 98239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Registered DDR2 RAM", 99239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Rambus XDR", 100239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Unbuffered DDR3 RAM", 101239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov "Registered DDR3 RAM", 102239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov}; 103239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav PetkovEXPORT_SYMBOL_GPL(edac_mem_types); 104239642fe19adc19ba0a69e96f3b1904dfd6a3b9fBorislav Petkov 105da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'. 106da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Adjust 'ptr' so that its alignment is at least as stringent as what the 107da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * compiler would provide for X and return the aligned result. 108da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 109da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * If 'size' is a constant, the compiler will optimize this whole function 110da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * down to either a no-op or the addition of a constant to the value of 'ptr'. 111da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 1127391c6dcab3094610cb99bbd559beaa282582eacDouglas Thompsonvoid *edac_align_ptr(void *ptr, unsigned size) 113da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 114da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned align, r; 115da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 116da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Here we assume that the alignment of a "long long" is the most 117da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * stringent alignment that the compiler will ever provide by default. 118da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * As far as I know, this is a reasonable assumption. 119da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 120da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (size > sizeof(long)) 121da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align = sizeof(long long); 122da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else if (size > sizeof(int)) 123da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align = sizeof(long); 124da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else if (size > sizeof(short)) 125da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align = sizeof(int); 126da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else if (size > sizeof(char)) 127da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox align = sizeof(short); 128da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox else 129079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson return (char *)ptr; 130da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 131da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox r = size % align; 132da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 133da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (r == 0) 134079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson return (char *)ptr; 135da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1367391c6dcab3094610cb99bbd559beaa282582eacDouglas Thompson return (void *)(((unsigned long)ptr) + align - r); 137da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 138da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 139da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 140da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * edac_mc_alloc: Allocate a struct mem_ctl_info structure 141da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @size_pvt: size of private storage needed 142da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @nr_csrows: Number of CWROWS needed for this MC 143da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @nr_chans: Number of channels for the MC 144da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 145da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Everything is kmalloc'ed as one big chunk - more efficient. 146da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Only can be used if all structures have the same lifetime - otherwise 147da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * you have to allocate and initialize your own structures. 148da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 149da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Use edac_mc_free() to free mc structures allocated by this function. 150da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 151da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Returns: 152da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * NULL allocation failed 153da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * struct mem_ctl_info pointer 154da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 155da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstruct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, 156b8f6f9755248026f21282e25cac49a1af698056cDoug Thompson unsigned nr_chans, int edac_index) 157da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 158da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *mci; 159da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csi, *csrow; 160da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct channel_info *chi, *chp, *chan; 161da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox void *pvt; 162da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned size; 163da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int row, chn; 1648096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson int err; 165da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 166da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Figure out the offsets of the various items from the start of an mc 167da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * structure. We want the alignment of each item to be at least as 168da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * stringent as what the compiler would provide if we could simply 169da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * hardcode everything into a single struct. 170da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 171079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson mci = (struct mem_ctl_info *)0; 1727391c6dcab3094610cb99bbd559beaa282582eacDouglas Thompson csi = edac_align_ptr(&mci[1], sizeof(*csi)); 1737391c6dcab3094610cb99bbd559beaa282582eacDouglas Thompson chi = edac_align_ptr(&csi[nr_csrows], sizeof(*chi)); 174e27e3dac651771fe3250f6305dee277bce29fc5dDouglas Thompson pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); 175079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson size = ((unsigned long)pvt) + sz_pvt; 176da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 1778096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson mci = kzalloc(size, GFP_KERNEL); 1788096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson if (mci == NULL) 179da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return NULL; 180da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 181da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Adjust pointers so they point within the memory we just allocated 182da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * rather than an imaginary chunk of memory located at address 0. 183da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 184079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi)); 185079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi)); 186079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL; 187da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 188b8f6f9755248026f21282e25cac49a1af698056cDoug Thompson /* setup index and various internal pointers */ 189b8f6f9755248026f21282e25cac49a1af698056cDoug Thompson mci->mc_idx = edac_index; 190da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->csrows = csi; 191da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->pvt_info = pvt; 192da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->nr_csrows = nr_csrows; 193da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 194da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (row = 0; row < nr_csrows; row++) { 195da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow = &csi[row]; 196da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->csrow_idx = row; 197da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->mci = mci; 198da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->nr_channels = nr_chans; 199da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chp = &chi[row * nr_chans]; 200da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox csrow->channels = chp; 201da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 202da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (chn = 0; chn < nr_chans; chn++) { 203da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chan = &chp[chn]; 204da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chan->chan_idx = chn; 205da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chan->csrow = csrow; 206da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 207da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 208da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 20981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang mci->op_state = OP_ALLOC; 2106fe1108f14f4f9581af97cab752f37dc8fa9fdecMauro Carvalho Chehab INIT_LIST_HEAD(&mci->grp_kobj_list); 21181d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 2128096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson /* 2138096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson * Initialize the 'root' kobj for the edac_mc controller 2148096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson */ 2158096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson err = edac_mc_register_sysfs_main_kobj(mci); 2168096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson if (err) { 2178096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson kfree(mci); 2188096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson return NULL; 2198096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson } 2208096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson 2218096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson /* at this point, the root kobj is valid, and in order to 2228096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson * 'free' the object, then the function: 2238096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson * edac_mc_unregister_sysfs_main_kobj() must be called 2248096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson * which will perform kobj unregistration and the actual free 2258096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson * will occur during the kobject callback operation 2268096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson */ 227da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return mci; 228da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 2299110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_alloc); 230da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 231da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 2328096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson * edac_mc_free 2338096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson * 'Free' a previously allocated 'mci' structure 234da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @mci: pointer to a struct mem_ctl_info structure 235da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 236da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_free(struct mem_ctl_info *mci) 237da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 238bbc560ae677c0f4d7ff8404a21409c99f35b297bMauro Carvalho Chehab debugf1("%s()\n", __func__); 239bbc560ae677c0f4d7ff8404a21409c99f35b297bMauro Carvalho Chehab 2408096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6Doug Thompson edac_mc_unregister_sysfs_main_kobj(mci); 241accf74fff36315a31dc7319dae2927af06e9296fMauro Carvalho Chehab 242accf74fff36315a31dc7319dae2927af06e9296fMauro Carvalho Chehab /* free the mci instance memory here */ 243accf74fff36315a31dc7319dae2927af06e9296fMauro Carvalho Chehab kfree(mci); 244da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 2459110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_free); 246da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 247bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 248939747bd680eb09bb98792b17a5bfd2f525afe9dMauro Carvalho Chehab/** 249bce19683c17485b584b62b984d6dcf5332181588Doug Thompson * find_mci_by_dev 250bce19683c17485b584b62b984d6dcf5332181588Doug Thompson * 251bce19683c17485b584b62b984d6dcf5332181588Doug Thompson * scan list of controllers looking for the one that manages 252bce19683c17485b584b62b984d6dcf5332181588Doug Thompson * the 'dev' device 253939747bd680eb09bb98792b17a5bfd2f525afe9dMauro Carvalho Chehab * @dev: pointer to a struct device related with the MCI 254bce19683c17485b584b62b984d6dcf5332181588Doug Thompson */ 255939747bd680eb09bb98792b17a5bfd2f525afe9dMauro Carvalho Chehabstruct mem_ctl_info *find_mci_by_dev(struct device *dev) 256da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 257da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *mci; 258da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct list_head *item; 259da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 260537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("%s()\n", __func__); 261da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 262da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list_for_each(item, &mc_devices) { 263da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci = list_entry(item, struct mem_ctl_info, link); 264da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 26537f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson if (mci->dev == dev) 266da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return mci; 267da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 268da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 269da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return NULL; 270da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 271939747bd680eb09bb98792b17a5bfd2f525afe9dMauro Carvalho ChehabEXPORT_SYMBOL_GPL(find_mci_by_dev); 272da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 27381d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang/* 27481d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang * handler for EDAC to check if NMI type handler has asserted interrupt 27581d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang */ 27681d87cb13e367bb804bf44889ae0de7369705d6cDave Jiangstatic int edac_mc_assert_error_check_and_clear(void) 27781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang{ 27866ee2f940ac8ab25f0c43a1e717d25dc46bfe74dDave Jiang int old_state; 27981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 280079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson if (edac_op_state == EDAC_OPSTATE_POLL) 28181d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang return 1; 28281d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 28366ee2f940ac8ab25f0c43a1e717d25dc46bfe74dDave Jiang old_state = edac_err_assert; 28466ee2f940ac8ab25f0c43a1e717d25dc46bfe74dDave Jiang edac_err_assert = 0; 28581d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 28666ee2f940ac8ab25f0c43a1e717d25dc46bfe74dDave Jiang return old_state; 28781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang} 28881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 28981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang/* 29081d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang * edac_mc_workq_function 29181d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang * performs the operation scheduled by a workq request 29281d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang */ 29381d87cb13e367bb804bf44889ae0de7369705d6cDave Jiangstatic void edac_mc_workq_function(struct work_struct *work_req) 29481d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang{ 295fbeb4384748abb78531bbe1e80d627412a0abcfaJean Delvare struct delayed_work *d_work = to_delayed_work(work_req); 29681d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work); 29781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 29881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang mutex_lock(&mem_ctls_mutex); 29981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 300bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson /* if this control struct has movd to offline state, we are done */ 301bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson if (mci->op_state == OP_OFFLINE) { 302bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson mutex_unlock(&mem_ctls_mutex); 303bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson return; 304bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson } 305bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson 30681d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang /* Only poll controllers that are running polled and have a check */ 30781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL)) 30881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang mci->edac_check(mci); 30981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 31081d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang mutex_unlock(&mem_ctls_mutex); 31181d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 31281d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang /* Reschedule */ 3134de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang queue_delayed_work(edac_workqueue, &mci->work, 314052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson msecs_to_jiffies(edac_mc_get_poll_msec())); 31581d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang} 31681d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 31781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang/* 31881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang * edac_mc_workq_setup 31981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang * initialize a workq item for this mci 32081d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang * passing in the new delay period in msec 321bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * 322bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * locking model: 323bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * 324bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * called with the mem_ctls_mutex held 32581d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang */ 326bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompsonstatic void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) 32781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang{ 32881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang debugf0("%s()\n", __func__); 32981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 330bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson /* if this instance is not in the POLL state, then simply return */ 331bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson if (mci->op_state != OP_RUNNING_POLL) 332bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson return; 333bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson 33481d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); 33581d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); 33681d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang} 33781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 33881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang/* 33981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang * edac_mc_workq_teardown 34081d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang * stop the workq processing on this mci 341bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * 342bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * locking model: 343bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * 344bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * called WITHOUT lock held 34581d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang */ 346bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompsonstatic void edac_mc_workq_teardown(struct mem_ctl_info *mci) 34781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang{ 34881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang int status; 34981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 35000740c58541b6087d78418cebca1fcb86dc6077dBorislav Petkov if (mci->op_state != OP_RUNNING_POLL) 35100740c58541b6087d78418cebca1fcb86dc6077dBorislav Petkov return; 35200740c58541b6087d78418cebca1fcb86dc6077dBorislav Petkov 353bce19683c17485b584b62b984d6dcf5332181588Doug Thompson status = cancel_delayed_work(&mci->work); 354bce19683c17485b584b62b984d6dcf5332181588Doug Thompson if (status == 0) { 355bce19683c17485b584b62b984d6dcf5332181588Doug Thompson debugf0("%s() not canceled, flush the queue\n", 356bce19683c17485b584b62b984d6dcf5332181588Doug Thompson __func__); 357bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson 358bce19683c17485b584b62b984d6dcf5332181588Doug Thompson /* workq instance might be running, wait for it */ 359bce19683c17485b584b62b984d6dcf5332181588Doug Thompson flush_workqueue(edac_workqueue); 36081d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang } 36181d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang} 36281d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 36381d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang/* 364bce19683c17485b584b62b984d6dcf5332181588Doug Thompson * edac_mc_reset_delay_period(unsigned long value) 365bce19683c17485b584b62b984d6dcf5332181588Doug Thompson * 366bce19683c17485b584b62b984d6dcf5332181588Doug Thompson * user space has updated our poll period value, need to 367bce19683c17485b584b62b984d6dcf5332181588Doug Thompson * reset our workq delays 36881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang */ 369bce19683c17485b584b62b984d6dcf5332181588Doug Thompsonvoid edac_mc_reset_delay_period(int value) 37081d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang{ 371bce19683c17485b584b62b984d6dcf5332181588Doug Thompson struct mem_ctl_info *mci; 372bce19683c17485b584b62b984d6dcf5332181588Doug Thompson struct list_head *item; 373bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 374bce19683c17485b584b62b984d6dcf5332181588Doug Thompson mutex_lock(&mem_ctls_mutex); 375bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 376bce19683c17485b584b62b984d6dcf5332181588Doug Thompson /* scan the list and turn off all workq timers, doing so under lock 377bce19683c17485b584b62b984d6dcf5332181588Doug Thompson */ 378bce19683c17485b584b62b984d6dcf5332181588Doug Thompson list_for_each(item, &mc_devices) { 379bce19683c17485b584b62b984d6dcf5332181588Doug Thompson mci = list_entry(item, struct mem_ctl_info, link); 380bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 381bce19683c17485b584b62b984d6dcf5332181588Doug Thompson if (mci->op_state == OP_RUNNING_POLL) 382bce19683c17485b584b62b984d6dcf5332181588Doug Thompson cancel_delayed_work(&mci->work); 383bce19683c17485b584b62b984d6dcf5332181588Doug Thompson } 384bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 385bce19683c17485b584b62b984d6dcf5332181588Doug Thompson mutex_unlock(&mem_ctls_mutex); 38681d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 387bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 388bce19683c17485b584b62b984d6dcf5332181588Doug Thompson /* re-walk the list, and reset the poll delay */ 389bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson mutex_lock(&mem_ctls_mutex); 390bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson 391bce19683c17485b584b62b984d6dcf5332181588Doug Thompson list_for_each(item, &mc_devices) { 392bce19683c17485b584b62b984d6dcf5332181588Doug Thompson mci = list_entry(item, struct mem_ctl_info, link); 393bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 394bce19683c17485b584b62b984d6dcf5332181588Doug Thompson edac_mc_workq_setup(mci, (unsigned long) value); 395bce19683c17485b584b62b984d6dcf5332181588Doug Thompson } 39681d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 39781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang mutex_unlock(&mem_ctls_mutex); 39881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang} 39981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 400bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 401bce19683c17485b584b62b984d6dcf5332181588Doug Thompson 4022d7bbb91c8df26c60d223205a087507430024177Doug Thompson/* Return 0 on success, 1 on failure. 4032d7bbb91c8df26c60d223205a087507430024177Doug Thompson * Before calling this function, caller must 4042d7bbb91c8df26c60d223205a087507430024177Doug Thompson * assign a unique value to mci->mc_idx. 405bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * 406bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * locking model: 407bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * 408bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson * called with the mem_ctls_mutex lock held 4092d7bbb91c8df26c60d223205a087507430024177Doug Thompson */ 410079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompsonstatic int add_mc_to_global_list(struct mem_ctl_info *mci) 411da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 412da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct list_head *item, *insert_before; 413da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct mem_ctl_info *p; 414da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 4152d7bbb91c8df26c60d223205a087507430024177Doug Thompson insert_before = &mc_devices; 416da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 417bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson p = find_mci_by_dev(mci->dev); 418bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson if (unlikely(p != NULL)) 4192d7bbb91c8df26c60d223205a087507430024177Doug Thompson goto fail0; 420da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 4212d7bbb91c8df26c60d223205a087507430024177Doug Thompson list_for_each(item, &mc_devices) { 4222d7bbb91c8df26c60d223205a087507430024177Doug Thompson p = list_entry(item, struct mem_ctl_info, link); 423da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 4242d7bbb91c8df26c60d223205a087507430024177Doug Thompson if (p->mc_idx >= mci->mc_idx) { 4252d7bbb91c8df26c60d223205a087507430024177Doug Thompson if (unlikely(p->mc_idx == mci->mc_idx)) 4262d7bbb91c8df26c60d223205a087507430024177Doug Thompson goto fail1; 427da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 4282d7bbb91c8df26c60d223205a087507430024177Doug Thompson insert_before = item; 4292d7bbb91c8df26c60d223205a087507430024177Doug Thompson break; 430da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 431da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 432da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 433da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox list_add_tail_rcu(&mci->link, insert_before); 434c0d121720220584bba2876b032e58a076b843fa1Dave Jiang atomic_inc(&edac_handlers); 435da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return 0; 4362d7bbb91c8df26c60d223205a087507430024177Doug Thompson 437052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompsonfail0: 4382d7bbb91c8df26c60d223205a087507430024177Doug Thompson edac_printk(KERN_WARNING, EDAC_MC, 439281efb17d88a91dc3b879bb1d49e3a66daf48797Kay Sievers "%s (%s) %s %s already assigned %d\n", dev_name(p->dev), 44017aa7e034416e3080bc57a786d09ba0a4a044561Stephen Rothwell edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx); 4412d7bbb91c8df26c60d223205a087507430024177Doug Thompson return 1; 4422d7bbb91c8df26c60d223205a087507430024177Doug Thompson 443052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompsonfail1: 4442d7bbb91c8df26c60d223205a087507430024177Doug Thompson edac_printk(KERN_WARNING, EDAC_MC, 445052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "bug in low-level driver: attempt to assign\n" 446052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__); 4472d7bbb91c8df26c60d223205a087507430024177Doug Thompson return 1; 448da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 449da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 450e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic void complete_mc_list_del(struct rcu_head *head) 451a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson{ 452a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson struct mem_ctl_info *mci; 453a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson 454a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson mci = container_of(head, struct mem_ctl_info, rcu); 455a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson INIT_LIST_HEAD(&mci->link); 456a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson} 457a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson 458e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic void del_mc_from_global_list(struct mem_ctl_info *mci) 459a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson{ 460c0d121720220584bba2876b032e58a076b843fa1Dave Jiang atomic_dec(&edac_handlers); 461a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson list_del_rcu(&mci->link); 462a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson call_rcu(&mci->rcu, complete_mc_list_del); 463458e5ff13e1bed050990d97e9aa55bcdafc951a7Jesper Dangaard Brouer rcu_barrier(); 464a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson} 465a1d03fcc1399b1e23922bcc3af1772b128aa6e93Dave Peterson 466da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 4675da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'. 4685da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson * 4695da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson * If found, return a pointer to the structure. 4705da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson * Else return NULL. 4715da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson * 4725da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson * Caller must hold mem_ctls_mutex. 4735da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson */ 474079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompsonstruct mem_ctl_info *edac_mc_find(int idx) 4755da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson{ 4765da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson struct list_head *item; 4775da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson struct mem_ctl_info *mci; 4785da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson 4795da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson list_for_each(item, &mc_devices) { 4805da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson mci = list_entry(item, struct mem_ctl_info, link); 4815da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson 4825da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson if (mci->mc_idx >= idx) { 4835da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson if (mci->mc_idx == idx) 4845da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson return mci; 4855da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson 4865da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson break; 4875da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson } 4885da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson } 4895da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson 4905da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson return NULL; 4915da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson} 4925da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas ThompsonEXPORT_SYMBOL(edac_mc_find); 4935da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson 4945da0831c598f94582bce6bb0a55b8de2f9897cb1Douglas Thompson/** 495472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and 496472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * create sysfs entries associated with mci structure 497da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * @mci: pointer to the mci structure to be added to the list 4982d7bbb91c8df26c60d223205a087507430024177Doug Thompson * @mc_idx: A unique numeric identifier to be assigned to the 'mci' structure. 499da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 500da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Return: 501da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 0 Success 502da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * !0 Failure 503da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 504da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 505da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* FIXME - should a warning be printed if no error detection? correction? */ 506b8f6f9755248026f21282e25cac49a1af698056cDoug Thompsonint edac_mc_add_mc(struct mem_ctl_info *mci) 507da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 508537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf0("%s()\n", __func__); 509b8f6f9755248026f21282e25cac49a1af698056cDoug Thompson 510da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#ifdef CONFIG_EDAC_DEBUG 511da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_debug_level >= 3) 512da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_dump_mci(mci); 513e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 514da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (edac_debug_level >= 4) { 515da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int i; 516da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 517da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (i = 0; i < mci->nr_csrows; i++) { 518da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int j; 519e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 520da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_dump_csrow(&mci->csrows[i]); 521da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (j = 0; j < mci->csrows[i].nr_channels; j++) 522079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson edac_mc_dump_channel(&mci->csrows[i]. 523052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson channels[j]); 524da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 525da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 526da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox#endif 52763b7df9101895d1f0a259c567b3bab949a23075fMatthias Kaehlcke mutex_lock(&mem_ctls_mutex); 528da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 529da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (add_mc_to_global_list(mci)) 530028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson goto fail0; 531da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 532da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* set load time so that error rate can be tracked */ 533da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->start_time = jiffies; 534da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 5359794f33ddedd878dd92fcf8b4834391840366919eric wollesen if (edac_create_sysfs_mci_device(mci)) { 5369794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_printk(mci, KERN_WARNING, 537052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "failed to create sysfs device\n"); 5389794f33ddedd878dd92fcf8b4834391840366919eric wollesen goto fail1; 5399794f33ddedd878dd92fcf8b4834391840366919eric wollesen } 540da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 54181d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang /* If there IS a check routine, then we are running POLLED */ 54281d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang if (mci->edac_check != NULL) { 54381d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang /* This instance is NOW RUNNING */ 54481d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang mci->op_state = OP_RUNNING_POLL; 54581d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 54681d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); 54781d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang } else { 54881d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang mci->op_state = OP_RUNNING_INTERRUPT; 54981d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang } 55081d87cb13e367bb804bf44889ae0de7369705d6cDave Jiang 551da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Report action taken */ 552bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':" 55317aa7e034416e3080bc57a786d09ba0a4a044561Stephen Rothwell " DEV %s\n", mci->mod_name, mci->ctl_name, edac_dev_name(mci)); 554da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 55563b7df9101895d1f0a259c567b3bab949a23075fMatthias Kaehlcke mutex_unlock(&mem_ctls_mutex); 556028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson return 0; 557da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 558052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompsonfail1: 559028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson del_mc_from_global_list(mci); 560028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson 561052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompsonfail0: 56263b7df9101895d1f0a259c567b3bab949a23075fMatthias Kaehlcke mutex_unlock(&mem_ctls_mutex); 563028a7b6d3d9fa2cc41d76d45575345cca8d00a4cDave Peterson return 1; 564da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 5659110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_add_mc); 566da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 567da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/** 568472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * edac_mc_del_mc: Remove sysfs entries for specified mci structure and 569472678ebd30d87cbe8d97562dcc0e46d1076040fDave Peterson * remove mci structure from global list 57037f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson * @pdev: Pointer to 'struct device' representing mci structure to remove. 571da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * 57218dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson * Return pointer to removed mci structure, or NULL if device not found. 573da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 574079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompsonstruct mem_ctl_info *edac_mc_del_mc(struct device *dev) 575da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 57618dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson struct mem_ctl_info *mci; 577da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 578bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson debugf0("%s()\n", __func__); 579bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson 58063b7df9101895d1f0a259c567b3bab949a23075fMatthias Kaehlcke mutex_lock(&mem_ctls_mutex); 58118dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson 582bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson /* find the requested mci struct in the global list */ 583bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson mci = find_mci_by_dev(dev); 584bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson if (mci == NULL) { 58563b7df9101895d1f0a259c567b3bab949a23075fMatthias Kaehlcke mutex_unlock(&mem_ctls_mutex); 58618dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson return NULL; 58718dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson } 58818dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson 589da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox del_mc_from_global_list(mci); 59063b7df9101895d1f0a259c567b3bab949a23075fMatthias Kaehlcke mutex_unlock(&mem_ctls_mutex); 591bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson 592bb31b3122c0dd07d2d958da17a50ad771ce79e2bBorislav Petkov /* flush workq processes */ 593bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson edac_mc_workq_teardown(mci); 594bb31b3122c0dd07d2d958da17a50ad771ce79e2bBorislav Petkov 595bb31b3122c0dd07d2d958da17a50ad771ce79e2bBorislav Petkov /* marking MCI offline */ 596bb31b3122c0dd07d2d958da17a50ad771ce79e2bBorislav Petkov mci->op_state = OP_OFFLINE; 597bb31b3122c0dd07d2d958da17a50ad771ce79e2bBorislav Petkov 598bb31b3122c0dd07d2d958da17a50ad771ce79e2bBorislav Petkov /* remove from sysfs */ 599bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson edac_remove_sysfs_mci_device(mci); 600bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson 601537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_printk(KERN_INFO, EDAC_MC, 602052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "Removed device %d for %s %s: DEV %s\n", mci->mc_idx, 60317aa7e034416e3080bc57a786d09ba0a4a044561Stephen Rothwell mci->mod_name, mci->ctl_name, edac_dev_name(mci)); 604bf52fa4a26567bfbf5b1d30f84cf0226e61d26cdDoug Thompson 60518dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson return mci; 606da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 6079110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_del_mc); 608da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 6092da1c119fd999cb834b4fe0c1a5a8c36195df1cbAdrian Bunkstatic void edac_mc_scrub_block(unsigned long page, unsigned long offset, 6102da1c119fd999cb834b4fe0c1a5a8c36195df1cbAdrian Bunk u32 size) 611da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 612da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct page *pg; 613da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox void *virt_addr; 614da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned long flags = 0; 615da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 616537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("%s()\n", __func__); 617da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 618da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* ECC error page was not in our memory. Ignore it. */ 619079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson if (!pfn_valid(page)) 620da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 621da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 622da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Find the actual page structure then map it and fix */ 623da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pg = pfn_to_page(page); 624da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 625da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (PageHighMem(pg)) 626da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox local_irq_save(flags); 627da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 628da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox virt_addr = kmap_atomic(pg, KM_BOUNCE_READ); 629da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 630da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Perform architecture specific atomic scrub operation */ 631da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox atomic_scrub(virt_addr + offset, size); 632da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 633da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* Unmap and complete */ 634da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox kunmap_atomic(virt_addr, KM_BOUNCE_READ); 635da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 636da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (PageHighMem(pg)) 637da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox local_irq_restore(flags); 638da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 639da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 640da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* FIXME - should return -1 */ 641e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonint edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) 642da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 643da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csrows = mci->csrows; 644da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int row, i; 645da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 646537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page); 647da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox row = -1; 648da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 649da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (i = 0; i < mci->nr_csrows; i++) { 650da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox struct csrow_info *csrow = &csrows[i]; 651da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 652da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (csrow->nr_pages == 0) 653da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox continue; 654da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 655537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) " 656537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson "mask(0x%lx)\n", mci->mc_idx, __func__, 657537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson csrow->first_page, page, csrow->last_page, 658537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson csrow->page_mask); 659da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 660da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if ((page >= csrow->first_page) && 661da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox (page <= csrow->last_page) && 662da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox ((page & csrow->page_mask) == 663da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox (csrow->first_page & csrow->page_mask))) { 664da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox row = i; 665da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox break; 666da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 667da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 668da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 669da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (row == -1) 670537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_ERR, 671052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "could not look up page error address %lx\n", 672052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson (unsigned long)page); 673da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 674da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return row; 675da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 6769110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page); 677da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 678da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* FIXME - setable log (warning/emerg) levels */ 679da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */ 680da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_handle_ce(struct mem_ctl_info *mci, 681052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson unsigned long page_frame_number, 682052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson unsigned long offset_in_page, unsigned long syndrome, 683052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson int row, int channel, const char *msg) 684da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 685da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox unsigned long remapped_page; 686da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 687537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("MC%d: %s()\n", mci->mc_idx, __func__); 688da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 689da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* FIXME - maybe make panic on INTERNAL ERROR an option */ 690da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (row >= mci->nr_csrows || row < 0) { 691da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* something is wrong */ 692537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_ERR, 693052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "INTERNAL ERROR: row out of range " 694052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "(%d >= %d)\n", row, mci->nr_csrows); 695da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); 696da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 697da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 698e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 699da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (channel >= mci->csrows[row].nr_channels || channel < 0) { 700da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* something is wrong */ 701537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_ERR, 702052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "INTERNAL ERROR: channel out of range " 703052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "(%d >= %d)\n", channel, 704052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson mci->csrows[row].nr_channels); 705da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); 706da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 707da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 708da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 7094de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_log_ce()) 710da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* FIXME - put in DIMM location */ 711537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_WARNING, 712052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "CE page 0x%lx, offset 0x%lx, grain %d, syndrome " 713052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "0x%lx, row %d, channel %d, label \"%s\": %s\n", 714052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson page_frame_number, offset_in_page, 715052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson mci->csrows[row].grain, syndrome, row, channel, 716052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson mci->csrows[row].channels[channel].label, msg); 717da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 718da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ce_count++; 719da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->csrows[row].ce_count++; 720da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->csrows[row].channels[channel].ce_count++; 721da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 722da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (mci->scrub_mode & SCRUB_SW_SRC) { 723da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* 724da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * Some MC's can remap memory so that it is still available 725da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * at a different address when PCI devices map into memory. 726da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * MC's that can't do this lose the memory where PCI devices 727da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * are mapped. This mapping is MC dependant and so we call 728da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * back into the MC driver for it to map the MC page to 729da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * a physical (CPU) page which can then be mapped to a virtual 730da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox * page - which can then be scrubbed. 731da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox */ 732da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox remapped_page = mci->ctl_page_to_phys ? 733052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson mci->ctl_page_to_phys(mci, page_frame_number) : 734052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson page_frame_number; 735da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 736da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_scrub_block(remapped_page, offset_in_page, 737052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson mci->csrows[row].grain); 738da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 739da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 7409110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_handle_ce); 741da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 742e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonvoid edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) 743da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 7444de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_log_ce()) 745537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_WARNING, 746052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "CE - no information available: %s\n", msg); 747e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 748da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ce_noinfo_count++; 749da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ce_count++; 750da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 7519110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info); 752da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 753da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxvoid edac_mc_handle_ue(struct mem_ctl_info *mci, 754052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson unsigned long page_frame_number, 755052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson unsigned long offset_in_page, int row, const char *msg) 756da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 757da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int len = EDAC_MC_LABEL_LEN * 4; 758da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char labels[len + 1]; 759da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox char *pos = labels; 760da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int chan; 761da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox int chars; 762da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 763537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson debugf3("MC%d: %s()\n", mci->mc_idx, __func__); 764da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 765da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* FIXME - maybe make panic on INTERNAL ERROR an option */ 766da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox if (row >= mci->nr_csrows || row < 0) { 767da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox /* something is wrong */ 768537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_ERR, 769052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "INTERNAL ERROR: row out of range " 770052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "(%d >= %d)\n", row, mci->nr_csrows); 771da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); 772da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox return; 773da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 774da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 775da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chars = snprintf(pos, len + 1, "%s", 776079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson mci->csrows[row].channels[0].label); 777da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox len -= chars; 778da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pos += chars; 779e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson 780da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0); 781052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson chan++) { 782da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox chars = snprintf(pos, len + 1, ":%s", 783079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson mci->csrows[row].channels[chan].label); 784da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox len -= chars; 785da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox pos += chars; 786da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox } 787da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 7884de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_log_ue()) 789537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_EMERG, 790052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "UE page 0x%lx, offset 0x%lx, grain %d, row %d, " 791052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "labels \"%s\": %s\n", page_frame_number, 792052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson offset_in_page, mci->csrows[row].grain, row, 793052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson labels, msg); 794da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 7954de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_panic_on_ue()) 796e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, " 797052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "row %d, labels \"%s\": %s\n", mci->mc_idx, 798052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson page_frame_number, offset_in_page, 799052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson mci->csrows[row].grain, row, labels, msg); 800da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 801da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ue_count++; 802da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->csrows[row].ue_count++; 803da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 8049110540f7f2bbcc3577d2580a696fbb7af68c892Dave PetersonEXPORT_SYMBOL_GPL(edac_mc_handle_ue); 805da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 806e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonvoid edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) 807da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox{ 8084de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_panic_on_ue()) 809da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox panic("EDAC MC%d: Uncorrected Error", mci->mc_idx); 810da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 8114de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_log_ue()) 812537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson edac_mc_printk(mci, KERN_WARNING, 813052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "UE - no information available: %s\n", msg); 814da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ue_noinfo_count++; 815da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox mci->ue_count++; 816da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox} 817079708b9173595bf74b31b14c36e946359ae6c7eDouglas ThompsonEXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); 818da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Cox 8199794f33ddedd878dd92fcf8b4834391840366919eric wollesen/************************************************************* 8209794f33ddedd878dd92fcf8b4834391840366919eric wollesen * On Fully Buffered DIMM modules, this help function is 8219794f33ddedd878dd92fcf8b4834391840366919eric wollesen * called to process UE events 8229794f33ddedd878dd92fcf8b4834391840366919eric wollesen */ 8239794f33ddedd878dd92fcf8b4834391840366919eric wollesenvoid edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, 824052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson unsigned int csrow, 825052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson unsigned int channela, 826052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson unsigned int channelb, char *msg) 8279794f33ddedd878dd92fcf8b4834391840366919eric wollesen{ 8289794f33ddedd878dd92fcf8b4834391840366919eric wollesen int len = EDAC_MC_LABEL_LEN * 4; 8299794f33ddedd878dd92fcf8b4834391840366919eric wollesen char labels[len + 1]; 8309794f33ddedd878dd92fcf8b4834391840366919eric wollesen char *pos = labels; 8319794f33ddedd878dd92fcf8b4834391840366919eric wollesen int chars; 8329794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8339794f33ddedd878dd92fcf8b4834391840366919eric wollesen if (csrow >= mci->nr_csrows) { 8349794f33ddedd878dd92fcf8b4834391840366919eric wollesen /* something is wrong */ 8359794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_printk(mci, KERN_ERR, 836052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "INTERNAL ERROR: row out of range (%d >= %d)\n", 837052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson csrow, mci->nr_csrows); 8389794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); 8399794f33ddedd878dd92fcf8b4834391840366919eric wollesen return; 8409794f33ddedd878dd92fcf8b4834391840366919eric wollesen } 8419794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8429794f33ddedd878dd92fcf8b4834391840366919eric wollesen if (channela >= mci->csrows[csrow].nr_channels) { 8439794f33ddedd878dd92fcf8b4834391840366919eric wollesen /* something is wrong */ 8449794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_printk(mci, KERN_ERR, 845052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "INTERNAL ERROR: channel-a out of range " 846052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "(%d >= %d)\n", 847052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson channela, mci->csrows[csrow].nr_channels); 8489794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); 8499794f33ddedd878dd92fcf8b4834391840366919eric wollesen return; 8509794f33ddedd878dd92fcf8b4834391840366919eric wollesen } 8519794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8529794f33ddedd878dd92fcf8b4834391840366919eric wollesen if (channelb >= mci->csrows[csrow].nr_channels) { 8539794f33ddedd878dd92fcf8b4834391840366919eric wollesen /* something is wrong */ 8549794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_printk(mci, KERN_ERR, 855052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "INTERNAL ERROR: channel-b out of range " 856052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "(%d >= %d)\n", 857052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson channelb, mci->csrows[csrow].nr_channels); 8589794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); 8599794f33ddedd878dd92fcf8b4834391840366919eric wollesen return; 8609794f33ddedd878dd92fcf8b4834391840366919eric wollesen } 8619794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8629794f33ddedd878dd92fcf8b4834391840366919eric wollesen mci->ue_count++; 8639794f33ddedd878dd92fcf8b4834391840366919eric wollesen mci->csrows[csrow].ue_count++; 8649794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8659794f33ddedd878dd92fcf8b4834391840366919eric wollesen /* Generate the DIMM labels from the specified channels */ 8669794f33ddedd878dd92fcf8b4834391840366919eric wollesen chars = snprintf(pos, len + 1, "%s", 8679794f33ddedd878dd92fcf8b4834391840366919eric wollesen mci->csrows[csrow].channels[channela].label); 868079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson len -= chars; 869079708b9173595bf74b31b14c36e946359ae6c7eDouglas Thompson pos += chars; 8709794f33ddedd878dd92fcf8b4834391840366919eric wollesen chars = snprintf(pos, len + 1, "-%s", 8719794f33ddedd878dd92fcf8b4834391840366919eric wollesen mci->csrows[csrow].channels[channelb].label); 8729794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8734de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_log_ue()) 8749794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_printk(mci, KERN_EMERG, 875052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "UE row %d, channel-a= %d channel-b= %d " 876052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "labels \"%s\": %s\n", csrow, channela, channelb, 877052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson labels, msg); 8789794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8794de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_panic_on_ue()) 8809794f33ddedd878dd92fcf8b4834391840366919eric wollesen panic("UE row %d, channel-a= %d channel-b= %d " 881052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "labels \"%s\": %s\n", csrow, channela, 882052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson channelb, labels, msg); 8839794f33ddedd878dd92fcf8b4834391840366919eric wollesen} 8849794f33ddedd878dd92fcf8b4834391840366919eric wollesenEXPORT_SYMBOL(edac_mc_handle_fbd_ue); 8859794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8869794f33ddedd878dd92fcf8b4834391840366919eric wollesen/************************************************************* 8879794f33ddedd878dd92fcf8b4834391840366919eric wollesen * On Fully Buffered DIMM modules, this help function is 8889794f33ddedd878dd92fcf8b4834391840366919eric wollesen * called to process CE events 8899794f33ddedd878dd92fcf8b4834391840366919eric wollesen */ 8909794f33ddedd878dd92fcf8b4834391840366919eric wollesenvoid edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, 891052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson unsigned int csrow, unsigned int channel, char *msg) 8929794f33ddedd878dd92fcf8b4834391840366919eric wollesen{ 8939794f33ddedd878dd92fcf8b4834391840366919eric wollesen 8949794f33ddedd878dd92fcf8b4834391840366919eric wollesen /* Ensure boundary values */ 8959794f33ddedd878dd92fcf8b4834391840366919eric wollesen if (csrow >= mci->nr_csrows) { 8969794f33ddedd878dd92fcf8b4834391840366919eric wollesen /* something is wrong */ 8979794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_printk(mci, KERN_ERR, 898052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "INTERNAL ERROR: row out of range (%d >= %d)\n", 899052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson csrow, mci->nr_csrows); 9009794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); 9019794f33ddedd878dd92fcf8b4834391840366919eric wollesen return; 9029794f33ddedd878dd92fcf8b4834391840366919eric wollesen } 9039794f33ddedd878dd92fcf8b4834391840366919eric wollesen if (channel >= mci->csrows[csrow].nr_channels) { 9049794f33ddedd878dd92fcf8b4834391840366919eric wollesen /* something is wrong */ 9059794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_printk(mci, KERN_ERR, 906052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "INTERNAL ERROR: channel out of range (%d >= %d)\n", 907052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson channel, mci->csrows[csrow].nr_channels); 9089794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); 9099794f33ddedd878dd92fcf8b4834391840366919eric wollesen return; 9109794f33ddedd878dd92fcf8b4834391840366919eric wollesen } 9119794f33ddedd878dd92fcf8b4834391840366919eric wollesen 9124de78c6877ec21142582ac19453c2d453d1ea298Dave Jiang if (edac_mc_get_log_ce()) 9139794f33ddedd878dd92fcf8b4834391840366919eric wollesen /* FIXME - put in DIMM location */ 9149794f33ddedd878dd92fcf8b4834391840366919eric wollesen edac_mc_printk(mci, KERN_WARNING, 915052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson "CE row %d, channel %d, label \"%s\": %s\n", 916052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson csrow, channel, 917052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson mci->csrows[csrow].channels[channel].label, msg); 9189794f33ddedd878dd92fcf8b4834391840366919eric wollesen 9199794f33ddedd878dd92fcf8b4834391840366919eric wollesen mci->ce_count++; 9209794f33ddedd878dd92fcf8b4834391840366919eric wollesen mci->csrows[csrow].ce_count++; 9219794f33ddedd878dd92fcf8b4834391840366919eric wollesen mci->csrows[csrow].channels[channel].ce_count++; 9229794f33ddedd878dd92fcf8b4834391840366919eric wollesen} 923079708b9173595bf74b31b14c36e946359ae6c7eDouglas ThompsonEXPORT_SYMBOL(edac_mc_handle_fbd_ce); 924