Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91b99041 authored by Dave Jiang's avatar Dave Jiang Committed by Linus Torvalds
Browse files

drivers/edac: updated PCI monitoring



Moving PCI to a per-instance device model

This should include the correct sysfs setup as well. Please review.

Signed-off-by: default avatarDave Jiang <djiang@mvista.com>
Signed-off-by: default avatarDouglas Thompson <dougthompson@xmission.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 81d87cb1
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -11,9 +11,12 @@ obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC)		+= edac_core.o

edac_core-objs	:= edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o

edac_core-objs	+= edac_module.o edac_device_sysfs.o

ifdef CONFIG_PCI
edac_core-objs	+= edac_pci.o edac_pci_sysfs.o
endif

obj-$(CONFIG_EDAC_AMD76X)		+= amd76x_edac.o
obj-$(CONFIG_EDAC_I5000)		+= i5000_edac.o
obj-$(CONFIG_EDAC_E7XXX)		+= e7xxx_edac.o
+16 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@

static int force_function_unhide;

static struct edac_pci_ctl_info *e752x_pci;

#define e752x_printk(level, fmt, arg...) \
	edac_printk(level, "e752x", fmt, ##arg)

@@ -1040,6 +1042,17 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
	e752x_init_error_reporting_regs(pvt);
	e752x_get_error_info(mci, &discard); /* clear other MCH errors */

	/* allocating generic PCI control info */
	e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
	if (!e752x_pci) {
		printk(KERN_WARNING
			"%s(): Unable to create PCI control\n",
			__func__);
		printk(KERN_WARNING
			"%s(): PCI error report via EDAC not setup\n",
			__func__);
	}

	/* get this far and it's successful */
	debugf3("%s(): success\n", __func__);
	return 0;
@@ -1073,6 +1086,9 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)

	debugf0("%s()\n", __func__);

	if (e752x_pci)
		edac_pci_release_generic_ctl(e752x_pci);

	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
		return;

+114 −6
Original line number Diff line number Diff line
@@ -60,6 +60,10 @@
#define edac_device_printk(ctl, level, fmt, arg...) \
	printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)

/* edac_pci printk */
#define edac_pci_printk(ctl, level, fmt, arg...) \
	printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)

/* prefixes for edac_printk() and edac_mc_printk() */
#define EDAC_MC "MC"
#define EDAC_PCI "PCI"
@@ -200,6 +204,13 @@ enum scrub_type {

/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */

/* EDAC internal operation states */
#define	OP_ALLOC		0x100
#define OP_RUNNING_POLL		0x201
#define OP_RUNNING_INTERRUPT	0x202
#define OP_RUNNING_POLL_INTR	0x203
#define OP_OFFLINE		0x300

extern char * edac_align_ptr(void *ptr, unsigned size);

/*
@@ -520,12 +531,6 @@ struct edac_device_ctl_info {

	/* the internal state of this controller instance */
	int op_state;
#define	OP_ALLOC		0x100
#define OP_RUNNING_POLL		0x201
#define OP_RUNNING_INTERRUPT	0x202
#define OP_RUNNING_POLL_INTR	0x203
#define OP_OFFLINE		0x300

	/* work struct for this instance */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
	struct delayed_work work;
@@ -626,6 +631,84 @@ extern void edac_device_free_ctl_info( struct edac_device_ctl_info *ctl_info);

#ifdef CONFIG_PCI

struct edac_pci_counter {
	atomic_t	pe_count;
	atomic_t	npe_count;
};

/*
 * Abstract edac_pci control info structure
 *
 */
struct edac_pci_ctl_info {
	/* for global list of edac_pci_ctl_info structs */
	struct list_head link;

	int pci_idx;

	/* Per instance controls for this edac_device */
	int check_parity_error;	/* boolean for checking parity errs */
	int log_parity_error;	/* boolean for logging parity errs */
	int panic_on_pe;	/* boolean for panic'ing on a PE */
	unsigned poll_msec;	/* number of milliseconds to poll interval */
	unsigned long delay;	/* number of jiffies for poll_msec */

	struct sysdev_class *edac_class;	/* pointer to class */

	/* the internal state of this controller instance */
	int op_state;
	/* work struct for this instance */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
	struct delayed_work work;
#else
	struct work_struct work;
#endif

	/* pointer to edac polling checking routine:
	 *	If NOT NULL: points to polling check routine
	 *	If NULL: Then assumes INTERRUPT operation, where
	 *		MC driver will receive events
	 */
	void (*edac_check) (struct edac_pci_ctl_info * edac_dev);

	struct device *dev;	/* pointer to device structure */

	const char *mod_name;	/* module name */
	const char *ctl_name;	/* edac controller  name */
	const char *dev_name;	/* pci/platform/etc... name */

	void *pvt_info;		/* pointer to 'private driver' info */

	unsigned long start_time;/* edac_pci load start time (jiffies)*/

	/* these are for safe removal of devices from global list while
	 * NMI handlers may be traversing list
	 */
	struct rcu_head rcu;
	struct completion complete;

	/* sysfs top name under 'edac' directory
	 * and instance name:
	 *	cpu/cpu0/...
	 *	cpu/cpu1/...
	 *	cpu/cpu2/...
	 *	...
	 */
	char name[EDAC_DEVICE_NAME_LEN + 1];

	/* Event counters for the this whole EDAC Device */
	struct edac_pci_counter counters;

	/* edac sysfs device control for the 'name'
	 * device this structure controls
	 */
	struct kobject kobj;
	struct completion kobj_complete;
};

#define to_edac_pci_ctl_work(w) \
		container_of(w, struct edac_pci_ctl_info,work)

/* write all or some bits in a byte-register*/
static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
		u8 mask)
@@ -726,5 +809,30 @@ extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
		int inst_nr, int block_nr, const char *msg);

/*
 * edac_pci APIs
 */
extern struct edac_pci_ctl_info *
edac_pci_alloc_ctl_info(unsigned int sz_pvt, const char *edac_pci_name);

extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);

extern void
edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, unsigned long value);

extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
extern struct edac_pci_ctl_info * edac_pci_del_device(struct device *dev);

extern struct edac_pci_ctl_info *
edac_pci_create_generic_ctl(struct device *dev, const char *mod_name);

extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci);
extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci);
extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);

/*
 * edac misc APIs
 */
extern char * edac_op_state_toString(int op_state);

#endif				/* _EDAC_CORE_H_ */
+1 −22
Original line number Diff line number Diff line
@@ -418,27 +418,6 @@ void edac_device_reset_delay_period(
	unlock_device_list();
}

/*
 * edac_op_state_toString(edac_dev)
 */
static char *edac_op_state_toString(struct edac_device_ctl_info *edac_dev)
{
	int opstate = edac_dev->op_state;

	if (opstate == OP_RUNNING_POLL)
		return "POLLED";
	else if (opstate == OP_RUNNING_INTERRUPT)
		return "INTERRUPT";
	else if (opstate == OP_RUNNING_POLL_INTR)
		return "POLL-INTR";
	else if (opstate == OP_ALLOC)
		return "ALLOC";
	else if (opstate == OP_OFFLINE)
		return "OFFLINE";

	return "UNKNOWN";
}

/**
 * edac_device_add_device: Insert the 'edac_dev' structure into the
 * edac_device global list and create sysfs entries associated with
@@ -496,7 +475,7 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev, int edac_idx)
		edac_dev->mod_name,
		edac_dev->ctl_name,
		dev_name(edac_dev),
		edac_op_state_toString(edac_dev)
		edac_op_state_toString(edac_dev->op_state)
		);

	unlock_device_list();
+20 −12
Original line number Diff line number Diff line
@@ -34,6 +34,25 @@ static struct sysdev_class edac_class = {
};
static int edac_class_valid = 0;

/*
 * edac_op_state_toString()
 */
char * edac_op_state_toString(int opstate)
{
	if (opstate == OP_RUNNING_POLL)
		return "POLLED";
	else if (opstate == OP_RUNNING_INTERRUPT)
		return "INTERRUPT";
	else if (opstate == OP_RUNNING_POLL_INTR)
		return "POLL-INTR";
	else if (opstate == OP_ALLOC)
		return "ALLOC";
	else if (opstate == OP_OFFLINE)
		return "OFFLINE";

	return "UNKNOWN";
}

/*
 * edac_get_edac_class()
 *
@@ -153,26 +172,16 @@ static int __init edac_init(void)
		goto error_sysfs;
	}

	/* Create the PCI parity sysfs entries */
	if (edac_sysfs_pci_setup()) {
		edac_printk(KERN_ERR, EDAC_MC,
			"PCI: Error initializing sysfs code\n");
		err = -ENODEV;
		goto error_mem;
	}

	/* Setup/Initialize the edac_device system */
	err = edac_workqueue_setup();
	if (err) {
		edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
		goto error_pci;
		goto error_mem;
	}

	return 0;

	/* Error teardown stack */
error_pci:
	edac_sysfs_pci_teardown();
error_mem:
	edac_sysfs_memctrl_teardown();
error_sysfs:
@@ -192,7 +201,6 @@ static void __exit edac_exit(void)
	/* tear down the various subsystems*/
	edac_workqueue_teardown();
	edac_sysfs_memctrl_teardown();
	edac_sysfs_pci_teardown();
	edac_unregister_sysfs_edac_name();
}

Loading