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