edac_pci.c (7638B)
1/* 2 * EDAC PCI component 3 * 4 * Author: Dave Jiang <djiang@mvista.com> 5 * 6 * 2007 (c) MontaVista Software, Inc. This file is licensed under 7 * the terms of the GNU General Public License version 2. This program 8 * is licensed "as is" without any warranty of any kind, whether express 9 * or implied. 10 * 11 */ 12#include <asm/page.h> 13#include <linux/uaccess.h> 14#include <linux/ctype.h> 15#include <linux/highmem.h> 16#include <linux/init.h> 17#include <linux/module.h> 18#include <linux/slab.h> 19#include <linux/smp.h> 20#include <linux/spinlock.h> 21#include <linux/sysctl.h> 22#include <linux/timer.h> 23 24#include "edac_pci.h" 25#include "edac_module.h" 26 27static DEFINE_MUTEX(edac_pci_ctls_mutex); 28static LIST_HEAD(edac_pci_list); 29static atomic_t pci_indexes = ATOMIC_INIT(0); 30 31struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, 32 const char *edac_pci_name) 33{ 34 struct edac_pci_ctl_info *pci; 35 36 edac_dbg(1, "\n"); 37 38 pci = kzalloc(sizeof(struct edac_pci_ctl_info), GFP_KERNEL); 39 if (!pci) 40 return NULL; 41 42 if (sz_pvt) { 43 pci->pvt_info = kzalloc(sz_pvt, GFP_KERNEL); 44 if (!pci->pvt_info) 45 goto free; 46 } 47 48 pci->op_state = OP_ALLOC; 49 50 snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name); 51 52 return pci; 53 54free: 55 kfree(pci); 56 return NULL; 57} 58EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info); 59 60void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci) 61{ 62 edac_dbg(1, "\n"); 63 64 edac_pci_remove_sysfs(pci); 65} 66EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info); 67 68/* 69 * find_edac_pci_by_dev() 70 * scans the edac_pci list for a specific 'struct device *' 71 * 72 * return NULL if not found, or return control struct pointer 73 */ 74static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev) 75{ 76 struct edac_pci_ctl_info *pci; 77 struct list_head *item; 78 79 edac_dbg(1, "\n"); 80 81 list_for_each(item, &edac_pci_list) { 82 pci = list_entry(item, struct edac_pci_ctl_info, link); 83 84 if (pci->dev == dev) 85 return pci; 86 } 87 88 return NULL; 89} 90 91/* 92 * add_edac_pci_to_global_list 93 * Before calling this function, caller must assign a unique value to 94 * edac_dev->pci_idx. 95 * Return: 96 * 0 on success 97 * 1 on failure 98 */ 99static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci) 100{ 101 struct list_head *item, *insert_before; 102 struct edac_pci_ctl_info *rover; 103 104 edac_dbg(1, "\n"); 105 106 insert_before = &edac_pci_list; 107 108 /* Determine if already on the list */ 109 rover = find_edac_pci_by_dev(pci->dev); 110 if (unlikely(rover != NULL)) 111 goto fail0; 112 113 /* Insert in ascending order by 'pci_idx', so find position */ 114 list_for_each(item, &edac_pci_list) { 115 rover = list_entry(item, struct edac_pci_ctl_info, link); 116 117 if (rover->pci_idx >= pci->pci_idx) { 118 if (unlikely(rover->pci_idx == pci->pci_idx)) 119 goto fail1; 120 121 insert_before = item; 122 break; 123 } 124 } 125 126 list_add_tail_rcu(&pci->link, insert_before); 127 return 0; 128 129fail0: 130 edac_printk(KERN_WARNING, EDAC_PCI, 131 "%s (%s) %s %s already assigned %d\n", 132 dev_name(rover->dev), edac_dev_name(rover), 133 rover->mod_name, rover->ctl_name, rover->pci_idx); 134 return 1; 135 136fail1: 137 edac_printk(KERN_WARNING, EDAC_PCI, 138 "but in low-level driver: attempt to assign\n" 139 "\tduplicate pci_idx %d in %s()\n", rover->pci_idx, 140 __func__); 141 return 1; 142} 143 144/* 145 * del_edac_pci_from_global_list 146 * 147 * remove the PCI control struct from the global list 148 */ 149static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci) 150{ 151 list_del_rcu(&pci->link); 152 153 /* these are for safe removal of devices from global list while 154 * NMI handlers may be traversing list 155 */ 156 synchronize_rcu(); 157 INIT_LIST_HEAD(&pci->link); 158} 159 160/* 161 * edac_pci_workq_function() 162 * 163 * periodic function that performs the operation 164 * scheduled by a workq request, for a given PCI control struct 165 */ 166static void edac_pci_workq_function(struct work_struct *work_req) 167{ 168 struct delayed_work *d_work = to_delayed_work(work_req); 169 struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work); 170 int msec; 171 unsigned long delay; 172 173 edac_dbg(3, "checking\n"); 174 175 mutex_lock(&edac_pci_ctls_mutex); 176 177 if (pci->op_state != OP_RUNNING_POLL) { 178 mutex_unlock(&edac_pci_ctls_mutex); 179 return; 180 } 181 182 if (edac_pci_get_check_errors()) 183 pci->edac_check(pci); 184 185 /* if we are on a one second period, then use round */ 186 msec = edac_pci_get_poll_msec(); 187 if (msec == 1000) 188 delay = round_jiffies_relative(msecs_to_jiffies(msec)); 189 else 190 delay = msecs_to_jiffies(msec); 191 192 edac_queue_work(&pci->work, delay); 193 194 mutex_unlock(&edac_pci_ctls_mutex); 195} 196 197int edac_pci_alloc_index(void) 198{ 199 return atomic_inc_return(&pci_indexes) - 1; 200} 201EXPORT_SYMBOL_GPL(edac_pci_alloc_index); 202 203int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx) 204{ 205 edac_dbg(0, "\n"); 206 207 pci->pci_idx = edac_idx; 208 pci->start_time = jiffies; 209 210 mutex_lock(&edac_pci_ctls_mutex); 211 212 if (add_edac_pci_to_global_list(pci)) 213 goto fail0; 214 215 if (edac_pci_create_sysfs(pci)) { 216 edac_pci_printk(pci, KERN_WARNING, 217 "failed to create sysfs pci\n"); 218 goto fail1; 219 } 220 221 if (pci->edac_check) { 222 pci->op_state = OP_RUNNING_POLL; 223 224 INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function); 225 edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec())); 226 227 } else { 228 pci->op_state = OP_RUNNING_INTERRUPT; 229 } 230 231 edac_pci_printk(pci, KERN_INFO, 232 "Giving out device to module %s controller %s: DEV %s (%s)\n", 233 pci->mod_name, pci->ctl_name, pci->dev_name, 234 edac_op_state_to_string(pci->op_state)); 235 236 mutex_unlock(&edac_pci_ctls_mutex); 237 return 0; 238 239 /* error unwind stack */ 240fail1: 241 del_edac_pci_from_global_list(pci); 242fail0: 243 mutex_unlock(&edac_pci_ctls_mutex); 244 return 1; 245} 246EXPORT_SYMBOL_GPL(edac_pci_add_device); 247 248struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev) 249{ 250 struct edac_pci_ctl_info *pci; 251 252 edac_dbg(0, "\n"); 253 254 mutex_lock(&edac_pci_ctls_mutex); 255 256 /* ensure the control struct is on the global list 257 * if not, then leave 258 */ 259 pci = find_edac_pci_by_dev(dev); 260 if (pci == NULL) { 261 mutex_unlock(&edac_pci_ctls_mutex); 262 return NULL; 263 } 264 265 pci->op_state = OP_OFFLINE; 266 267 del_edac_pci_from_global_list(pci); 268 269 mutex_unlock(&edac_pci_ctls_mutex); 270 271 if (pci->edac_check) 272 edac_stop_work(&pci->work); 273 274 edac_printk(KERN_INFO, EDAC_PCI, 275 "Removed device %d for %s %s: DEV %s\n", 276 pci->pci_idx, pci->mod_name, pci->ctl_name, edac_dev_name(pci)); 277 278 return pci; 279} 280EXPORT_SYMBOL_GPL(edac_pci_del_device); 281 282/* 283 * edac_pci_generic_check 284 * 285 * a Generic parity check API 286 */ 287static void edac_pci_generic_check(struct edac_pci_ctl_info *pci) 288{ 289 edac_dbg(4, "\n"); 290 edac_pci_do_parity_check(); 291} 292 293/* free running instance index counter */ 294static int edac_pci_idx; 295#define EDAC_PCI_GENCTL_NAME "EDAC PCI controller" 296 297struct edac_pci_gen_data { 298 int edac_idx; 299}; 300 301struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev, 302 const char *mod_name) 303{ 304 struct edac_pci_ctl_info *pci; 305 struct edac_pci_gen_data *pdata; 306 307 pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME); 308 if (!pci) 309 return NULL; 310 311 pdata = pci->pvt_info; 312 pci->dev = dev; 313 dev_set_drvdata(pci->dev, pci); 314 pci->dev_name = pci_name(to_pci_dev(dev)); 315 316 pci->mod_name = mod_name; 317 pci->ctl_name = EDAC_PCI_GENCTL_NAME; 318 if (edac_op_state == EDAC_OPSTATE_POLL) 319 pci->edac_check = edac_pci_generic_check; 320 321 pdata->edac_idx = edac_pci_idx++; 322 323 if (edac_pci_add_device(pci, pdata->edac_idx) > 0) { 324 edac_dbg(3, "failed edac_pci_add_device()\n"); 325 edac_pci_free_ctl_info(pci); 326 return NULL; 327 } 328 329 return pci; 330} 331EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl); 332 333void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci) 334{ 335 edac_dbg(0, "pci mod=%s\n", pci->mod_name); 336 337 edac_pci_del_device(pci->dev); 338 edac_pci_free_ctl_info(pci); 339} 340EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);