0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <asm/page.h>
0016 #include <linux/uaccess.h>
0017 #include <linux/ctype.h>
0018 #include <linux/highmem.h>
0019 #include <linux/init.h>
0020 #include <linux/jiffies.h>
0021 #include <linux/module.h>
0022 #include <linux/slab.h>
0023 #include <linux/smp.h>
0024 #include <linux/spinlock.h>
0025 #include <linux/sysctl.h>
0026 #include <linux/timer.h>
0027
0028 #include "edac_device.h"
0029 #include "edac_module.h"
0030
0031
0032
0033
0034 static DEFINE_MUTEX(device_ctls_mutex);
0035 static LIST_HEAD(edac_device_list);
0036
0037 #ifdef CONFIG_EDAC_DEBUG
0038 static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
0039 {
0040 edac_dbg(3, "\tedac_dev = %p dev_idx=%d\n",
0041 edac_dev, edac_dev->dev_idx);
0042 edac_dbg(4, "\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
0043 edac_dbg(3, "\tdev = %p\n", edac_dev->dev);
0044 edac_dbg(3, "\tmod_name:ctl_name = %s:%s\n",
0045 edac_dev->mod_name, edac_dev->ctl_name);
0046 edac_dbg(3, "\tpvt_info = %p\n\n", edac_dev->pvt_info);
0047 }
0048 #endif
0049
0050
0051
0052
0053 struct edac_device_ctl_info *
0054 edac_device_alloc_ctl_info(unsigned pvt_sz, char *dev_name, unsigned nr_instances,
0055 char *blk_name, unsigned nr_blocks, unsigned off_val,
0056 struct edac_dev_sysfs_block_attribute *attrib_spec,
0057 unsigned nr_attrib, int device_index)
0058 {
0059 struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
0060 struct edac_device_block *dev_blk, *blk_p, *blk;
0061 struct edac_device_instance *dev_inst, *inst;
0062 struct edac_device_ctl_info *dev_ctl;
0063 unsigned instance, block, attr;
0064 void *pvt;
0065 int err;
0066
0067 edac_dbg(4, "instances=%d blocks=%d\n", nr_instances, nr_blocks);
0068
0069 dev_ctl = kzalloc(sizeof(struct edac_device_ctl_info), GFP_KERNEL);
0070 if (!dev_ctl)
0071 return NULL;
0072
0073 dev_inst = kcalloc(nr_instances, sizeof(struct edac_device_instance), GFP_KERNEL);
0074 if (!dev_inst)
0075 goto free;
0076
0077 dev_ctl->instances = dev_inst;
0078
0079 dev_blk = kcalloc(nr_instances * nr_blocks, sizeof(struct edac_device_block), GFP_KERNEL);
0080 if (!dev_blk)
0081 goto free;
0082
0083 dev_ctl->blocks = dev_blk;
0084
0085 if (nr_attrib) {
0086 dev_attrib = kcalloc(nr_attrib, sizeof(struct edac_dev_sysfs_block_attribute),
0087 GFP_KERNEL);
0088 if (!dev_attrib)
0089 goto free;
0090
0091 dev_ctl->attribs = dev_attrib;
0092 }
0093
0094 if (pvt_sz) {
0095 pvt = kzalloc(pvt_sz, GFP_KERNEL);
0096 if (!pvt)
0097 goto free;
0098
0099 dev_ctl->pvt_info = pvt;
0100 }
0101
0102 dev_ctl->dev_idx = device_index;
0103 dev_ctl->nr_instances = nr_instances;
0104
0105
0106 dev_ctl->log_ce = 1;
0107 dev_ctl->log_ue = 1;
0108
0109
0110 snprintf(dev_ctl->name, sizeof(dev_ctl->name),"%s", dev_name);
0111
0112
0113 for (instance = 0; instance < nr_instances; instance++) {
0114 inst = &dev_inst[instance];
0115 inst->ctl = dev_ctl;
0116 inst->nr_blocks = nr_blocks;
0117 blk_p = &dev_blk[instance * nr_blocks];
0118 inst->blocks = blk_p;
0119
0120
0121 snprintf(inst->name, sizeof(inst->name), "%s%u", dev_name, instance);
0122
0123
0124 for (block = 0; block < nr_blocks; block++) {
0125 blk = &blk_p[block];
0126 blk->instance = inst;
0127 snprintf(blk->name, sizeof(blk->name),
0128 "%s%d", blk_name, block + off_val);
0129
0130 edac_dbg(4, "instance=%d inst_p=%p block=#%d block_p=%p name='%s'\n",
0131 instance, inst, block, blk, blk->name);
0132
0133
0134
0135
0136 if ((nr_attrib == 0) || (attrib_spec == NULL))
0137 continue;
0138
0139
0140 blk->nr_attribs = nr_attrib;
0141 attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
0142 blk->block_attributes = attrib_p;
0143
0144 edac_dbg(4, "THIS BLOCK_ATTRIB=%p\n",
0145 blk->block_attributes);
0146
0147
0148
0149
0150
0151
0152 for (attr = 0; attr < nr_attrib; attr++) {
0153 attrib = &attrib_p[attr];
0154
0155
0156
0157
0158 attrib->attr = attrib_spec[attr].attr;
0159 attrib->show = attrib_spec[attr].show;
0160 attrib->store = attrib_spec[attr].store;
0161
0162 attrib->block = blk;
0163
0164 edac_dbg(4, "alloc-attrib=%p attrib_name='%s' attrib-spec=%p spec-name=%s\n",
0165 attrib, attrib->attr.name,
0166 &attrib_spec[attr],
0167 attrib_spec[attr].attr.name
0168 );
0169 }
0170 }
0171 }
0172
0173
0174 dev_ctl->op_state = OP_ALLOC;
0175
0176
0177
0178
0179 err = edac_device_register_sysfs_main_kobj(dev_ctl);
0180 if (err)
0181 goto free;
0182
0183
0184
0185
0186
0187
0188
0189
0190 return dev_ctl;
0191
0192 free:
0193 __edac_device_free_ctl_info(dev_ctl);
0194
0195 return NULL;
0196 }
0197 EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
0198
0199 void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info)
0200 {
0201 edac_device_unregister_sysfs_main_kobj(ctl_info);
0202 }
0203 EXPORT_SYMBOL_GPL(edac_device_free_ctl_info);
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215 static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev)
0216 {
0217 struct edac_device_ctl_info *edac_dev;
0218 struct list_head *item;
0219
0220 edac_dbg(0, "\n");
0221
0222 list_for_each(item, &edac_device_list) {
0223 edac_dev = list_entry(item, struct edac_device_ctl_info, link);
0224
0225 if (edac_dev->dev == dev)
0226 return edac_dev;
0227 }
0228
0229 return NULL;
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev)
0244 {
0245 struct list_head *item, *insert_before;
0246 struct edac_device_ctl_info *rover;
0247
0248 insert_before = &edac_device_list;
0249
0250
0251 rover = find_edac_device_by_dev(edac_dev->dev);
0252 if (unlikely(rover != NULL))
0253 goto fail0;
0254
0255
0256 list_for_each(item, &edac_device_list) {
0257 rover = list_entry(item, struct edac_device_ctl_info, link);
0258
0259 if (rover->dev_idx >= edac_dev->dev_idx) {
0260 if (unlikely(rover->dev_idx == edac_dev->dev_idx))
0261 goto fail1;
0262
0263 insert_before = item;
0264 break;
0265 }
0266 }
0267
0268 list_add_tail_rcu(&edac_dev->link, insert_before);
0269 return 0;
0270
0271 fail0:
0272 edac_printk(KERN_WARNING, EDAC_MC,
0273 "%s (%s) %s %s already assigned %d\n",
0274 dev_name(rover->dev), edac_dev_name(rover),
0275 rover->mod_name, rover->ctl_name, rover->dev_idx);
0276 return 1;
0277
0278 fail1:
0279 edac_printk(KERN_WARNING, EDAC_MC,
0280 "bug in low-level driver: attempt to assign\n"
0281 " duplicate dev_idx %d in %s()\n", rover->dev_idx,
0282 __func__);
0283 return 1;
0284 }
0285
0286
0287
0288
0289 static void del_edac_device_from_global_list(struct edac_device_ctl_info
0290 *edac_device)
0291 {
0292 list_del_rcu(&edac_device->link);
0293
0294
0295
0296
0297 synchronize_rcu();
0298 INIT_LIST_HEAD(&edac_device->link);
0299 }
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313 static void edac_device_workq_function(struct work_struct *work_req)
0314 {
0315 struct delayed_work *d_work = to_delayed_work(work_req);
0316 struct edac_device_ctl_info *edac_dev = to_edac_device_ctl_work(d_work);
0317
0318 mutex_lock(&device_ctls_mutex);
0319
0320
0321 if (edac_dev->op_state == OP_OFFLINE) {
0322 mutex_unlock(&device_ctls_mutex);
0323 return;
0324 }
0325
0326
0327 if ((edac_dev->op_state == OP_RUNNING_POLL) &&
0328 (edac_dev->edac_check != NULL)) {
0329 edac_dev->edac_check(edac_dev);
0330 }
0331
0332 mutex_unlock(&device_ctls_mutex);
0333
0334
0335
0336
0337
0338
0339 if (edac_dev->poll_msec == 1000)
0340 edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
0341 else
0342 edac_queue_work(&edac_dev->work, edac_dev->delay);
0343 }
0344
0345
0346
0347
0348
0349
0350 static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
0351 unsigned msec)
0352 {
0353 edac_dbg(0, "\n");
0354
0355
0356
0357
0358
0359 edac_dev->poll_msec = msec;
0360 edac_dev->delay = msecs_to_jiffies(msec);
0361
0362 INIT_DELAYED_WORK(&edac_dev->work, edac_device_workq_function);
0363
0364
0365
0366
0367
0368
0369 if (edac_dev->poll_msec == 1000)
0370 edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
0371 else
0372 edac_queue_work(&edac_dev->work, edac_dev->delay);
0373 }
0374
0375
0376
0377
0378
0379 static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
0380 {
0381 if (!edac_dev->edac_check)
0382 return;
0383
0384 edac_dev->op_state = OP_OFFLINE;
0385
0386 edac_stop_work(&edac_dev->work);
0387 }
0388
0389
0390
0391
0392
0393
0394
0395
0396 void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
0397 unsigned long value)
0398 {
0399 unsigned long jiffs = msecs_to_jiffies(value);
0400
0401 if (value == 1000)
0402 jiffs = round_jiffies_relative(value);
0403
0404 edac_dev->poll_msec = value;
0405 edac_dev->delay = jiffs;
0406
0407 edac_mod_work(&edac_dev->work, jiffs);
0408 }
0409
0410 int edac_device_alloc_index(void)
0411 {
0412 static atomic_t device_indexes = ATOMIC_INIT(0);
0413
0414 return atomic_inc_return(&device_indexes) - 1;
0415 }
0416 EXPORT_SYMBOL_GPL(edac_device_alloc_index);
0417
0418 int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
0419 {
0420 edac_dbg(0, "\n");
0421
0422 #ifdef CONFIG_EDAC_DEBUG
0423 if (edac_debug_level >= 3)
0424 edac_device_dump_device(edac_dev);
0425 #endif
0426 mutex_lock(&device_ctls_mutex);
0427
0428 if (add_edac_dev_to_global_list(edac_dev))
0429 goto fail0;
0430
0431
0432 edac_dev->start_time = jiffies;
0433
0434
0435 if (edac_device_create_sysfs(edac_dev)) {
0436 edac_device_printk(edac_dev, KERN_WARNING,
0437 "failed to create sysfs device\n");
0438 goto fail1;
0439 }
0440
0441
0442 if (edac_dev->edac_check != NULL) {
0443
0444 edac_dev->op_state = OP_RUNNING_POLL;
0445
0446
0447
0448
0449
0450 edac_device_workq_setup(edac_dev, 1000);
0451 } else {
0452 edac_dev->op_state = OP_RUNNING_INTERRUPT;
0453 }
0454
0455
0456 edac_device_printk(edac_dev, KERN_INFO,
0457 "Giving out device to module %s controller %s: DEV %s (%s)\n",
0458 edac_dev->mod_name, edac_dev->ctl_name, edac_dev->dev_name,
0459 edac_op_state_to_string(edac_dev->op_state));
0460
0461 mutex_unlock(&device_ctls_mutex);
0462 return 0;
0463
0464 fail1:
0465
0466 del_edac_device_from_global_list(edac_dev);
0467
0468 fail0:
0469 mutex_unlock(&device_ctls_mutex);
0470 return 1;
0471 }
0472 EXPORT_SYMBOL_GPL(edac_device_add_device);
0473
0474 struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
0475 {
0476 struct edac_device_ctl_info *edac_dev;
0477
0478 edac_dbg(0, "\n");
0479
0480 mutex_lock(&device_ctls_mutex);
0481
0482
0483 edac_dev = find_edac_device_by_dev(dev);
0484 if (edac_dev == NULL) {
0485 mutex_unlock(&device_ctls_mutex);
0486 return NULL;
0487 }
0488
0489
0490 edac_dev->op_state = OP_OFFLINE;
0491
0492
0493 del_edac_device_from_global_list(edac_dev);
0494
0495 mutex_unlock(&device_ctls_mutex);
0496
0497
0498 edac_device_workq_teardown(edac_dev);
0499
0500
0501 edac_device_remove_sysfs(edac_dev);
0502
0503 edac_printk(KERN_INFO, EDAC_MC,
0504 "Removed device %d for %s %s: DEV %s\n",
0505 edac_dev->dev_idx,
0506 edac_dev->mod_name, edac_dev->ctl_name, edac_dev_name(edac_dev));
0507
0508 return edac_dev;
0509 }
0510 EXPORT_SYMBOL_GPL(edac_device_del_device);
0511
0512 static inline int edac_device_get_log_ce(struct edac_device_ctl_info *edac_dev)
0513 {
0514 return edac_dev->log_ce;
0515 }
0516
0517 static inline int edac_device_get_log_ue(struct edac_device_ctl_info *edac_dev)
0518 {
0519 return edac_dev->log_ue;
0520 }
0521
0522 static inline int edac_device_get_panic_on_ue(struct edac_device_ctl_info
0523 *edac_dev)
0524 {
0525 return edac_dev->panic_on_ue;
0526 }
0527
0528 void edac_device_handle_ce_count(struct edac_device_ctl_info *edac_dev,
0529 unsigned int count, int inst_nr, int block_nr,
0530 const char *msg)
0531 {
0532 struct edac_device_instance *instance;
0533 struct edac_device_block *block = NULL;
0534
0535 if (!count)
0536 return;
0537
0538 if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
0539 edac_device_printk(edac_dev, KERN_ERR,
0540 "INTERNAL ERROR: 'instance' out of range "
0541 "(%d >= %d)\n", inst_nr,
0542 edac_dev->nr_instances);
0543 return;
0544 }
0545
0546 instance = edac_dev->instances + inst_nr;
0547
0548 if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
0549 edac_device_printk(edac_dev, KERN_ERR,
0550 "INTERNAL ERROR: instance %d 'block' "
0551 "out of range (%d >= %d)\n",
0552 inst_nr, block_nr,
0553 instance->nr_blocks);
0554 return;
0555 }
0556
0557 if (instance->nr_blocks > 0) {
0558 block = instance->blocks + block_nr;
0559 block->counters.ce_count += count;
0560 }
0561
0562
0563 instance->counters.ce_count += count;
0564 edac_dev->counters.ce_count += count;
0565
0566 if (edac_device_get_log_ce(edac_dev))
0567 edac_device_printk(edac_dev, KERN_WARNING,
0568 "CE: %s instance: %s block: %s count: %d '%s'\n",
0569 edac_dev->ctl_name, instance->name,
0570 block ? block->name : "N/A", count, msg);
0571 }
0572 EXPORT_SYMBOL_GPL(edac_device_handle_ce_count);
0573
0574 void edac_device_handle_ue_count(struct edac_device_ctl_info *edac_dev,
0575 unsigned int count, int inst_nr, int block_nr,
0576 const char *msg)
0577 {
0578 struct edac_device_instance *instance;
0579 struct edac_device_block *block = NULL;
0580
0581 if (!count)
0582 return;
0583
0584 if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
0585 edac_device_printk(edac_dev, KERN_ERR,
0586 "INTERNAL ERROR: 'instance' out of range "
0587 "(%d >= %d)\n", inst_nr,
0588 edac_dev->nr_instances);
0589 return;
0590 }
0591
0592 instance = edac_dev->instances + inst_nr;
0593
0594 if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
0595 edac_device_printk(edac_dev, KERN_ERR,
0596 "INTERNAL ERROR: instance %d 'block' "
0597 "out of range (%d >= %d)\n",
0598 inst_nr, block_nr,
0599 instance->nr_blocks);
0600 return;
0601 }
0602
0603 if (instance->nr_blocks > 0) {
0604 block = instance->blocks + block_nr;
0605 block->counters.ue_count += count;
0606 }
0607
0608
0609 instance->counters.ue_count += count;
0610 edac_dev->counters.ue_count += count;
0611
0612 if (edac_device_get_log_ue(edac_dev))
0613 edac_device_printk(edac_dev, KERN_EMERG,
0614 "UE: %s instance: %s block: %s count: %d '%s'\n",
0615 edac_dev->ctl_name, instance->name,
0616 block ? block->name : "N/A", count, msg);
0617
0618 if (edac_device_get_panic_on_ue(edac_dev))
0619 panic("EDAC %s: UE instance: %s block %s count: %d '%s'\n",
0620 edac_dev->ctl_name, instance->name,
0621 block ? block->name : "N/A", count, msg);
0622 }
0623 EXPORT_SYMBOL_GPL(edac_device_handle_ue_count);