2 * edac_mc kernel module
3 * (C) 2005, 2006 Linux Networx (http://lnxi.com)
4 * This file may be distributed under the terms of the
5 * GNU General Public License.
7 * Written by Thayne Harbaugh
8 * Based on work by Dan Hollis <goemon at anime dot net> and others.
9 * http://www.anime.net/~goemon/linux-ecc/
11 * Modified by Dave Peterson and Doug Thompson
15 #include <linux/module.h>
16 #include <linux/proc_fs.h>
17 #include <linux/kernel.h>
18 #include <linux/types.h>
19 #include <linux/smp.h>
20 #include <linux/init.h>
21 #include <linux/sysctl.h>
22 #include <linux/highmem.h>
23 #include <linux/timer.h>
24 #include <linux/slab.h>
25 #include <linux/jiffies.h>
26 #include <linux/spinlock.h>
27 #include <linux/list.h>
28 #include <linux/ctype.h>
29 #include <linux/edac.h>
30 #include <asm/uaccess.h>
33 #include "edac_core.h"
34 #include "edac_module.h"
36 /* lock to memory controller's control array */
37 static DEFINE_MUTEX(mem_ctls_mutex);
38 static LIST_HEAD(mc_devices);
40 #ifdef CONFIG_EDAC_DEBUG
42 static void edac_mc_dump_channel(struct rank_info *chan)
44 debugf4("\tchannel = %p\n", chan);
45 debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
46 debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
47 debugf4("\tdimm->ce_count = %d\n", chan->dimm->ce_count);
48 debugf4("\tdimm->label = '%s'\n", chan->dimm->label);
49 debugf4("\tdimm->nr_pages = 0x%x\n", chan->dimm->nr_pages);
52 static void edac_mc_dump_csrow(struct csrow_info *csrow)
54 debugf4("\tcsrow = %p\n", csrow);
55 debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx);
56 debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page);
57 debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page);
58 debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask);
59 debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels);
60 debugf4("\tcsrow->channels = %p\n", csrow->channels);
61 debugf4("\tcsrow->mci = %p\n\n", csrow->mci);
64 static void edac_mc_dump_mci(struct mem_ctl_info *mci)
66 debugf3("\tmci = %p\n", mci);
67 debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap);
68 debugf3("\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap);
69 debugf3("\tmci->edac_cap = %lx\n", mci->edac_cap);
70 debugf4("\tmci->edac_check = %p\n", mci->edac_check);
71 debugf3("\tmci->nr_csrows = %d, csrows = %p\n",
72 mci->nr_csrows, mci->csrows);
73 debugf3("\tdev = %p\n", mci->dev);
74 debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name);
75 debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
78 #endif /* CONFIG_EDAC_DEBUG */
81 * keep those in sync with the enum mem_type
83 const char *edac_mem_types[] = {
85 "Reserved csrow type",
88 "Extended data out RAM",
89 "Burst Extended data out RAM",
90 "Single data rate SDRAM",
91 "Registered single data rate SDRAM",
92 "Double data rate SDRAM",
93 "Registered Double data rate SDRAM",
95 "Unbuffered DDR2 RAM",
96 "Fully buffered DDR2",
97 "Registered DDR2 RAM",
99 "Unbuffered DDR3 RAM",
100 "Registered DDR3 RAM",
102 EXPORT_SYMBOL_GPL(edac_mem_types);
105 * edac_align_ptr - Prepares the pointer offsets for a single-shot allocation
106 * @p: pointer to a pointer with the memory offset to be used. At
107 * return, this will be incremented to point to the next offset
108 * @size: Size of the data structure to be reserved
109 * @n_elems: Number of elements that should be reserved
111 * If 'size' is a constant, the compiler will optimize this whole function
112 * down to either a no-op or the addition of a constant to the value of '*p'.
114 * The 'p' pointer is absolutely needed to keep the proper advancing
115 * further in memory to the proper offsets when allocating the struct along
116 * with its embedded structs, as edac_device_alloc_ctl_info() does it
117 * above, for example.
119 * At return, the pointer 'p' will be incremented to be used on a next call
122 void *edac_align_ptr(void **p, unsigned size, int n_elems)
127 *p += size * n_elems;
130 * 'p' can possibly be an unaligned item X such that sizeof(X) is
131 * 'size'. Adjust 'p' so that its alignment is at least as
132 * stringent as what the compiler would provide for X and return
133 * the aligned result.
134 * Here we assume that the alignment of a "long long" is the most
135 * stringent alignment that the compiler will ever provide by default.
136 * As far as I know, this is a reasonable assumption.
138 if (size > sizeof(long))
139 align = sizeof(long long);
140 else if (size > sizeof(int))
141 align = sizeof(long);
142 else if (size > sizeof(short))
144 else if (size > sizeof(char))
145 align = sizeof(short);
156 return (void *)(((unsigned long)ptr) + align - r);
160 * edac_mc_alloc: Allocate a struct mem_ctl_info structure
161 * @size_pvt: size of private storage needed
162 * @nr_csrows: Number of CWROWS needed for this MC
163 * @nr_chans: Number of channels for the MC
165 * Everything is kmalloc'ed as one big chunk - more efficient.
166 * Only can be used if all structures have the same lifetime - otherwise
167 * you have to allocate and initialize your own structures.
169 * Use edac_mc_free() to free mc structures allocated by this function.
172 * NULL allocation failed
173 * struct mem_ctl_info pointer
175 struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
176 unsigned nr_chans, int edac_index)
179 struct mem_ctl_info *mci;
180 struct csrow_info *csi, *csrow;
181 struct rank_info *chi, *chp, *chan;
182 struct dimm_info *dimm;
188 /* Figure out the offsets of the various items from the start of an mc
189 * structure. We want the alignment of each item to be at least as
190 * stringent as what the compiler would provide if we could simply
191 * hardcode everything into a single struct.
193 mci = edac_align_ptr(&ptr, sizeof(*mci), 1);
194 csi = edac_align_ptr(&ptr, sizeof(*csi), nr_csrows);
195 chi = edac_align_ptr(&ptr, sizeof(*chi), nr_csrows * nr_chans);
196 dimm = edac_align_ptr(&ptr, sizeof(*dimm), nr_csrows * nr_chans);
197 pvt = edac_align_ptr(&ptr, sz_pvt, 1);
198 size = ((unsigned long)pvt) + sz_pvt;
200 mci = kzalloc(size, GFP_KERNEL);
204 /* Adjust pointers so they point within the memory we just allocated
205 * rather than an imaginary chunk of memory located at address 0.
207 csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
208 chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
209 dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm));
210 pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
212 /* setup index and various internal pointers */
213 mci->mc_idx = edac_index;
217 mci->nr_csrows = nr_csrows;
220 * For now, assumes that a per-csrow arrangement for dimms.
221 * This will be latter changed.
225 for (row = 0; row < nr_csrows; row++) {
227 csrow->csrow_idx = row;
229 csrow->nr_channels = nr_chans;
230 chp = &chi[row * nr_chans];
231 csrow->channels = chp;
233 for (chn = 0; chn < nr_chans; chn++) {
235 chan->chan_idx = chn;
238 mci->csrows[row].channels[chn].dimm = dimm;
240 dimm->csrow_channel = chn;
246 mci->op_state = OP_ALLOC;
247 INIT_LIST_HEAD(&mci->grp_kobj_list);
250 * Initialize the 'root' kobj for the edac_mc controller
252 err = edac_mc_register_sysfs_main_kobj(mci);
258 /* at this point, the root kobj is valid, and in order to
259 * 'free' the object, then the function:
260 * edac_mc_unregister_sysfs_main_kobj() must be called
261 * which will perform kobj unregistration and the actual free
262 * will occur during the kobject callback operation
266 EXPORT_SYMBOL_GPL(edac_mc_alloc);
270 * 'Free' a previously allocated 'mci' structure
271 * @mci: pointer to a struct mem_ctl_info structure
273 void edac_mc_free(struct mem_ctl_info *mci)
275 debugf1("%s()\n", __func__);
277 edac_mc_unregister_sysfs_main_kobj(mci);
279 /* free the mci instance memory here */
282 EXPORT_SYMBOL_GPL(edac_mc_free);
288 * scan list of controllers looking for the one that manages
290 * @dev: pointer to a struct device related with the MCI
292 struct mem_ctl_info *find_mci_by_dev(struct device *dev)
294 struct mem_ctl_info *mci;
295 struct list_head *item;
297 debugf3("%s()\n", __func__);
299 list_for_each(item, &mc_devices) {
300 mci = list_entry(item, struct mem_ctl_info, link);
308 EXPORT_SYMBOL_GPL(find_mci_by_dev);
311 * handler for EDAC to check if NMI type handler has asserted interrupt
313 static int edac_mc_assert_error_check_and_clear(void)
317 if (edac_op_state == EDAC_OPSTATE_POLL)
320 old_state = edac_err_assert;
327 * edac_mc_workq_function
328 * performs the operation scheduled by a workq request
330 static void edac_mc_workq_function(struct work_struct *work_req)
332 struct delayed_work *d_work = to_delayed_work(work_req);
333 struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work);
335 mutex_lock(&mem_ctls_mutex);
337 /* if this control struct has movd to offline state, we are done */
338 if (mci->op_state == OP_OFFLINE) {
339 mutex_unlock(&mem_ctls_mutex);
343 /* Only poll controllers that are running polled and have a check */
344 if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
345 mci->edac_check(mci);
347 mutex_unlock(&mem_ctls_mutex);
350 queue_delayed_work(edac_workqueue, &mci->work,
351 msecs_to_jiffies(edac_mc_get_poll_msec()));
355 * edac_mc_workq_setup
356 * initialize a workq item for this mci
357 * passing in the new delay period in msec
361 * called with the mem_ctls_mutex held
363 static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
365 debugf0("%s()\n", __func__);
367 /* if this instance is not in the POLL state, then simply return */
368 if (mci->op_state != OP_RUNNING_POLL)
371 INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
372 queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
376 * edac_mc_workq_teardown
377 * stop the workq processing on this mci
381 * called WITHOUT lock held
383 static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
387 if (mci->op_state != OP_RUNNING_POLL)
390 status = cancel_delayed_work(&mci->work);
392 debugf0("%s() not canceled, flush the queue\n",
395 /* workq instance might be running, wait for it */
396 flush_workqueue(edac_workqueue);
401 * edac_mc_reset_delay_period(unsigned long value)
403 * user space has updated our poll period value, need to
404 * reset our workq delays
406 void edac_mc_reset_delay_period(int value)
408 struct mem_ctl_info *mci;
409 struct list_head *item;
411 mutex_lock(&mem_ctls_mutex);
413 /* scan the list and turn off all workq timers, doing so under lock
415 list_for_each(item, &mc_devices) {
416 mci = list_entry(item, struct mem_ctl_info, link);
418 if (mci->op_state == OP_RUNNING_POLL)
419 cancel_delayed_work(&mci->work);
422 mutex_unlock(&mem_ctls_mutex);
425 /* re-walk the list, and reset the poll delay */
426 mutex_lock(&mem_ctls_mutex);
428 list_for_each(item, &mc_devices) {
429 mci = list_entry(item, struct mem_ctl_info, link);
431 edac_mc_workq_setup(mci, (unsigned long) value);
434 mutex_unlock(&mem_ctls_mutex);
439 /* Return 0 on success, 1 on failure.
440 * Before calling this function, caller must
441 * assign a unique value to mci->mc_idx.
445 * called with the mem_ctls_mutex lock held
447 static int add_mc_to_global_list(struct mem_ctl_info *mci)
449 struct list_head *item, *insert_before;
450 struct mem_ctl_info *p;
452 insert_before = &mc_devices;
454 p = find_mci_by_dev(mci->dev);
455 if (unlikely(p != NULL))
458 list_for_each(item, &mc_devices) {
459 p = list_entry(item, struct mem_ctl_info, link);
461 if (p->mc_idx >= mci->mc_idx) {
462 if (unlikely(p->mc_idx == mci->mc_idx))
465 insert_before = item;
470 list_add_tail_rcu(&mci->link, insert_before);
471 atomic_inc(&edac_handlers);
475 edac_printk(KERN_WARNING, EDAC_MC,
476 "%s (%s) %s %s already assigned %d\n", dev_name(p->dev),
477 edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
481 edac_printk(KERN_WARNING, EDAC_MC,
482 "bug in low-level driver: attempt to assign\n"
483 " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
487 static void del_mc_from_global_list(struct mem_ctl_info *mci)
489 atomic_dec(&edac_handlers);
490 list_del_rcu(&mci->link);
492 /* these are for safe removal of devices from global list while
493 * NMI handlers may be traversing list
496 INIT_LIST_HEAD(&mci->link);
500 * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'.
502 * If found, return a pointer to the structure.
505 * Caller must hold mem_ctls_mutex.
507 struct mem_ctl_info *edac_mc_find(int idx)
509 struct list_head *item;
510 struct mem_ctl_info *mci;
512 list_for_each(item, &mc_devices) {
513 mci = list_entry(item, struct mem_ctl_info, link);
515 if (mci->mc_idx >= idx) {
516 if (mci->mc_idx == idx)
525 EXPORT_SYMBOL(edac_mc_find);
528 * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
529 * create sysfs entries associated with mci structure
530 * @mci: pointer to the mci structure to be added to the list
531 * @mc_idx: A unique numeric identifier to be assigned to the 'mci' structure.
538 /* FIXME - should a warning be printed if no error detection? correction? */
539 int edac_mc_add_mc(struct mem_ctl_info *mci)
541 debugf0("%s()\n", __func__);
543 #ifdef CONFIG_EDAC_DEBUG
544 if (edac_debug_level >= 3)
545 edac_mc_dump_mci(mci);
547 if (edac_debug_level >= 4) {
550 for (i = 0; i < mci->nr_csrows; i++) {
553 edac_mc_dump_csrow(&mci->csrows[i]);
554 for (j = 0; j < mci->csrows[i].nr_channels; j++)
555 edac_mc_dump_channel(&mci->csrows[i].
560 mutex_lock(&mem_ctls_mutex);
562 if (add_mc_to_global_list(mci))
565 /* set load time so that error rate can be tracked */
566 mci->start_time = jiffies;
568 if (edac_create_sysfs_mci_device(mci)) {
569 edac_mc_printk(mci, KERN_WARNING,
570 "failed to create sysfs device\n");
574 /* If there IS a check routine, then we are running POLLED */
575 if (mci->edac_check != NULL) {
576 /* This instance is NOW RUNNING */
577 mci->op_state = OP_RUNNING_POLL;
579 edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
581 mci->op_state = OP_RUNNING_INTERRUPT;
584 /* Report action taken */
585 edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':"
586 " DEV %s\n", mci->mod_name, mci->ctl_name, edac_dev_name(mci));
588 mutex_unlock(&mem_ctls_mutex);
592 del_mc_from_global_list(mci);
595 mutex_unlock(&mem_ctls_mutex);
598 EXPORT_SYMBOL_GPL(edac_mc_add_mc);
601 * edac_mc_del_mc: Remove sysfs entries for specified mci structure and
602 * remove mci structure from global list
603 * @pdev: Pointer to 'struct device' representing mci structure to remove.
605 * Return pointer to removed mci structure, or NULL if device not found.
607 struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
609 struct mem_ctl_info *mci;
611 debugf0("%s()\n", __func__);
613 mutex_lock(&mem_ctls_mutex);
615 /* find the requested mci struct in the global list */
616 mci = find_mci_by_dev(dev);
618 mutex_unlock(&mem_ctls_mutex);
622 del_mc_from_global_list(mci);
623 mutex_unlock(&mem_ctls_mutex);
625 /* flush workq processes */
626 edac_mc_workq_teardown(mci);
628 /* marking MCI offline */
629 mci->op_state = OP_OFFLINE;
631 /* remove from sysfs */
632 edac_remove_sysfs_mci_device(mci);
634 edac_printk(KERN_INFO, EDAC_MC,
635 "Removed device %d for %s %s: DEV %s\n", mci->mc_idx,
636 mci->mod_name, mci->ctl_name, edac_dev_name(mci));
640 EXPORT_SYMBOL_GPL(edac_mc_del_mc);
642 static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
647 unsigned long flags = 0;
649 debugf3("%s()\n", __func__);
651 /* ECC error page was not in our memory. Ignore it. */
652 if (!pfn_valid(page))
655 /* Find the actual page structure then map it and fix */
656 pg = pfn_to_page(page);
659 local_irq_save(flags);
661 virt_addr = kmap_atomic(pg);
663 /* Perform architecture specific atomic scrub operation */
664 atomic_scrub(virt_addr + offset, size);
666 /* Unmap and complete */
667 kunmap_atomic(virt_addr);
670 local_irq_restore(flags);
673 /* FIXME - should return -1 */
674 int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
676 struct csrow_info *csrows = mci->csrows;
679 debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page);
682 for (i = 0; i < mci->nr_csrows; i++) {
683 struct csrow_info *csrow = &csrows[i];
685 for (j = 0; j < csrow->nr_channels; j++) {
686 struct dimm_info *dimm = csrow->channels[j].dimm;
692 debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) "
693 "mask(0x%lx)\n", mci->mc_idx, __func__,
694 csrow->first_page, page, csrow->last_page,
697 if ((page >= csrow->first_page) &&
698 (page <= csrow->last_page) &&
699 ((page & csrow->page_mask) ==
700 (csrow->first_page & csrow->page_mask))) {
707 edac_mc_printk(mci, KERN_ERR,
708 "could not look up page error address %lx\n",
709 (unsigned long)page);
713 EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
715 /* FIXME - setable log (warning/emerg) levels */
716 /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
717 void edac_mc_handle_ce(struct mem_ctl_info *mci,
718 unsigned long page_frame_number,
719 unsigned long offset_in_page, unsigned long syndrome,
720 int row, int channel, const char *msg)
722 unsigned long remapped_page;
726 debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
728 /* FIXME - maybe make panic on INTERNAL ERROR an option */
729 if (row >= mci->nr_csrows || row < 0) {
730 /* something is wrong */
731 edac_mc_printk(mci, KERN_ERR,
732 "INTERNAL ERROR: row out of range "
733 "(%d >= %d)\n", row, mci->nr_csrows);
734 edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
738 if (channel >= mci->csrows[row].nr_channels || channel < 0) {
739 /* something is wrong */
740 edac_mc_printk(mci, KERN_ERR,
741 "INTERNAL ERROR: channel out of range "
742 "(%d >= %d)\n", channel,
743 mci->csrows[row].nr_channels);
744 edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
748 label = mci->csrows[row].channels[channel].dimm->label;
749 grain = mci->csrows[row].channels[channel].dimm->grain;
751 if (edac_mc_get_log_ce())
752 /* FIXME - put in DIMM location */
753 edac_mc_printk(mci, KERN_WARNING,
754 "CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
755 "0x%lx, row %d, channel %d, label \"%s\": %s\n",
756 page_frame_number, offset_in_page,
757 grain, syndrome, row, channel,
761 mci->csrows[row].ce_count++;
762 mci->csrows[row].channels[channel].dimm->ce_count++;
763 mci->csrows[row].channels[channel].ce_count++;
765 if (mci->scrub_mode & SCRUB_SW_SRC) {
767 * Some MC's can remap memory so that it is still available
768 * at a different address when PCI devices map into memory.
769 * MC's that can't do this lose the memory where PCI devices
770 * are mapped. This mapping is MC dependent and so we call
771 * back into the MC driver for it to map the MC page to
772 * a physical (CPU) page which can then be mapped to a virtual
773 * page - which can then be scrubbed.
775 remapped_page = mci->ctl_page_to_phys ?
776 mci->ctl_page_to_phys(mci, page_frame_number) :
779 edac_mc_scrub_block(remapped_page, offset_in_page, grain);
782 EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
784 void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
786 if (edac_mc_get_log_ce())
787 edac_mc_printk(mci, KERN_WARNING,
788 "CE - no information available: %s\n", msg);
790 mci->ce_noinfo_count++;
793 EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
795 void edac_mc_handle_ue(struct mem_ctl_info *mci,
796 unsigned long page_frame_number,
797 unsigned long offset_in_page, int row, const char *msg)
799 int len = EDAC_MC_LABEL_LEN * 4;
800 char labels[len + 1];
807 debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
809 /* FIXME - maybe make panic on INTERNAL ERROR an option */
810 if (row >= mci->nr_csrows || row < 0) {
811 /* something is wrong */
812 edac_mc_printk(mci, KERN_ERR,
813 "INTERNAL ERROR: row out of range "
814 "(%d >= %d)\n", row, mci->nr_csrows);
815 edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
819 grain = mci->csrows[row].channels[0].dimm->grain;
820 label = mci->csrows[row].channels[0].dimm->label;
821 chars = snprintf(pos, len + 1, "%s", label);
825 for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0);
827 label = mci->csrows[row].channels[chan].dimm->label;
828 chars = snprintf(pos, len + 1, ":%s", label);
833 if (edac_mc_get_log_ue())
834 edac_mc_printk(mci, KERN_EMERG,
835 "UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
836 "labels \"%s\": %s\n", page_frame_number,
837 offset_in_page, grain, row, labels, msg);
839 if (edac_mc_get_panic_on_ue())
840 panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
841 "row %d, labels \"%s\": %s\n", mci->mc_idx,
842 page_frame_number, offset_in_page,
843 grain, row, labels, msg);
846 mci->csrows[row].ue_count++;
848 EXPORT_SYMBOL_GPL(edac_mc_handle_ue);
850 void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
852 if (edac_mc_get_panic_on_ue())
853 panic("EDAC MC%d: Uncorrected Error", mci->mc_idx);
855 if (edac_mc_get_log_ue())
856 edac_mc_printk(mci, KERN_WARNING,
857 "UE - no information available: %s\n", msg);
858 mci->ue_noinfo_count++;
861 EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
863 /*************************************************************
864 * On Fully Buffered DIMM modules, this help function is
865 * called to process UE events
867 void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
869 unsigned int channela,
870 unsigned int channelb, char *msg)
872 int len = EDAC_MC_LABEL_LEN * 4;
873 char labels[len + 1];
878 if (csrow >= mci->nr_csrows) {
879 /* something is wrong */
880 edac_mc_printk(mci, KERN_ERR,
881 "INTERNAL ERROR: row out of range (%d >= %d)\n",
882 csrow, mci->nr_csrows);
883 edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
887 if (channela >= mci->csrows[csrow].nr_channels) {
888 /* something is wrong */
889 edac_mc_printk(mci, KERN_ERR,
890 "INTERNAL ERROR: channel-a out of range "
892 channela, mci->csrows[csrow].nr_channels);
893 edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
897 if (channelb >= mci->csrows[csrow].nr_channels) {
898 /* something is wrong */
899 edac_mc_printk(mci, KERN_ERR,
900 "INTERNAL ERROR: channel-b out of range "
902 channelb, mci->csrows[csrow].nr_channels);
903 edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
908 mci->csrows[csrow].ue_count++;
910 /* Generate the DIMM labels from the specified channels */
911 label = mci->csrows[csrow].channels[channela].dimm->label;
912 chars = snprintf(pos, len + 1, "%s", label);
916 chars = snprintf(pos, len + 1, "-%s",
917 mci->csrows[csrow].channels[channelb].dimm->label);
919 if (edac_mc_get_log_ue())
920 edac_mc_printk(mci, KERN_EMERG,
921 "UE row %d, channel-a= %d channel-b= %d "
922 "labels \"%s\": %s\n", csrow, channela, channelb,
925 if (edac_mc_get_panic_on_ue())
926 panic("UE row %d, channel-a= %d channel-b= %d "
927 "labels \"%s\": %s\n", csrow, channela,
928 channelb, labels, msg);
930 EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
932 /*************************************************************
933 * On Fully Buffered DIMM modules, this help function is
934 * called to process CE events
936 void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
937 unsigned int csrow, unsigned int channel, char *msg)
941 /* Ensure boundary values */
942 if (csrow >= mci->nr_csrows) {
943 /* something is wrong */
944 edac_mc_printk(mci, KERN_ERR,
945 "INTERNAL ERROR: row out of range (%d >= %d)\n",
946 csrow, mci->nr_csrows);
947 edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
950 if (channel >= mci->csrows[csrow].nr_channels) {
951 /* something is wrong */
952 edac_mc_printk(mci, KERN_ERR,
953 "INTERNAL ERROR: channel out of range (%d >= %d)\n",
954 channel, mci->csrows[csrow].nr_channels);
955 edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
959 label = mci->csrows[csrow].channels[channel].dimm->label;
961 if (edac_mc_get_log_ce())
962 /* FIXME - put in DIMM location */
963 edac_mc_printk(mci, KERN_WARNING,
964 "CE row %d, channel %d, label \"%s\": %s\n",
965 csrow, channel, label, msg);
968 mci->csrows[csrow].ce_count++;
969 mci->csrows[csrow].channels[channel].dimm->ce_count++;
970 mci->csrows[csrow].channels[channel].ce_count++;
972 EXPORT_SYMBOL(edac_mc_handle_fbd_ce);