Commit 30e1f7a8 authored by Borislav Petkov's avatar Borislav Petkov Committed by Borislav Petkov

EDAC: Export edac sysfs class to users.

Move toplevel sysfs class to the stub and make it available to
non-modularized code too. Add proper refcounting of its users and move
the registration functionality into the reference counting routines.
Signed-off-by: default avatarBorislav Petkov <borislav.petkov@amd.com>
parent 7cfd4a87
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/edac.h>
#include "edac_core.h" #include "edac_core.h"
#include "edac_module.h" #include "edac_module.h"
...@@ -235,7 +236,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) ...@@ -235,7 +236,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
debugf1("%s()\n", __func__); debugf1("%s()\n", __func__);
/* get the /sys/devices/system/edac reference */ /* get the /sys/devices/system/edac reference */
edac_class = edac_get_edac_class(); edac_class = edac_get_sysfs_class();
if (edac_class == NULL) { if (edac_class == NULL) {
debugf1("%s() no edac_class error\n", __func__); debugf1("%s() no edac_class error\n", __func__);
err = -ENODEV; err = -ENODEV;
...@@ -255,7 +256,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) ...@@ -255,7 +256,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
if (!try_module_get(edac_dev->owner)) { if (!try_module_get(edac_dev->owner)) {
err = -ENODEV; err = -ENODEV;
goto err_out; goto err_mod_get;
} }
/* register */ /* register */
...@@ -282,6 +283,9 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) ...@@ -282,6 +283,9 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
err_kobj_reg: err_kobj_reg:
module_put(edac_dev->owner); module_put(edac_dev->owner);
err_mod_get:
edac_put_sysfs_class();
err_out: err_out:
return err; return err;
} }
...@@ -290,12 +294,11 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) ...@@ -290,12 +294,11 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
* edac_device_unregister_sysfs_main_kobj: * edac_device_unregister_sysfs_main_kobj:
* the '..../edac/<name>' kobject * the '..../edac/<name>' kobject
*/ */
void edac_device_unregister_sysfs_main_kobj( void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
struct edac_device_ctl_info *edac_dev)
{ {
debugf0("%s()\n", __func__); debugf0("%s()\n", __func__);
debugf4("%s() name of kobject is: %s\n", 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 * Unregister the edac device's kobject and
...@@ -304,7 +307,8 @@ void edac_device_unregister_sysfs_main_kobj( ...@@ -304,7 +307,8 @@ void edac_device_unregister_sysfs_main_kobj(
* a) module_put() this module * a) module_put() this module
* b) 'kfree' the memory * b) 'kfree' the memory
*/ */
kobject_put(&edac_dev->kobj); kobject_put(&dev->kobj);
edac_put_sysfs_class();
} }
/* edac_dev -> instance information */ /* edac_dev -> instance information */
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/edac.h>
#include <linux/bug.h> #include <linux/bug.h>
#include "edac_core.h" #include "edac_core.h"
...@@ -1017,7 +1018,7 @@ int edac_sysfs_setup_mc_kset(void) ...@@ -1017,7 +1018,7 @@ int edac_sysfs_setup_mc_kset(void)
debugf1("%s()\n", __func__); debugf1("%s()\n", __func__);
/* get the /sys/devices/system/edac class reference */ /* get the /sys/devices/system/edac class reference */
edac_class = edac_get_edac_class(); edac_class = edac_get_sysfs_class();
if (edac_class == NULL) { if (edac_class == NULL) {
debugf1("%s() no edac_class error=%d\n", __func__, err); debugf1("%s() no edac_class error=%d\n", __func__, err);
goto fail_out; goto fail_out;
...@@ -1028,15 +1029,16 @@ int edac_sysfs_setup_mc_kset(void) ...@@ -1028,15 +1029,16 @@ int edac_sysfs_setup_mc_kset(void)
if (!mc_kset) { if (!mc_kset) {
err = -ENOMEM; err = -ENOMEM;
debugf1("%s() Failed to register '.../edac/mc'\n", __func__); debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
goto fail_out; goto fail_kset;
} }
debugf1("%s() Registered '.../edac/mc' kobject\n", __func__); debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
return 0; return 0;
fail_kset:
edac_put_sysfs_class();
/* error unwind stack */
fail_out: fail_out:
return err; return err;
} }
...@@ -1049,5 +1051,6 @@ int edac_sysfs_setup_mc_kset(void) ...@@ -1049,5 +1051,6 @@ int edac_sysfs_setup_mc_kset(void)
void edac_sysfs_teardown_mc_kset(void) void edac_sysfs_teardown_mc_kset(void)
{ {
kset_unregister(mc_kset); kset_unregister(mc_kset);
edac_put_sysfs_class();
} }
...@@ -26,15 +26,6 @@ EXPORT_SYMBOL_GPL(edac_debug_level); ...@@ -26,15 +26,6 @@ EXPORT_SYMBOL_GPL(edac_debug_level);
/* scope is to module level only */ /* scope is to module level only */
struct workqueue_struct *edac_workqueue; 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() * edac_op_state_to_string()
*/ */
...@@ -54,60 +45,6 @@ char *edac_op_state_to_string(int opstate) ...@@ -54,60 +45,6 @@ char *edac_op_state_to_string(int opstate)
return "UNKNOWN"; 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 * edac_workqueue_setup
* initialize the edac work queue for polling operations * initialize the edac work queue for polling operations
...@@ -153,22 +90,12 @@ static int __init edac_init(void) ...@@ -153,22 +90,12 @@ static int __init edac_init(void)
*/ */
edac_pci_clear_parity_errors(); 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 * now set up the mc_kset under the edac class object
*/ */
err = edac_sysfs_setup_mc_kset(); err = edac_sysfs_setup_mc_kset();
if (err) if (err)
goto sysfs_setup_fail; goto error;
/* Setup/Initialize the workq for this core */ /* Setup/Initialize the workq for this core */
err = edac_workqueue_setup(); err = edac_workqueue_setup();
...@@ -183,9 +110,6 @@ static int __init edac_init(void) ...@@ -183,9 +110,6 @@ static int __init edac_init(void)
workq_fail: workq_fail:
edac_sysfs_teardown_mc_kset(); edac_sysfs_teardown_mc_kset();
sysfs_setup_fail:
edac_unregister_sysfs_edac_name();
error: error:
return err; return err;
} }
...@@ -201,7 +125,6 @@ static void __exit edac_exit(void) ...@@ -201,7 +125,6 @@ static void __exit edac_exit(void)
/* tear down the various subsystems */ /* tear down the various subsystems */
edac_workqueue_teardown(); edac_workqueue_teardown();
edac_sysfs_teardown_mc_kset(); edac_sysfs_teardown_mc_kset();
edac_unregister_sysfs_edac_name();
} }
/* /*
......
...@@ -42,7 +42,6 @@ extern void edac_device_unregister_sysfs_main_kobj( ...@@ -42,7 +42,6 @@ extern void edac_device_unregister_sysfs_main_kobj(
struct edac_device_ctl_info *edac_dev); struct edac_device_ctl_info *edac_dev);
extern int edac_device_create_sysfs(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 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 */ /* edac core workqueue: single CPU mode */
extern struct workqueue_struct *edac_workqueue; extern struct workqueue_struct *edac_workqueue;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/sysdev.h> #include <linux/edac.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ctype.h> #include <linux/ctype.h>
...@@ -354,7 +354,7 @@ static int edac_pci_main_kobj_setup(void) ...@@ -354,7 +354,7 @@ static int edac_pci_main_kobj_setup(void)
/* First time, so create the main kobject and its /* First time, so create the main kobject and its
* controls and atributes * controls and atributes
*/ */
edac_class = edac_get_edac_class(); edac_class = edac_get_sysfs_class();
if (edac_class == NULL) { if (edac_class == NULL) {
debugf1("%s() no edac_class\n", __func__); debugf1("%s() no edac_class\n", __func__);
err = -ENODEV; err = -ENODEV;
...@@ -368,7 +368,7 @@ static int edac_pci_main_kobj_setup(void) ...@@ -368,7 +368,7 @@ static int edac_pci_main_kobj_setup(void)
if (!try_module_get(THIS_MODULE)) { if (!try_module_get(THIS_MODULE)) {
debugf1("%s() try_module_get() failed\n", __func__); debugf1("%s() try_module_get() failed\n", __func__);
err = -ENODEV; err = -ENODEV;
goto decrement_count_fail; goto mod_get_fail;
} }
edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
...@@ -403,6 +403,9 @@ static int edac_pci_main_kobj_setup(void) ...@@ -403,6 +403,9 @@ static int edac_pci_main_kobj_setup(void)
kzalloc_fail: kzalloc_fail:
module_put(THIS_MODULE); module_put(THIS_MODULE);
mod_get_fail:
edac_put_sysfs_class();
decrement_count_fail: decrement_count_fail:
/* if are on this error exit, nothing to tear down */ /* if are on this error exit, nothing to tear down */
atomic_dec(&edac_pci_sysfs_refcount); atomic_dec(&edac_pci_sysfs_refcount);
...@@ -429,6 +432,7 @@ static void edac_pci_main_kobj_teardown(void) ...@@ -429,6 +432,7 @@ static void edac_pci_main_kobj_teardown(void)
__func__); __func__);
kobject_put(edac_pci_top_main_kobj); kobject_put(edac_pci_top_main_kobj);
} }
edac_put_sysfs_class();
} }
/* /*
......
...@@ -3,10 +3,13 @@ ...@@ -3,10 +3,13 @@
* *
* Author: Dave Jiang <djiang@mvista.com> * Author: Dave Jiang <djiang@mvista.com>
* *
* 2007 (c) MontaVista Software, Inc. This file is licensed under * 2007 (c) MontaVista Software, Inc.
* the terms of the GNU General Public License version 2. This program * 2010 (c) Advanced Micro Devices Inc.
* is licensed "as is" without any warranty of any kind, whether express * Borislav Petkov <borislav.petkov@amd.com>
* or implied. *
* 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> #include <linux/module.h>
...@@ -23,6 +26,8 @@ EXPORT_SYMBOL_GPL(edac_handlers); ...@@ -23,6 +26,8 @@ EXPORT_SYMBOL_GPL(edac_handlers);
int edac_err_assert = 0; int edac_err_assert = 0;
EXPORT_SYMBOL_GPL(edac_err_assert); 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 * called to determine if there is an EDAC driver interested in
* knowing an event (such as NMI) occurred * knowing an event (such as NMI) occurred
...@@ -44,3 +49,41 @@ void edac_atomic_assert_error(void) ...@@ -44,3 +49,41 @@ void edac_atomic_assert_error(void)
edac_err_assert++; edac_err_assert++;
} }
EXPORT_SYMBOL_GPL(edac_atomic_assert_error); 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);
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define _LINUX_EDAC_H_ #define _LINUX_EDAC_H_
#include <asm/atomic.h> #include <asm/atomic.h>
#include <linux/sysdev.h>
#define EDAC_OPSTATE_INVAL -1 #define EDAC_OPSTATE_INVAL -1
#define EDAC_OPSTATE_POLL 0 #define EDAC_OPSTATE_POLL 0
...@@ -22,9 +23,12 @@ ...@@ -22,9 +23,12 @@
extern int edac_op_state; extern int edac_op_state;
extern int edac_err_assert; extern int edac_err_assert;
extern atomic_t edac_handlers; extern atomic_t edac_handlers;
extern struct sysdev_class edac_class;
extern int edac_handler_set(void); extern int edac_handler_set(void);
extern void edac_atomic_assert_error(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) static inline void opstate_init(void)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment