Commit be80a1ca authored by Borislav Petkov's avatar Borislav Petkov
Browse files

Merge branches 'edac-misc' and 'edac-alloc-cleanup' into edac-updates-for-v5.19



Combine all collected EDAC changes for submission into v5.19:

* edac-misc:
  EDAC/xgene: Fix typo processsors -> processors
  EDAC/i5100: Remove unused inline function i5100_nrecmema_dm_buf_id()
  EDAC/ghes: Change ghes_hw from global to static
  EDAC/armada_xp: Use devm_platform_ioremap_resource()
  EDAC/synopsys: Add a SPDX identifier
  EDAC/synopsys: Add driver support for i.MX platforms
  EDAC/dmc520: Don't print an error for each unconfigured interrupt line
  efi/cper: Reformat CPER memory error location to more readable
  EDAC/ghes: Unify CPER memory error location reporting
  efi/cper: Add a cper_mem_err_status_str() to decode error description
  powerpc/85xx: Remove fsl,85... bindings

* edac-alloc-cleanup:
  EDAC: Use kcalloc()
  EDAC/mc: Get rid of edac_align_ptr()
  EDAC/device: Sanitize edac_device_alloc_ctl_info() definition
  EDAC/device: Get rid of the silly one-shot memory allocation in edac_device_alloc_ctl_info()
  EDAC/pci: Get rid of the silly one-shot memory allocation in edac_pci_alloc_ctl_info()
  EDAC/mc: Get rid of silly one-shot struct allocation in edac_mc_alloc()

Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
parents 2aeb1f5f 13088b65
Loading
Loading
Loading
Loading
+50 −80
Original line number Diff line number Diff line
@@ -47,99 +47,67 @@ static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
}
#endif				/* CONFIG_EDAC_DEBUG */

struct edac_device_ctl_info *edac_device_alloc_ctl_info(
	unsigned sz_private,
	char *edac_device_name, unsigned nr_instances,
	char *edac_block_name, unsigned nr_blocks,
	unsigned offset_value,		/* zero, 1, or other based offset */
	struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib,
	int device_index)
/*
 * @off_val: zero, 1, or other based offset
 */
struct edac_device_ctl_info *
edac_device_alloc_ctl_info(unsigned pvt_sz, char *dev_name, unsigned nr_instances,
			   char *blk_name, unsigned nr_blocks, unsigned off_val,
			   struct edac_dev_sysfs_block_attribute *attrib_spec,
			   unsigned nr_attrib, int device_index)
{
	struct edac_device_ctl_info *dev_ctl;
	struct edac_device_instance *dev_inst, *inst;
	struct edac_device_block *dev_blk, *blk_p, *blk;
	struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
	unsigned total_size;
	unsigned count;
	struct edac_device_block *dev_blk, *blk_p, *blk;
	struct edac_device_instance *dev_inst, *inst;
	struct edac_device_ctl_info *dev_ctl;
	unsigned instance, block, attr;
	void *pvt, *p;
	void *pvt;
	int err;

	edac_dbg(4, "instances=%d blocks=%d\n", nr_instances, nr_blocks);

	/* Calculate the size of memory we need to allocate AND
	 * determine the offsets of the various item arrays
	 * (instance,block,attrib) from the start of an  allocated structure.
	 * We want the alignment of each item  (instance,block,attrib)
	 * to be at least as stringent as what the compiler would
	 * provide if we could simply hardcode everything into a single struct.
	 */
	p = NULL;
	dev_ctl = edac_align_ptr(&p, sizeof(*dev_ctl), 1);
	dev_ctl = kzalloc(sizeof(struct edac_device_ctl_info), GFP_KERNEL);
	if (!dev_ctl)
		return NULL;

	/* Calc the 'end' offset past end of ONE ctl_info structure
	 * which will become the start of the 'instance' array
	 */
	dev_inst = edac_align_ptr(&p, sizeof(*dev_inst), nr_instances);
	dev_inst = kcalloc(nr_instances, sizeof(struct edac_device_instance), GFP_KERNEL);
	if (!dev_inst)
		goto free;

	/* Calc the 'end' offset past the instance array within the ctl_info
	 * which will become the start of the block array
	 */
	count = nr_instances * nr_blocks;
	dev_blk = edac_align_ptr(&p, sizeof(*dev_blk), count);
	dev_ctl->instances = dev_inst;

	/* Calc the 'end' offset past the dev_blk array
	 * which will become the start of the attrib array, if any.
	 */
	/* calc how many nr_attrib we need */
	if (nr_attrib > 0)
		count *= nr_attrib;
	dev_attrib = edac_align_ptr(&p, sizeof(*dev_attrib), count);
	dev_blk = kcalloc(nr_instances * nr_blocks, sizeof(struct edac_device_block), GFP_KERNEL);
	if (!dev_blk)
		goto free;

	/* Calc the 'end' offset past the attributes array */
	pvt = edac_align_ptr(&p, sz_private, 1);
	dev_ctl->blocks = dev_blk;

	/* 'pvt' now points to where the private data area is.
	 * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
	 * is baselined at ZERO
	 */
	total_size = ((unsigned long)pvt) + sz_private;
	if (nr_attrib) {
		dev_attrib = kcalloc(nr_attrib, sizeof(struct edac_dev_sysfs_block_attribute),
				     GFP_KERNEL);
		if (!dev_attrib)
			goto free;

	/* Allocate the amount of memory for the set of control structures */
	dev_ctl = kzalloc(total_size, GFP_KERNEL);
	if (dev_ctl == NULL)
		return NULL;
		dev_ctl->attribs = dev_attrib;
	}

	if (pvt_sz) {
		pvt = kzalloc(pvt_sz, GFP_KERNEL);
		if (!pvt)
			goto free;

		dev_ctl->pvt_info = pvt;
	}

	/* Adjust pointers so they point within the actual memory we
	 * just allocated rather than an imaginary chunk of memory
	 * located at address 0.
	 * 'dev_ctl' points to REAL memory, while the others are
	 * ZERO based and thus need to be adjusted to point within
	 * the allocated memory.
	 */
	dev_inst = (struct edac_device_instance *)
		(((char *)dev_ctl) + ((unsigned long)dev_inst));
	dev_blk = (struct edac_device_block *)
		(((char *)dev_ctl) + ((unsigned long)dev_blk));
	dev_attrib = (struct edac_dev_sysfs_block_attribute *)
		(((char *)dev_ctl) + ((unsigned long)dev_attrib));
	pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL;

	/* Begin storing the information into the control info structure */
	dev_ctl->dev_idx	= device_index;
	dev_ctl->nr_instances	= nr_instances;
	dev_ctl->instances = dev_inst;
	dev_ctl->pvt_info = pvt;

	/* Default logging of CEs and UEs */
	dev_ctl->log_ce = 1;
	dev_ctl->log_ue = 1;

	/* Name of this edac device */
	snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);

	edac_dbg(4, "edac_dev=%p next after end=%p\n",
		 dev_ctl, pvt + sz_private);
	snprintf(dev_ctl->name, sizeof(dev_ctl->name),"%s", dev_name);

	/* Initialize every Instance */
	for (instance = 0; instance < nr_instances; instance++) {
@@ -150,15 +118,14 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
		inst->blocks = blk_p;

		/* name of this instance */
		snprintf(inst->name, sizeof(inst->name),
			 "%s%u", edac_device_name, instance);
		snprintf(inst->name, sizeof(inst->name), "%s%u", dev_name, instance);

		/* Initialize every block in each instance */
		for (block = 0; block < nr_blocks; block++) {
			blk = &blk_p[block];
			blk->instance = inst;
			snprintf(blk->name, sizeof(blk->name),
				 "%s%d", edac_block_name, block+offset_value);
				 "%s%d", blk_name, block + off_val);

			edac_dbg(4, "instance=%d inst_p=%p block=#%d block_p=%p name='%s'\n",
				 instance, inst, block, blk, blk->name);
@@ -210,10 +177,8 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
	 * Initialize the 'root' kobj for the edac_device controller
	 */
	err = edac_device_register_sysfs_main_kobj(dev_ctl);
	if (err) {
		kfree(dev_ctl);
		return NULL;
	}
	if (err)
		goto free;

	/* at this point, the root kobj is valid, and in order to
	 * 'free' the object, then the function:
@@ -223,6 +188,11 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
	 */

	return dev_ctl;

free:
	__edac_device_free_ctl_info(dev_ctl);

	return NULL;
}
EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);

+14 −0
Original line number Diff line number Diff line
@@ -216,6 +216,8 @@ struct edac_device_ctl_info {
	 */
	u32 nr_instances;
	struct edac_device_instance *instances;
	struct edac_device_block *blocks;
	struct edac_dev_sysfs_block_attribute *attribs;

	/* Event counters for the this whole EDAC Device */
	struct edac_device_counter counters;
@@ -348,4 +350,16 @@ edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, int inst_nr,
 */
extern int edac_device_alloc_index(void);
extern const char *edac_layer_name[];

/* Free the actual struct */
static inline void __edac_device_free_ctl_info(struct edac_device_ctl_info *ci)
{
	if (ci) {
		kfree(ci->pvt_info);
		kfree(ci->attribs);
		kfree(ci->blocks);
		kfree(ci->instances);
		kfree(ci);
	}
}
#endif
+1 −4
Original line number Diff line number Diff line
@@ -208,10 +208,7 @@ static void edac_device_ctrl_master_release(struct kobject *kobj)
	/* decrement the EDAC CORE module ref count */
	module_put(edac_dev->owner);

	/* free the control struct containing the 'main' kobj
	 * passed in to this routine
	 */
	kfree(edac_dev);
	__edac_device_free_ctl_info(edac_dev);
}

/* ktype for the main (master) kobject */
+13 −83
Original line number Diff line number Diff line
@@ -170,61 +170,6 @@ const char * const edac_mem_types[] = {
};
EXPORT_SYMBOL_GPL(edac_mem_types);

/**
 * edac_align_ptr - Prepares the pointer offsets for a single-shot allocation
 * @p:		pointer to a pointer with the memory offset to be used. At
 *		return, this will be incremented to point to the next offset
 * @size:	Size of the data structure to be reserved
 * @n_elems:	Number of elements that should be reserved
 *
 * If 'size' is a constant, the compiler will optimize this whole function
 * down to either a no-op or the addition of a constant to the value of '*p'.
 *
 * The 'p' pointer is absolutely needed to keep the proper advancing
 * further in memory to the proper offsets when allocating the struct along
 * with its embedded structs, as edac_device_alloc_ctl_info() does it
 * above, for example.
 *
 * At return, the pointer 'p' will be incremented to be used on a next call
 * to this function.
 */
void *edac_align_ptr(void **p, unsigned int size, int n_elems)
{
	unsigned int align, r;
	void *ptr = *p;

	*p += size * n_elems;

	/*
	 * 'p' can possibly be an unaligned item X such that sizeof(X) is
	 * 'size'.  Adjust 'p' so that its alignment is at least as
	 * stringent as what the compiler would provide for X and return
	 * the aligned result.
	 * Here we assume that the alignment of a "long long" is the most
	 * stringent alignment that the compiler will ever provide by default.
	 * As far as I know, this is a reasonable assumption.
	 */
	if (size > sizeof(long))
		align = sizeof(long long);
	else if (size > sizeof(int))
		align = sizeof(long);
	else if (size > sizeof(short))
		align = sizeof(int);
	else if (size > sizeof(char))
		align = sizeof(short);
	else
		return ptr;

	r = (unsigned long)ptr % align;

	if (r == 0)
		return ptr;

	*p += align - r;

	return (void *)(((unsigned long)ptr) + align - r);
}

static void _edac_mc_free(struct mem_ctl_info *mci)
{
	put_device(&mci->dev);
@@ -257,6 +202,8 @@ static void mci_release(struct device *dev)
		}
		kfree(mci->csrows);
	}
	kfree(mci->pvt_info);
	kfree(mci->layers);
	kfree(mci);
}

@@ -392,9 +339,8 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
{
	struct mem_ctl_info *mci;
	struct edac_mc_layer *layer;
	unsigned int idx, size, tot_dimms = 1;
	unsigned int idx, tot_dimms = 1;
	unsigned int tot_csrows = 1, tot_channels = 1;
	void *pvt, *ptr = NULL;
	bool per_rank = false;

	if (WARN_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0))
@@ -416,41 +362,25 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
			per_rank = true;
	}

	/* Figure out the offsets of the various items from the start of an mc
	 * structure.  We want the alignment of each item to be at least as
	 * stringent as what the compiler would provide if we could simply
	 * hardcode everything into a single struct.
	 */
	mci	= edac_align_ptr(&ptr, sizeof(*mci), 1);
	layer	= edac_align_ptr(&ptr, sizeof(*layer), n_layers);
	pvt	= edac_align_ptr(&ptr, sz_pvt, 1);
	size	= ((unsigned long)pvt) + sz_pvt;

	edac_dbg(1, "allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
		 size,
		 tot_dimms,
		 per_rank ? "ranks" : "dimms",
		 tot_csrows * tot_channels);

	mci = kzalloc(size, GFP_KERNEL);
	if (mci == NULL)
	mci = kzalloc(sizeof(struct mem_ctl_info), GFP_KERNEL);
	if (!mci)
		return NULL;

	mci->layers = kcalloc(n_layers, sizeof(struct edac_mc_layer), GFP_KERNEL);
	if (!mci->layers)
		goto error;

	mci->pvt_info = kzalloc(sz_pvt, GFP_KERNEL);
	if (!mci->pvt_info)
		goto error;

	mci->dev.release = mci_release;
	device_initialize(&mci->dev);

	/* Adjust pointers so they point within the memory we just allocated
	 * rather than an imaginary chunk of memory located at address 0.
	 */
	layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
	pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;

	/* setup index and various internal pointers */
	mci->mc_idx = mc_num;
	mci->tot_dimms = tot_dimms;
	mci->pvt_info = pvt;
	mci->n_layers = n_layers;
	mci->layers = layer;
	memcpy(mci->layers, layers, sizeof(*layer) * n_layers);
	mci->nr_csrows = tot_csrows;
	mci->num_cschannel = tot_channels;
+0 −2
Original line number Diff line number Diff line
@@ -59,8 +59,6 @@ extern void edac_device_reset_delay_period(struct edac_device_ctl_info
					   *edac_dev, unsigned long value);
extern void edac_mc_reset_delay_period(unsigned long value);

extern void *edac_align_ptr(void **p, unsigned size, int n_elems);

/*
 * EDAC debugfs functions
 */
Loading