Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/edac/edac_device.c
15109 views
1
2
/*
3
* edac_device.c
4
* (C) 2007 www.douglaskthompson.com
5
*
6
* This file may be distributed under the terms of the
7
* GNU General Public License.
8
*
9
* Written by Doug Thompson <[email protected]>
10
*
11
* edac_device API implementation
12
* 19 Jan 2007
13
*/
14
15
#include <linux/module.h>
16
#include <linux/types.h>
17
#include <linux/smp.h>
18
#include <linux/init.h>
19
#include <linux/sysctl.h>
20
#include <linux/highmem.h>
21
#include <linux/timer.h>
22
#include <linux/slab.h>
23
#include <linux/jiffies.h>
24
#include <linux/spinlock.h>
25
#include <linux/list.h>
26
#include <linux/sysdev.h>
27
#include <linux/ctype.h>
28
#include <linux/workqueue.h>
29
#include <asm/uaccess.h>
30
#include <asm/page.h>
31
32
#include "edac_core.h"
33
#include "edac_module.h"
34
35
/* lock for the list: 'edac_device_list', manipulation of this list
36
* is protected by the 'device_ctls_mutex' lock
37
*/
38
static DEFINE_MUTEX(device_ctls_mutex);
39
static LIST_HEAD(edac_device_list);
40
41
#ifdef CONFIG_EDAC_DEBUG
42
static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
43
{
44
debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev, edac_dev->dev_idx);
45
debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
46
debugf3("\tdev = %p\n", edac_dev->dev);
47
debugf3("\tmod_name:ctl_name = %s:%s\n",
48
edac_dev->mod_name, edac_dev->ctl_name);
49
debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info);
50
}
51
#endif /* CONFIG_EDAC_DEBUG */
52
53
54
/*
55
* edac_device_alloc_ctl_info()
56
* Allocate a new edac device control info structure
57
*
58
* The control structure is allocated in complete chunk
59
* from the OS. It is in turn sub allocated to the
60
* various objects that compose the struture
61
*
62
* The structure has a 'nr_instance' array within itself.
63
* Each instance represents a major component
64
* Example: L1 cache and L2 cache are 2 instance components
65
*
66
* Within each instance is an array of 'nr_blocks' blockoffsets
67
*/
68
struct edac_device_ctl_info *edac_device_alloc_ctl_info(
69
unsigned sz_private,
70
char *edac_device_name, unsigned nr_instances,
71
char *edac_block_name, unsigned nr_blocks,
72
unsigned offset_value, /* zero, 1, or other based offset */
73
struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib,
74
int device_index)
75
{
76
struct edac_device_ctl_info *dev_ctl;
77
struct edac_device_instance *dev_inst, *inst;
78
struct edac_device_block *dev_blk, *blk_p, *blk;
79
struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
80
unsigned total_size;
81
unsigned count;
82
unsigned instance, block, attr;
83
void *pvt;
84
int err;
85
86
debugf4("%s() instances=%d blocks=%d\n",
87
__func__, nr_instances, nr_blocks);
88
89
/* Calculate the size of memory we need to allocate AND
90
* determine the offsets of the various item arrays
91
* (instance,block,attrib) from the start of an allocated structure.
92
* We want the alignment of each item (instance,block,attrib)
93
* to be at least as stringent as what the compiler would
94
* provide if we could simply hardcode everything into a single struct.
95
*/
96
dev_ctl = (struct edac_device_ctl_info *)NULL;
97
98
/* Calc the 'end' offset past end of ONE ctl_info structure
99
* which will become the start of the 'instance' array
100
*/
101
dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst));
102
103
/* Calc the 'end' offset past the instance array within the ctl_info
104
* which will become the start of the block array
105
*/
106
dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk));
107
108
/* Calc the 'end' offset past the dev_blk array
109
* which will become the start of the attrib array, if any.
110
*/
111
count = nr_instances * nr_blocks;
112
dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib));
113
114
/* Check for case of when an attribute array is specified */
115
if (nr_attrib > 0) {
116
/* calc how many nr_attrib we need */
117
count *= nr_attrib;
118
119
/* Calc the 'end' offset past the attributes array */
120
pvt = edac_align_ptr(&dev_attrib[count], sz_private);
121
} else {
122
/* no attribute array specificed */
123
pvt = edac_align_ptr(dev_attrib, sz_private);
124
}
125
126
/* 'pvt' now points to where the private data area is.
127
* At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
128
* is baselined at ZERO
129
*/
130
total_size = ((unsigned long)pvt) + sz_private;
131
132
/* Allocate the amount of memory for the set of control structures */
133
dev_ctl = kzalloc(total_size, GFP_KERNEL);
134
if (dev_ctl == NULL)
135
return NULL;
136
137
/* Adjust pointers so they point within the actual memory we
138
* just allocated rather than an imaginary chunk of memory
139
* located at address 0.
140
* 'dev_ctl' points to REAL memory, while the others are
141
* ZERO based and thus need to be adjusted to point within
142
* the allocated memory.
143
*/
144
dev_inst = (struct edac_device_instance *)
145
(((char *)dev_ctl) + ((unsigned long)dev_inst));
146
dev_blk = (struct edac_device_block *)
147
(((char *)dev_ctl) + ((unsigned long)dev_blk));
148
dev_attrib = (struct edac_dev_sysfs_block_attribute *)
149
(((char *)dev_ctl) + ((unsigned long)dev_attrib));
150
pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL;
151
152
/* Begin storing the information into the control info structure */
153
dev_ctl->dev_idx = device_index;
154
dev_ctl->nr_instances = nr_instances;
155
dev_ctl->instances = dev_inst;
156
dev_ctl->pvt_info = pvt;
157
158
/* Default logging of CEs and UEs */
159
dev_ctl->log_ce = 1;
160
dev_ctl->log_ue = 1;
161
162
/* Name of this edac device */
163
snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
164
165
debugf4("%s() edac_dev=%p next after end=%p\n",
166
__func__, dev_ctl, pvt + sz_private );
167
168
/* Initialize every Instance */
169
for (instance = 0; instance < nr_instances; instance++) {
170
inst = &dev_inst[instance];
171
inst->ctl = dev_ctl;
172
inst->nr_blocks = nr_blocks;
173
blk_p = &dev_blk[instance * nr_blocks];
174
inst->blocks = blk_p;
175
176
/* name of this instance */
177
snprintf(inst->name, sizeof(inst->name),
178
"%s%u", edac_device_name, instance);
179
180
/* Initialize every block in each instance */
181
for (block = 0; block < nr_blocks; block++) {
182
blk = &blk_p[block];
183
blk->instance = inst;
184
snprintf(blk->name, sizeof(blk->name),
185
"%s%d", edac_block_name, block+offset_value);
186
187
debugf4("%s() instance=%d inst_p=%p block=#%d "
188
"block_p=%p name='%s'\n",
189
__func__, instance, inst, block,
190
blk, blk->name);
191
192
/* if there are NO attributes OR no attribute pointer
193
* then continue on to next block iteration
194
*/
195
if ((nr_attrib == 0) || (attrib_spec == NULL))
196
continue;
197
198
/* setup the attribute array for this block */
199
blk->nr_attribs = nr_attrib;
200
attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
201
blk->block_attributes = attrib_p;
202
203
debugf4("%s() THIS BLOCK_ATTRIB=%p\n",
204
__func__, blk->block_attributes);
205
206
/* Initialize every user specified attribute in this
207
* block with the data the caller passed in
208
* Each block gets its own copy of pointers,
209
* and its unique 'value'
210
*/
211
for (attr = 0; attr < nr_attrib; attr++) {
212
attrib = &attrib_p[attr];
213
214
/* populate the unique per attrib
215
* with the code pointers and info
216
*/
217
attrib->attr = attrib_spec[attr].attr;
218
attrib->show = attrib_spec[attr].show;
219
attrib->store = attrib_spec[attr].store;
220
221
attrib->block = blk; /* up link */
222
223
debugf4("%s() alloc-attrib=%p attrib_name='%s' "
224
"attrib-spec=%p spec-name=%s\n",
225
__func__, attrib, attrib->attr.name,
226
&attrib_spec[attr],
227
attrib_spec[attr].attr.name
228
);
229
}
230
}
231
}
232
233
/* Mark this instance as merely ALLOCATED */
234
dev_ctl->op_state = OP_ALLOC;
235
236
/*
237
* Initialize the 'root' kobj for the edac_device controller
238
*/
239
err = edac_device_register_sysfs_main_kobj(dev_ctl);
240
if (err) {
241
kfree(dev_ctl);
242
return NULL;
243
}
244
245
/* at this point, the root kobj is valid, and in order to
246
* 'free' the object, then the function:
247
* edac_device_unregister_sysfs_main_kobj() must be called
248
* which will perform kobj unregistration and the actual free
249
* will occur during the kobject callback operation
250
*/
251
252
return dev_ctl;
253
}
254
EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
255
256
/*
257
* edac_device_free_ctl_info()
258
* frees the memory allocated by the edac_device_alloc_ctl_info()
259
* function
260
*/
261
void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info)
262
{
263
edac_device_unregister_sysfs_main_kobj(ctl_info);
264
}
265
EXPORT_SYMBOL_GPL(edac_device_free_ctl_info);
266
267
/*
268
* find_edac_device_by_dev
269
* scans the edac_device list for a specific 'struct device *'
270
*
271
* lock to be held prior to call: device_ctls_mutex
272
*
273
* Return:
274
* pointer to control structure managing 'dev'
275
* NULL if not found on list
276
*/
277
static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev)
278
{
279
struct edac_device_ctl_info *edac_dev;
280
struct list_head *item;
281
282
debugf0("%s()\n", __func__);
283
284
list_for_each(item, &edac_device_list) {
285
edac_dev = list_entry(item, struct edac_device_ctl_info, link);
286
287
if (edac_dev->dev == dev)
288
return edac_dev;
289
}
290
291
return NULL;
292
}
293
294
/*
295
* add_edac_dev_to_global_list
296
* Before calling this function, caller must
297
* assign a unique value to edac_dev->dev_idx.
298
*
299
* lock to be held prior to call: device_ctls_mutex
300
*
301
* Return:
302
* 0 on success
303
* 1 on failure.
304
*/
305
static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev)
306
{
307
struct list_head *item, *insert_before;
308
struct edac_device_ctl_info *rover;
309
310
insert_before = &edac_device_list;
311
312
/* Determine if already on the list */
313
rover = find_edac_device_by_dev(edac_dev->dev);
314
if (unlikely(rover != NULL))
315
goto fail0;
316
317
/* Insert in ascending order by 'dev_idx', so find position */
318
list_for_each(item, &edac_device_list) {
319
rover = list_entry(item, struct edac_device_ctl_info, link);
320
321
if (rover->dev_idx >= edac_dev->dev_idx) {
322
if (unlikely(rover->dev_idx == edac_dev->dev_idx))
323
goto fail1;
324
325
insert_before = item;
326
break;
327
}
328
}
329
330
list_add_tail_rcu(&edac_dev->link, insert_before);
331
return 0;
332
333
fail0:
334
edac_printk(KERN_WARNING, EDAC_MC,
335
"%s (%s) %s %s already assigned %d\n",
336
dev_name(rover->dev), edac_dev_name(rover),
337
rover->mod_name, rover->ctl_name, rover->dev_idx);
338
return 1;
339
340
fail1:
341
edac_printk(KERN_WARNING, EDAC_MC,
342
"bug in low-level driver: attempt to assign\n"
343
" duplicate dev_idx %d in %s()\n", rover->dev_idx,
344
__func__);
345
return 1;
346
}
347
348
/*
349
* del_edac_device_from_global_list
350
*/
351
static void del_edac_device_from_global_list(struct edac_device_ctl_info
352
*edac_device)
353
{
354
list_del_rcu(&edac_device->link);
355
356
/* these are for safe removal of devices from global list while
357
* NMI handlers may be traversing list
358
*/
359
synchronize_rcu();
360
INIT_LIST_HEAD(&edac_device->link);
361
}
362
363
/*
364
* edac_device_workq_function
365
* performs the operation scheduled by a workq request
366
*
367
* this workq is embedded within an edac_device_ctl_info
368
* structure, that needs to be polled for possible error events.
369
*
370
* This operation is to acquire the list mutex lock
371
* (thus preventing insertation or deletion)
372
* and then call the device's poll function IFF this device is
373
* running polled and there is a poll function defined.
374
*/
375
static void edac_device_workq_function(struct work_struct *work_req)
376
{
377
struct delayed_work *d_work = to_delayed_work(work_req);
378
struct edac_device_ctl_info *edac_dev = to_edac_device_ctl_work(d_work);
379
380
mutex_lock(&device_ctls_mutex);
381
382
/* If we are being removed, bail out immediately */
383
if (edac_dev->op_state == OP_OFFLINE) {
384
mutex_unlock(&device_ctls_mutex);
385
return;
386
}
387
388
/* Only poll controllers that are running polled and have a check */
389
if ((edac_dev->op_state == OP_RUNNING_POLL) &&
390
(edac_dev->edac_check != NULL)) {
391
edac_dev->edac_check(edac_dev);
392
}
393
394
mutex_unlock(&device_ctls_mutex);
395
396
/* Reschedule the workq for the next time period to start again
397
* if the number of msec is for 1 sec, then adjust to the next
398
* whole one second to save timers fireing all over the period
399
* between integral seconds
400
*/
401
if (edac_dev->poll_msec == 1000)
402
queue_delayed_work(edac_workqueue, &edac_dev->work,
403
round_jiffies_relative(edac_dev->delay));
404
else
405
queue_delayed_work(edac_workqueue, &edac_dev->work,
406
edac_dev->delay);
407
}
408
409
/*
410
* edac_device_workq_setup
411
* initialize a workq item for this edac_device instance
412
* passing in the new delay period in msec
413
*/
414
void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
415
unsigned msec)
416
{
417
debugf0("%s()\n", __func__);
418
419
/* take the arg 'msec' and set it into the control structure
420
* to used in the time period calculation
421
* then calc the number of jiffies that represents
422
*/
423
edac_dev->poll_msec = msec;
424
edac_dev->delay = msecs_to_jiffies(msec);
425
426
INIT_DELAYED_WORK(&edac_dev->work, edac_device_workq_function);
427
428
/* optimize here for the 1 second case, which will be normal value, to
429
* fire ON the 1 second time event. This helps reduce all sorts of
430
* timers firing on sub-second basis, while they are happy
431
* to fire together on the 1 second exactly
432
*/
433
if (edac_dev->poll_msec == 1000)
434
queue_delayed_work(edac_workqueue, &edac_dev->work,
435
round_jiffies_relative(edac_dev->delay));
436
else
437
queue_delayed_work(edac_workqueue, &edac_dev->work,
438
edac_dev->delay);
439
}
440
441
/*
442
* edac_device_workq_teardown
443
* stop the workq processing on this edac_dev
444
*/
445
void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
446
{
447
int status;
448
449
status = cancel_delayed_work(&edac_dev->work);
450
if (status == 0) {
451
/* workq instance might be running, wait for it */
452
flush_workqueue(edac_workqueue);
453
}
454
}
455
456
/*
457
* edac_device_reset_delay_period
458
*
459
* need to stop any outstanding workq queued up at this time
460
* because we will be resetting the sleep time.
461
* Then restart the workq on the new delay
462
*/
463
void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
464
unsigned long value)
465
{
466
/* cancel the current workq request, without the mutex lock */
467
edac_device_workq_teardown(edac_dev);
468
469
/* acquire the mutex before doing the workq setup */
470
mutex_lock(&device_ctls_mutex);
471
472
/* restart the workq request, with new delay value */
473
edac_device_workq_setup(edac_dev, value);
474
475
mutex_unlock(&device_ctls_mutex);
476
}
477
478
/*
479
* edac_device_alloc_index: Allocate a unique device index number
480
*
481
* Return:
482
* allocated index number
483
*/
484
int edac_device_alloc_index(void)
485
{
486
static atomic_t device_indexes = ATOMIC_INIT(0);
487
488
return atomic_inc_return(&device_indexes) - 1;
489
}
490
EXPORT_SYMBOL_GPL(edac_device_alloc_index);
491
492
/**
493
* edac_device_add_device: Insert the 'edac_dev' structure into the
494
* edac_device global list and create sysfs entries associated with
495
* edac_device structure.
496
* @edac_device: pointer to the edac_device structure to be added to the list
497
* 'edac_device' structure.
498
*
499
* Return:
500
* 0 Success
501
* !0 Failure
502
*/
503
int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
504
{
505
debugf0("%s()\n", __func__);
506
507
#ifdef CONFIG_EDAC_DEBUG
508
if (edac_debug_level >= 3)
509
edac_device_dump_device(edac_dev);
510
#endif
511
mutex_lock(&device_ctls_mutex);
512
513
if (add_edac_dev_to_global_list(edac_dev))
514
goto fail0;
515
516
/* set load time so that error rate can be tracked */
517
edac_dev->start_time = jiffies;
518
519
/* create this instance's sysfs entries */
520
if (edac_device_create_sysfs(edac_dev)) {
521
edac_device_printk(edac_dev, KERN_WARNING,
522
"failed to create sysfs device\n");
523
goto fail1;
524
}
525
526
/* If there IS a check routine, then we are running POLLED */
527
if (edac_dev->edac_check != NULL) {
528
/* This instance is NOW RUNNING */
529
edac_dev->op_state = OP_RUNNING_POLL;
530
531
/*
532
* enable workq processing on this instance,
533
* default = 1000 msec
534
*/
535
edac_device_workq_setup(edac_dev, 1000);
536
} else {
537
edac_dev->op_state = OP_RUNNING_INTERRUPT;
538
}
539
540
/* Report action taken */
541
edac_device_printk(edac_dev, KERN_INFO,
542
"Giving out device to module '%s' controller "
543
"'%s': DEV '%s' (%s)\n",
544
edac_dev->mod_name,
545
edac_dev->ctl_name,
546
edac_dev_name(edac_dev),
547
edac_op_state_to_string(edac_dev->op_state));
548
549
mutex_unlock(&device_ctls_mutex);
550
return 0;
551
552
fail1:
553
/* Some error, so remove the entry from the lsit */
554
del_edac_device_from_global_list(edac_dev);
555
556
fail0:
557
mutex_unlock(&device_ctls_mutex);
558
return 1;
559
}
560
EXPORT_SYMBOL_GPL(edac_device_add_device);
561
562
/**
563
* edac_device_del_device:
564
* Remove sysfs entries for specified edac_device structure and
565
* then remove edac_device structure from global list
566
*
567
* @pdev:
568
* Pointer to 'struct device' representing edac_device
569
* structure to remove.
570
*
571
* Return:
572
* Pointer to removed edac_device structure,
573
* OR NULL if device not found.
574
*/
575
struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
576
{
577
struct edac_device_ctl_info *edac_dev;
578
579
debugf0("%s()\n", __func__);
580
581
mutex_lock(&device_ctls_mutex);
582
583
/* Find the structure on the list, if not there, then leave */
584
edac_dev = find_edac_device_by_dev(dev);
585
if (edac_dev == NULL) {
586
mutex_unlock(&device_ctls_mutex);
587
return NULL;
588
}
589
590
/* mark this instance as OFFLINE */
591
edac_dev->op_state = OP_OFFLINE;
592
593
/* deregister from global list */
594
del_edac_device_from_global_list(edac_dev);
595
596
mutex_unlock(&device_ctls_mutex);
597
598
/* clear workq processing on this instance */
599
edac_device_workq_teardown(edac_dev);
600
601
/* Tear down the sysfs entries for this instance */
602
edac_device_remove_sysfs(edac_dev);
603
604
edac_printk(KERN_INFO, EDAC_MC,
605
"Removed device %d for %s %s: DEV %s\n",
606
edac_dev->dev_idx,
607
edac_dev->mod_name, edac_dev->ctl_name, edac_dev_name(edac_dev));
608
609
return edac_dev;
610
}
611
EXPORT_SYMBOL_GPL(edac_device_del_device);
612
613
static inline int edac_device_get_log_ce(struct edac_device_ctl_info *edac_dev)
614
{
615
return edac_dev->log_ce;
616
}
617
618
static inline int edac_device_get_log_ue(struct edac_device_ctl_info *edac_dev)
619
{
620
return edac_dev->log_ue;
621
}
622
623
static inline int edac_device_get_panic_on_ue(struct edac_device_ctl_info
624
*edac_dev)
625
{
626
return edac_dev->panic_on_ue;
627
}
628
629
/*
630
* edac_device_handle_ce
631
* perform a common output and handling of an 'edac_dev' CE event
632
*/
633
void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
634
int inst_nr, int block_nr, const char *msg)
635
{
636
struct edac_device_instance *instance;
637
struct edac_device_block *block = NULL;
638
639
if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
640
edac_device_printk(edac_dev, KERN_ERR,
641
"INTERNAL ERROR: 'instance' out of range "
642
"(%d >= %d)\n", inst_nr,
643
edac_dev->nr_instances);
644
return;
645
}
646
647
instance = edac_dev->instances + inst_nr;
648
649
if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
650
edac_device_printk(edac_dev, KERN_ERR,
651
"INTERNAL ERROR: instance %d 'block' "
652
"out of range (%d >= %d)\n",
653
inst_nr, block_nr,
654
instance->nr_blocks);
655
return;
656
}
657
658
if (instance->nr_blocks > 0) {
659
block = instance->blocks + block_nr;
660
block->counters.ce_count++;
661
}
662
663
/* Propagate the count up the 'totals' tree */
664
instance->counters.ce_count++;
665
edac_dev->counters.ce_count++;
666
667
if (edac_device_get_log_ce(edac_dev))
668
edac_device_printk(edac_dev, KERN_WARNING,
669
"CE: %s instance: %s block: %s '%s'\n",
670
edac_dev->ctl_name, instance->name,
671
block ? block->name : "N/A", msg);
672
}
673
EXPORT_SYMBOL_GPL(edac_device_handle_ce);
674
675
/*
676
* edac_device_handle_ue
677
* perform a common output and handling of an 'edac_dev' UE event
678
*/
679
void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
680
int inst_nr, int block_nr, const char *msg)
681
{
682
struct edac_device_instance *instance;
683
struct edac_device_block *block = NULL;
684
685
if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
686
edac_device_printk(edac_dev, KERN_ERR,
687
"INTERNAL ERROR: 'instance' out of range "
688
"(%d >= %d)\n", inst_nr,
689
edac_dev->nr_instances);
690
return;
691
}
692
693
instance = edac_dev->instances + inst_nr;
694
695
if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
696
edac_device_printk(edac_dev, KERN_ERR,
697
"INTERNAL ERROR: instance %d 'block' "
698
"out of range (%d >= %d)\n",
699
inst_nr, block_nr,
700
instance->nr_blocks);
701
return;
702
}
703
704
if (instance->nr_blocks > 0) {
705
block = instance->blocks + block_nr;
706
block->counters.ue_count++;
707
}
708
709
/* Propagate the count up the 'totals' tree */
710
instance->counters.ue_count++;
711
edac_dev->counters.ue_count++;
712
713
if (edac_device_get_log_ue(edac_dev))
714
edac_device_printk(edac_dev, KERN_EMERG,
715
"UE: %s instance: %s block: %s '%s'\n",
716
edac_dev->ctl_name, instance->name,
717
block ? block->name : "N/A", msg);
718
719
if (edac_device_get_panic_on_ue(edac_dev))
720
panic("EDAC %s: UE instance: %s block %s '%s'\n",
721
edac_dev->ctl_name, instance->name,
722
block ? block->name : "N/A", msg);
723
}
724
EXPORT_SYMBOL_GPL(edac_device_handle_ue);
725
726