#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#include "edac_module.h"
debugf1("%s()\n", __func__);
/* get the /sys/devices/system/edac reference */
- edac_class = edac_get_edac_class();
+ edac_class = edac_get_sysfs_class();
if (edac_class == NULL) {
debugf1("%s() no edac_class error\n", __func__);
err = -ENODEV;
if (!try_module_get(edac_dev->owner)) {
err = -ENODEV;
- goto err_out;
+ goto err_mod_get;
}
/* register */
err_kobj_reg:
module_put(edac_dev->owner);
+err_mod_get:
+ edac_put_sysfs_class();
+
err_out:
return err;
}
* edac_device_unregister_sysfs_main_kobj:
* the '..../edac/<name>' kobject
*/
-void edac_device_unregister_sysfs_main_kobj(
- struct edac_device_ctl_info *edac_dev)
+void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
{
debugf0("%s()\n", __func__);
debugf4("%s() name of kobject is: %s\n",
- __func__, kobject_name(&edac_dev->kobj));
+ __func__, kobject_name(&dev->kobj));
/*
* Unregister the edac device's kobject and
* a) module_put() this module
* b) 'kfree' the memory
*/
- kobject_put(&edac_dev->kobj);
+ kobject_put(&dev->kobj);
+ edac_put_sysfs_class();
}
/* edac_dev -> instance information */
#include <linux/ctype.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include <linux/bug.h>
#include "edac_core.h"
debugf1("%s()\n", __func__);
/* get the /sys/devices/system/edac class reference */
- edac_class = edac_get_edac_class();
+ edac_class = edac_get_sysfs_class();
if (edac_class == NULL) {
debugf1("%s() no edac_class error=%d\n", __func__, err);
goto fail_out;
if (!mc_kset) {
err = -ENOMEM;
debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
- goto fail_out;
+ goto fail_kset;
}
debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
return 0;
+fail_kset:
+ edac_put_sysfs_class();
- /* error unwind stack */
fail_out:
return err;
}
void edac_sysfs_teardown_mc_kset(void)
{
kset_unregister(mc_kset);
+ edac_put_sysfs_class();
}
/* scope is to module level only */
struct workqueue_struct *edac_workqueue;
-/*
- * sysfs object: /sys/devices/system/edac
- * need to export to other files in this modules
- */
-static struct sysdev_class edac_class = {
- .name = "edac",
-};
-static int edac_class_valid;
-
/*
* edac_op_state_to_string()
*/
return "UNKNOWN";
}
-/*
- * edac_get_edac_class()
- *
- * return pointer to the edac class of 'edac'
- */
-struct sysdev_class *edac_get_edac_class(void)
-{
- struct sysdev_class *classptr = NULL;
-
- if (edac_class_valid)
- classptr = &edac_class;
-
- return classptr;
-}
-
-/*
- * edac_register_sysfs_edac_name()
- *
- * register the 'edac' into /sys/devices/system
- *
- * return:
- * 0 success
- * !0 error
- */
-static int edac_register_sysfs_edac_name(void)
-{
- int err;
-
- /* create the /sys/devices/system/edac directory */
- err = sysdev_class_register(&edac_class);
-
- if (err) {
- debugf1("%s() error=%d\n", __func__, err);
- return err;
- }
-
- edac_class_valid = 1;
- return 0;
-}
-
-/*
- * sysdev_class_unregister()
- *
- * unregister the 'edac' from /sys/devices/system
- */
-static void edac_unregister_sysfs_edac_name(void)
-{
- /* only if currently registered, then unregister it */
- if (edac_class_valid)
- sysdev_class_unregister(&edac_class);
-
- edac_class_valid = 0;
-}
-
/*
* edac_workqueue_setup
* initialize the edac work queue for polling operations
*/
edac_pci_clear_parity_errors();
- /*
- * perform the registration of the /sys/devices/system/edac class object
- */
- if (edac_register_sysfs_edac_name()) {
- edac_printk(KERN_ERR, EDAC_MC,
- "Error initializing 'edac' kobject\n");
- err = -ENODEV;
- goto error;
- }
-
/*
* now set up the mc_kset under the edac class object
*/
err = edac_sysfs_setup_mc_kset();
if (err)
- goto sysfs_setup_fail;
+ goto error;
/* Setup/Initialize the workq for this core */
err = edac_workqueue_setup();
workq_fail:
edac_sysfs_teardown_mc_kset();
-sysfs_setup_fail:
- edac_unregister_sysfs_edac_name();
-
error:
return err;
}
/* tear down the various subsystems */
edac_workqueue_teardown();
edac_sysfs_teardown_mc_kset();
- edac_unregister_sysfs_edac_name();
}
/*
struct edac_device_ctl_info *edac_dev);
extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
-extern struct sysdev_class *edac_get_edac_class(void);
/* edac core workqueue: single CPU mode */
extern struct workqueue_struct *edac_workqueue;
*
*/
#include <linux/module.h>
-#include <linux/sysdev.h>
+#include <linux/edac.h>
#include <linux/slab.h>
#include <linux/ctype.h>
/* First time, so create the main kobject and its
* controls and atributes
*/
- edac_class = edac_get_edac_class();
+ edac_class = edac_get_sysfs_class();
if (edac_class == NULL) {
debugf1("%s() no edac_class\n", __func__);
err = -ENODEV;
if (!try_module_get(THIS_MODULE)) {
debugf1("%s() try_module_get() failed\n", __func__);
err = -ENODEV;
- goto decrement_count_fail;
+ goto mod_get_fail;
}
edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
kzalloc_fail:
module_put(THIS_MODULE);
+mod_get_fail:
+ edac_put_sysfs_class();
+
decrement_count_fail:
/* if are on this error exit, nothing to tear down */
atomic_dec(&edac_pci_sysfs_refcount);
__func__);
kobject_put(edac_pci_top_main_kobj);
}
+ edac_put_sysfs_class();
}
/*
*
* Author: Dave Jiang <djiang@mvista.com>
*
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * 2007 (c) MontaVista Software, Inc.
+ * 2010 (c) Advanced Micro Devices Inc.
+ * Borislav Petkov <borislav.petkov@amd.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
*
*/
#include <linux/module.h>
int edac_err_assert = 0;
EXPORT_SYMBOL_GPL(edac_err_assert);
+static atomic_t edac_class_valid = ATOMIC_INIT(0);
+
/*
* called to determine if there is an EDAC driver interested in
* knowing an event (such as NMI) occurred
edac_err_assert++;
}
EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
+
+/*
+ * sysfs object: /sys/devices/system/edac
+ * need to export to other files
+ */
+struct sysdev_class edac_class = {
+ .name = "edac",
+};
+EXPORT_SYMBOL_GPL(edac_class);
+
+/* return pointer to the 'edac' node in sysfs */
+struct sysdev_class *edac_get_sysfs_class(void)
+{
+ int err = 0;
+
+ if (atomic_read(&edac_class_valid))
+ goto out;
+
+ /* create the /sys/devices/system/edac directory */
+ err = sysdev_class_register(&edac_class);
+ if (err) {
+ printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
+ return NULL;
+ }
+
+out:
+ atomic_inc(&edac_class_valid);
+ return &edac_class;
+}
+EXPORT_SYMBOL_GPL(edac_get_sysfs_class);
+
+void edac_put_sysfs_class(void)
+{
+ /* last user unregisters it */
+ if (atomic_dec_and_test(&edac_class_valid))
+ sysdev_class_unregister(&edac_class);
+}
+EXPORT_SYMBOL_GPL(edac_put_sysfs_class);
#define _LINUX_EDAC_H_
#include <asm/atomic.h>
+#include <linux/sysdev.h>
#define EDAC_OPSTATE_INVAL -1
#define EDAC_OPSTATE_POLL 0
extern int edac_op_state;
extern int edac_err_assert;
extern atomic_t edac_handlers;
+extern struct sysdev_class edac_class;
extern int edac_handler_set(void);
extern void edac_atomic_assert_error(void);
+extern struct sysdev_class *edac_get_sysfs_class(void);
+extern void edac_put_sysfs_class(void);
static inline void opstate_init(void)
{