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->ce_count = %d\n", chan->ce_count);
47 debugf4("\tchannel->label = '%s'\n", chan->dimm->label);
48 debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
51 static void edac_mc_dump_csrow(struct csrow_info *csrow)
53 debugf4("\tcsrow = %p\n", csrow);
54 debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx);
55 debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page);
56 debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page);
57 debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask);
58 debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages);
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);
104 /* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'.
105 * Adjust 'ptr' so that its alignment is at least as stringent as what the
106 * compiler would provide for X and return the aligned result.
108 * If 'size' is a constant, the compiler will optimize this whole function
109 * down to either a no-op or the addition of a constant to the value of 'ptr'.
111 void *edac_align_ptr(void *ptr, unsigned size)
115 /* Here we assume that the alignment of a "long long" is the most
116 * stringent alignment that the compiler will ever provide by default.
117 * As far as I know, this is a reasonable assumption.
119 if (size > sizeof(long))
120 align = sizeof(long long);
121 else if (size > sizeof(int))
122 align = sizeof(long);
123 else if (size > sizeof(short))
125 else if (size > sizeof(char))
126 align = sizeof(short);
135 return (void *)(((unsigned long)ptr) + align - r);
139 * edac_mc_alloc: Allocate a struct mem_ctl_info structure
140 * @size_pvt: size of private storage needed
141 * @nr_csrows: Number of CWROWS needed for this MC
142 * @nr_chans: Number of channels for the MC
144 * Everything is kmalloc'ed as one big chunk - more efficient.
145 * Only can be used if all structures have the same lifetime - otherwise
146 * you have to allocate and initialize your own structures.
148 * Use edac_mc_free() to free mc structures allocated by this function.
151 * NULL allocation failed
152 * struct mem_ctl_info pointer
154 struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
155 unsigned nr_chans, int edac_index)
157 struct mem_ctl_info *mci;
158 struct csrow_info *csi, *csrow;
159 struct rank_info *chi, *chp, *chan;
160 struct dimm_info *dimm;
166 /* Figure out the offsets of the various items from the start of an mc
167 * structure. We want the alignment of each item to be at least as
168 * stringent as what the compiler would provide if we could simply
169 * hardcode everything into a single struct.
171 mci = (struct mem_ctl_info *)0;
172 csi = edac_align_ptr(&mci[1], sizeof(*csi));
173 chi = edac_align_ptr(&csi[nr_csrows], sizeof(*chi));
174 dimm = edac_align_ptr(&chi[nr_chans * nr_csrows], sizeof(*dimm));
175 pvt = edac_align_ptr(&dimm[nr_chans * nr_csrows], sz_pvt);
176 size = ((unsigned long)pvt) + sz_pvt;
178 mci = kzalloc(size, GFP_KERNEL);
182 /* Adjust pointers so they point within the memory we just allocated
183 * rather than an imaginary chunk of memory located at address 0.
185 csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
186 chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
187 dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm));
188 pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
190 /* setup index and various internal pointers */
191 mci->mc_idx = edac_index;
195 mci->nr_csrows = nr_csrows;
198 * For now, assumes that a per-csrow arrangement for dimms.
199 * This will be latter changed.
203 for (row = 0; row < nr_csrows; row++) {
205 csrow->csrow_idx = row;
207 csrow->nr_channels = nr_chans;
208 chp = &chi[row * nr_chans];
209 csrow->channels = chp;
211 for (chn = 0; chn < nr_chans; chn++) {
213 chan->chan_idx = chn;
216 mci->csrows[row].channels[chn].dimm = dimm;
218 dimm->csrow_channel = chn;
224 mci->op_state = OP_ALLOC;
225 INIT_LIST_HEAD(&mci->grp_kobj_list);
228 * Initialize the 'root' kobj for the edac_mc controller
230 err = edac_mc_register_sysfs_main_kobj(mci);
236 /* at this point, the root kobj is valid, and in order to
237 * 'free' the object, then the function:
238 * edac_mc_unregister_sysfs_main_kobj() must be called
239 * which will perform kobj unregistration and the actual free
240 * will occur during the kobject callback operation
244 EXPORT_SYMBOL_GPL(edac_mc_alloc);
248 * 'Free' a previously allocated 'mci' structure
249 * @mci: pointer to a struct mem_ctl_info structure
251 void edac_mc_free(struct mem_ctl_info *mci)
253 debugf1("%s()\n", __func__);
255 edac_mc_unregister_sysfs_main_kobj(mci);
257 /* free the mci instance memory here */
260 EXPORT_SYMBOL_GPL(edac_mc_free);
266 * scan list of controllers looking for the one that manages
268 * @dev: pointer to a struct device related with the MCI
270 struct mem_ctl_info *find_mci_by_dev(struct device *dev)
272 struct mem_ctl_info *mci;
273 struct list_head *item;
275 debugf3("%s()\n", __func__);
277 list_for_each(item, &mc_devices) {
278 mci = list_entry(item, struct mem_ctl_info, link);
286 EXPORT_SYMBOL_GPL(find_mci_by_dev);
289 * handler for EDAC to check if NMI type handler has asserted interrupt
291 static int edac_mc_assert_error_check_and_clear(void)
295 if (edac_op_state == EDAC_OPSTATE_POLL)
298 old_state = edac_err_assert;
305 * edac_mc_workq_function
306 * performs the operation scheduled by a workq request
308 static void edac_mc_workq_function(struct work_struct *work_req)
310 struct delayed_work *d_work = to_delayed_work(work_req);
311 struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work);
313 mutex_lock(&mem_ctls_mutex);
315 /* if this control struct has movd to offline state, we are done */
316 if (mci->op_state == OP_OFFLINE) {
317 mutex_unlock(&mem_ctls_mutex);
321 /* Only poll controllers that are running polled and have a check */
322 if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
323 mci->edac_check(mci);
325 mutex_unlock(&mem_ctls_mutex);
328 queue_delayed_work(edac_workqueue, &mci->work,
329 msecs_to_jiffies(edac_mc_get_poll_msec()));
333 * edac_mc_workq_setup
334 * initialize a workq item for this mci
335 * passing in the new delay period in msec
339 * called with the mem_ctls_mutex held
341 static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
343 debugf0("%s()\n", __func__);
345 /* if this instance is not in the POLL state, then simply return */
346 if (mci->op_state != OP_RUNNING_POLL)
349 INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
350 queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
354 * edac_mc_workq_teardown
355 * stop the workq processing on this mci
359 * called WITHOUT lock held
361 static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
365 if (mci->op_state != OP_RUNNING_POLL)
368 status = cancel_delayed_work(&mci->work);
370 debugf0("%s() not canceled, flush the queue\n",
373 /* workq instance might be running, wait for it */
374 flush_workqueue(edac_workqueue);
379 * edac_mc_reset_delay_period(unsigned long value)
381 * user space has updated our poll period value, need to
382 * reset our workq delays
384 void edac_mc_reset_delay_period(int value)
386 struct mem_ctl_info *mci;
387 struct list_head *item;
389 mutex_lock(&mem_ctls_mutex);
391 /* scan the list and turn off all workq timers, doing so under lock
393 list_for_each(item, &mc_devices) {
394 mci = list_entry(item, struct mem_ctl_info, link);
396 if (mci->op_state == OP_RUNNING_POLL)
397 cancel_delayed_work(&mci->work);
400 mutex_unlock(&mem_ctls_mutex);
403 /* re-walk the list, and reset the poll delay */
404 mutex_lock(&mem_ctls_mutex);
406 list_for_each(item, &mc_devices) {
407 mci = list_entry(item, struct mem_ctl_info, link);
409 edac_mc_workq_setup(mci, (unsigned long) value);
412 mutex_unlock(&mem_ctls_mutex);
417 /* Return 0 on success, 1 on failure.
418 * Before calling this function, caller must
419 * assign a unique value to mci->mc_idx.
423 * called with the mem_ctls_mutex lock held
425 static int add_mc_to_global_list(struct mem_ctl_info *mci)
427 struct list_head *item, *insert_before;
428 struct mem_ctl_info *p;
430 insert_before = &mc_devices;
432 p = find_mci_by_dev(mci->dev);
433 if (unlikely(p != NULL))
436 list_for_each(item, &mc_devices) {
437 p = list_entry(item, struct mem_ctl_info, link);
439 if (p->mc_idx >= mci->mc_idx) {
440 if (unlikely(p->mc_idx == mci->mc_idx))
443 insert_before = item;
448 list_add_tail_rcu(&mci->link, insert_before);
449 atomic_inc(&edac_handlers);
453 edac_printk(KERN_WARNING, EDAC_MC,
454 "%s (%s) %s %s already assigned %d\n", dev_name(p->dev),
455 edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
459 edac_printk(KERN_WARNING, EDAC_MC,
460 "bug in low-level driver: attempt to assign\n"
461 " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
465 static void del_mc_from_global_list(struct mem_ctl_info *mci)
467 atomic_dec(&edac_handlers);
468 list_del_rcu(&mci->link);
470 /* these are for safe removal of devices from global list while
471 * NMI handlers may be traversing list
474 INIT_LIST_HEAD(&mci->link);
478 * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'.
480 * If found, return a pointer to the structure.
483 * Caller must hold mem_ctls_mutex.
485 struct mem_ctl_info *edac_mc_find(int idx)
487 struct list_head *item;
488 struct mem_ctl_info *mci;
490 list_for_each(item, &mc_devices) {
491 mci = list_entry(item, struct mem_ctl_info, link);
493 if (mci->mc_idx >= idx) {
494 if (mci->mc_idx == idx)
503 EXPORT_SYMBOL(edac_mc_find);
506 * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
507 * create sysfs entries associated with mci structure
508 * @mci: pointer to the mci structure to be added to the list
509 * @mc_idx: A unique numeric identifier to be assigned to the 'mci' structure.
516 /* FIXME - should a warning be printed if no error detection? correction? */
517 int edac_mc_add_mc(struct mem_ctl_info *mci)
519 debugf0("%s()\n", __func__);
521 #ifdef CONFIG_EDAC_DEBUG
522 if (edac_debug_level >= 3)
523 edac_mc_dump_mci(mci);
525 if (edac_debug_level >= 4) {
528 for (i = 0; i < mci->nr_csrows; i++) {
531 edac_mc_dump_csrow(&mci->csrows[i]);
532 for (j = 0; j < mci->csrows[i].nr_channels; j++)
533 edac_mc_dump_channel(&mci->csrows[i].
538 mutex_lock(&mem_ctls_mutex);
540 if (add_mc_to_global_list(mci))
543 /* set load time so that error rate can be tracked */
544 mci->start_time = jiffies;
546 if (edac_create_sysfs_mci_device(mci)) {
547 edac_mc_printk(mci, KERN_WARNING,
548 "failed to create sysfs device\n");
552 /* If there IS a check routine, then we are running POLLED */
553 if (mci->edac_check != NULL) {
554 /* This instance is NOW RUNNING */
555 mci->op_state = OP_RUNNING_POLL;
557 edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
559 mci->op_state = OP_RUNNING_INTERRUPT;
562 /* Report action taken */
563 edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':"
564 " DEV %s\n", mci->mod_name, mci->ctl_name, edac_dev_name(mci));
566 mutex_unlock(&mem_ctls_mutex);
570 del_mc_from_global_list(mci);
573 mutex_unlock(&mem_ctls_mutex);
576 EXPORT_SYMBOL_GPL(edac_mc_add_mc);
579 * edac_mc_del_mc: Remove sysfs entries for specified mci structure and
580 * remove mci structure from global list
581 * @pdev: Pointer to 'struct device' representing mci structure to remove.
583 * Return pointer to removed mci structure, or NULL if device not found.
585 struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
587 struct mem_ctl_info *mci;
589 debugf0("%s()\n", __func__);
591 mutex_lock(&mem_ctls_mutex);
593 /* find the requested mci struct in the global list */
594 mci = find_mci_by_dev(dev);
596 mutex_unlock(&mem_ctls_mutex);
600 del_mc_from_global_list(mci);
601 mutex_unlock(&mem_ctls_mutex);
603 /* flush workq processes */
604 edac_mc_workq_teardown(mci);
606 /* marking MCI offline */
607 mci->op_state = OP_OFFLINE;
609 /* remove from sysfs */
610 edac_remove_sysfs_mci_device(mci);
612 edac_printk(KERN_INFO, EDAC_MC,
613 "Removed device %d for %s %s: DEV %s\n", mci->mc_idx,
614 mci->mod_name, mci->ctl_name, edac_dev_name(mci));
618 EXPORT_SYMBOL_GPL(edac_mc_del_mc);
620 static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
625 unsigned long flags = 0;
627 debugf3("%s()\n", __func__);
629 /* ECC error page was not in our memory. Ignore it. */
630 if (!pfn_valid(page))
633 /* Find the actual page structure then map it and fix */
634 pg = pfn_to_page(page);
637 local_irq_save(flags);
639 virt_addr = kmap_atomic(pg);
641 /* Perform architecture specific atomic scrub operation */
642 atomic_scrub(virt_addr + offset, size);
644 /* Unmap and complete */
645 kunmap_atomic(virt_addr);
648 local_irq_restore(flags);
651 /* FIXME - should return -1 */
652 int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
654 struct csrow_info *csrows = mci->csrows;
657 debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page);
660 for (i = 0; i < mci->nr_csrows; i++) {
661 struct csrow_info *csrow = &csrows[i];
663 if (csrow->nr_pages == 0)
666 debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) "
667 "mask(0x%lx)\n", mci->mc_idx, __func__,
668 csrow->first_page, page, csrow->last_page,
671 if ((page >= csrow->first_page) &&
672 (page <= csrow->last_page) &&
673 ((page & csrow->page_mask) ==
674 (csrow->first_page & csrow->page_mask))) {
681 edac_mc_printk(mci, KERN_ERR,
682 "could not look up page error address %lx\n",
683 (unsigned long)page);
687 EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
689 /* FIXME - setable log (warning/emerg) levels */
690 /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
691 void edac_mc_handle_ce(struct mem_ctl_info *mci,
692 unsigned long page_frame_number,
693 unsigned long offset_in_page, unsigned long syndrome,
694 int row, int channel, const char *msg)
696 unsigned long remapped_page;
699 debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
701 /* FIXME - maybe make panic on INTERNAL ERROR an option */
702 if (row >= mci->nr_csrows || row < 0) {
703 /* something is wrong */
704 edac_mc_printk(mci, KERN_ERR,
705 "INTERNAL ERROR: row out of range "
706 "(%d >= %d)\n", row, mci->nr_csrows);
707 edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
711 if (channel >= mci->csrows[row].nr_channels || channel < 0) {
712 /* something is wrong */
713 edac_mc_printk(mci, KERN_ERR,
714 "INTERNAL ERROR: channel out of range "
715 "(%d >= %d)\n", channel,
716 mci->csrows[row].nr_channels);
717 edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
721 label = mci->csrows[row].channels[channel].dimm->label;
723 if (edac_mc_get_log_ce())
724 /* FIXME - put in DIMM location */
725 edac_mc_printk(mci, KERN_WARNING,
726 "CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
727 "0x%lx, row %d, channel %d, label \"%s\": %s\n",
728 page_frame_number, offset_in_page,
729 mci->csrows[row].grain, syndrome, row, channel,
733 mci->csrows[row].ce_count++;
734 mci->csrows[row].channels[channel].ce_count++;
736 if (mci->scrub_mode & SCRUB_SW_SRC) {
738 * Some MC's can remap memory so that it is still available
739 * at a different address when PCI devices map into memory.
740 * MC's that can't do this lose the memory where PCI devices
741 * are mapped. This mapping is MC dependent and so we call
742 * back into the MC driver for it to map the MC page to
743 * a physical (CPU) page which can then be mapped to a virtual
744 * page - which can then be scrubbed.
746 remapped_page = mci->ctl_page_to_phys ?
747 mci->ctl_page_to_phys(mci, page_frame_number) :
750 edac_mc_scrub_block(remapped_page, offset_in_page,
751 mci->csrows[row].grain);
754 EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
756 void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
758 if (edac_mc_get_log_ce())
759 edac_mc_printk(mci, KERN_WARNING,
760 "CE - no information available: %s\n", msg);
762 mci->ce_noinfo_count++;
765 EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
767 void edac_mc_handle_ue(struct mem_ctl_info *mci,
768 unsigned long page_frame_number,
769 unsigned long offset_in_page, int row, const char *msg)
771 int len = EDAC_MC_LABEL_LEN * 4;
772 char labels[len + 1];
778 debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
780 /* FIXME - maybe make panic on INTERNAL ERROR an option */
781 if (row >= mci->nr_csrows || row < 0) {
782 /* something is wrong */
783 edac_mc_printk(mci, KERN_ERR,
784 "INTERNAL ERROR: row out of range "
785 "(%d >= %d)\n", row, mci->nr_csrows);
786 edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
790 label = mci->csrows[row].channels[0].dimm->label;
791 chars = snprintf(pos, len + 1, "%s", label);
795 for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0);
797 label = mci->csrows[row].channels[chan].dimm->label;
798 chars = snprintf(pos, len + 1, ":%s", label);
803 if (edac_mc_get_log_ue())
804 edac_mc_printk(mci, KERN_EMERG,
805 "UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
806 "labels \"%s\": %s\n", page_frame_number,
807 offset_in_page, mci->csrows[row].grain, row,
810 if (edac_mc_get_panic_on_ue())
811 panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
812 "row %d, labels \"%s\": %s\n", mci->mc_idx,
813 page_frame_number, offset_in_page,
814 mci->csrows[row].grain, row, labels, msg);
817 mci->csrows[row].ue_count++;
819 EXPORT_SYMBOL_GPL(edac_mc_handle_ue);
821 void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
823 if (edac_mc_get_panic_on_ue())
824 panic("EDAC MC%d: Uncorrected Error", mci->mc_idx);
826 if (edac_mc_get_log_ue())
827 edac_mc_printk(mci, KERN_WARNING,
828 "UE - no information available: %s\n", msg);
829 mci->ue_noinfo_count++;
832 EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
834 /*************************************************************
835 * On Fully Buffered DIMM modules, this help function is
836 * called to process UE events
838 void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
840 unsigned int channela,
841 unsigned int channelb, char *msg)
843 int len = EDAC_MC_LABEL_LEN * 4;
844 char labels[len + 1];
849 if (csrow >= mci->nr_csrows) {
850 /* something is wrong */
851 edac_mc_printk(mci, KERN_ERR,
852 "INTERNAL ERROR: row out of range (%d >= %d)\n",
853 csrow, mci->nr_csrows);
854 edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
858 if (channela >= mci->csrows[csrow].nr_channels) {
859 /* something is wrong */
860 edac_mc_printk(mci, KERN_ERR,
861 "INTERNAL ERROR: channel-a out of range "
863 channela, mci->csrows[csrow].nr_channels);
864 edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
868 if (channelb >= mci->csrows[csrow].nr_channels) {
869 /* something is wrong */
870 edac_mc_printk(mci, KERN_ERR,
871 "INTERNAL ERROR: channel-b out of range "
873 channelb, mci->csrows[csrow].nr_channels);
874 edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
879 mci->csrows[csrow].ue_count++;
881 /* Generate the DIMM labels from the specified channels */
882 label = mci->csrows[csrow].channels[channela].dimm->label;
883 chars = snprintf(pos, len + 1, "%s", label);
886 chars = snprintf(pos, len + 1, "-%s",
887 mci->csrows[csrow].channels[channelb].dimm->label);
889 if (edac_mc_get_log_ue())
890 edac_mc_printk(mci, KERN_EMERG,
891 "UE row %d, channel-a= %d channel-b= %d "
892 "labels \"%s\": %s\n", csrow, channela, channelb,
895 if (edac_mc_get_panic_on_ue())
896 panic("UE row %d, channel-a= %d channel-b= %d "
897 "labels \"%s\": %s\n", csrow, channela,
898 channelb, labels, msg);
900 EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
902 /*************************************************************
903 * On Fully Buffered DIMM modules, this help function is
904 * called to process CE events
906 void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
907 unsigned int csrow, unsigned int channel, char *msg)
911 /* Ensure boundary values */
912 if (csrow >= mci->nr_csrows) {
913 /* something is wrong */
914 edac_mc_printk(mci, KERN_ERR,
915 "INTERNAL ERROR: row out of range (%d >= %d)\n",
916 csrow, mci->nr_csrows);
917 edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
920 if (channel >= mci->csrows[csrow].nr_channels) {
921 /* something is wrong */
922 edac_mc_printk(mci, KERN_ERR,
923 "INTERNAL ERROR: channel out of range (%d >= %d)\n",
924 channel, mci->csrows[csrow].nr_channels);
925 edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
929 label = mci->csrows[csrow].channels[channel].dimm->label;
931 if (edac_mc_get_log_ce())
932 /* FIXME - put in DIMM location */
933 edac_mc_printk(mci, KERN_WARNING,
934 "CE row %d, channel %d, label \"%s\": %s\n",
935 csrow, channel, label, msg);
938 mci->csrows[csrow].ce_count++;
939 mci->csrows[csrow].channels[channel].ce_count++;
941 EXPORT_SYMBOL(edac_mc_handle_fbd_ce);