diff options
Diffstat (limited to 'drivers/edac/edac_mc.c')
-rw-r--r-- | drivers/edac/edac_mc.c | 88 |
1 files changed, 10 insertions, 78 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 9c205274c1cb..8a7a3ab745aa 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/sysdev.h> | 30 | #include <linux/sysdev.h> |
31 | #include <linux/ctype.h> | 31 | #include <linux/ctype.h> |
32 | #include <linux/kthread.h> | ||
32 | 33 | ||
33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
34 | #include <asm/page.h> | 35 | #include <asm/page.h> |
@@ -64,6 +65,8 @@ static atomic_t pci_parity_count = ATOMIC_INIT(0); | |||
64 | static DECLARE_MUTEX(mem_ctls_mutex); | 65 | static DECLARE_MUTEX(mem_ctls_mutex); |
65 | static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); | 66 | static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); |
66 | 67 | ||
68 | static struct task_struct *edac_thread; | ||
69 | |||
67 | /* Structure of the whitelist and blacklist arrays */ | 70 | /* Structure of the whitelist and blacklist arrays */ |
68 | struct edac_pci_device_list { | 71 | struct edac_pci_device_list { |
69 | unsigned int vendor; /* Vendor ID */ | 72 | unsigned int vendor; /* Vendor ID */ |
@@ -2073,7 +2076,6 @@ static inline void check_mc_devices (void) | |||
2073 | */ | 2076 | */ |
2074 | static void do_edac_check(void) | 2077 | static void do_edac_check(void) |
2075 | { | 2078 | { |
2076 | |||
2077 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 2079 | debugf3("MC: " __FILE__ ": %s()\n", __func__); |
2078 | 2080 | ||
2079 | check_mc_devices(); | 2081 | check_mc_devices(); |
@@ -2081,62 +2083,16 @@ static void do_edac_check(void) | |||
2081 | do_pci_parity_check(); | 2083 | do_pci_parity_check(); |
2082 | } | 2084 | } |
2083 | 2085 | ||
2084 | |||
2085 | /* | ||
2086 | * EDAC thread state information | ||
2087 | */ | ||
2088 | struct bs_thread_info | ||
2089 | { | ||
2090 | struct task_struct *task; | ||
2091 | struct completion *event; | ||
2092 | char *name; | ||
2093 | void (*run)(void); | ||
2094 | }; | ||
2095 | |||
2096 | static struct bs_thread_info bs_thread; | ||
2097 | |||
2098 | /* | ||
2099 | * edac_kernel_thread | ||
2100 | * This the kernel thread that processes edac operations | ||
2101 | * in a normal thread environment | ||
2102 | */ | ||
2103 | static int edac_kernel_thread(void *arg) | 2086 | static int edac_kernel_thread(void *arg) |
2104 | { | 2087 | { |
2105 | struct bs_thread_info *thread = (struct bs_thread_info *) arg; | 2088 | while (!kthread_should_stop()) { |
2106 | 2089 | do_edac_check(); | |
2107 | /* detach thread */ | ||
2108 | daemonize(thread->name); | ||
2109 | |||
2110 | current->exit_signal = SIGCHLD; | ||
2111 | allow_signal(SIGKILL); | ||
2112 | thread->task = current; | ||
2113 | |||
2114 | /* indicate to starting task we have started */ | ||
2115 | complete(thread->event); | ||
2116 | |||
2117 | /* loop forever, until we are told to stop */ | ||
2118 | while(thread->run != NULL) { | ||
2119 | void (*run)(void); | ||
2120 | |||
2121 | /* call the function to check the memory controllers */ | ||
2122 | run = thread->run; | ||
2123 | if (run) | ||
2124 | run(); | ||
2125 | |||
2126 | if (signal_pending(current)) | ||
2127 | flush_signals(current); | ||
2128 | |||
2129 | /* ensure we are interruptable */ | ||
2130 | set_current_state(TASK_INTERRUPTIBLE); | ||
2131 | 2090 | ||
2132 | /* goto sleep for the interval */ | 2091 | /* goto sleep for the interval */ |
2133 | schedule_timeout((HZ * poll_msec) / 1000); | 2092 | schedule_timeout_interruptible((HZ * poll_msec) / 1000); |
2134 | try_to_freeze(); | 2093 | try_to_freeze(); |
2135 | } | 2094 | } |
2136 | 2095 | ||
2137 | /* notify waiter that we are exiting */ | ||
2138 | complete(thread->event); | ||
2139 | |||
2140 | return 0; | 2096 | return 0; |
2141 | } | 2097 | } |
2142 | 2098 | ||
@@ -2146,9 +2102,6 @@ static int edac_kernel_thread(void *arg) | |||
2146 | */ | 2102 | */ |
2147 | static int __init edac_mc_init(void) | 2103 | static int __init edac_mc_init(void) |
2148 | { | 2104 | { |
2149 | int ret; | ||
2150 | struct completion event; | ||
2151 | |||
2152 | printk(KERN_INFO "MC: " __FILE__ " version " EDAC_MC_VERSION "\n"); | 2105 | printk(KERN_INFO "MC: " __FILE__ " version " EDAC_MC_VERSION "\n"); |
2153 | 2106 | ||
2154 | /* | 2107 | /* |
@@ -2176,24 +2129,15 @@ static int __init edac_mc_init(void) | |||
2176 | return -ENODEV; | 2129 | return -ENODEV; |
2177 | } | 2130 | } |
2178 | 2131 | ||
2179 | /* Create our kernel thread */ | ||
2180 | init_completion(&event); | ||
2181 | bs_thread.event = &event; | ||
2182 | bs_thread.name = "kedac"; | ||
2183 | bs_thread.run = do_edac_check; | ||
2184 | |||
2185 | /* create our kernel thread */ | 2132 | /* create our kernel thread */ |
2186 | ret = kernel_thread(edac_kernel_thread, &bs_thread, CLONE_KERNEL); | 2133 | edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac"); |
2187 | if (ret < 0) { | 2134 | if (IS_ERR(edac_thread)) { |
2188 | /* remove the sysfs entries */ | 2135 | /* remove the sysfs entries */ |
2189 | edac_sysfs_memctrl_teardown(); | 2136 | edac_sysfs_memctrl_teardown(); |
2190 | edac_sysfs_pci_teardown(); | 2137 | edac_sysfs_pci_teardown(); |
2191 | return -ENOMEM; | 2138 | return PTR_ERR(edac_thread); |
2192 | } | 2139 | } |
2193 | 2140 | ||
2194 | /* wait for our kernel theard ack that it is up and running */ | ||
2195 | wait_for_completion(&event); | ||
2196 | |||
2197 | return 0; | 2141 | return 0; |
2198 | } | 2142 | } |
2199 | 2143 | ||
@@ -2204,21 +2148,9 @@ static int __init edac_mc_init(void) | |||
2204 | */ | 2148 | */ |
2205 | static void __exit edac_mc_exit(void) | 2149 | static void __exit edac_mc_exit(void) |
2206 | { | 2150 | { |
2207 | struct completion event; | ||
2208 | |||
2209 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 2151 | debugf0("MC: " __FILE__ ": %s()\n", __func__); |
2210 | 2152 | ||
2211 | init_completion(&event); | 2153 | kthread_stop(edac_thread); |
2212 | bs_thread.event = &event; | ||
2213 | |||
2214 | /* As soon as ->run is set to NULL, the task could disappear, | ||
2215 | * so we need to hold tasklist_lock until we have sent the signal | ||
2216 | */ | ||
2217 | read_lock(&tasklist_lock); | ||
2218 | bs_thread.run = NULL; | ||
2219 | send_sig(SIGKILL, bs_thread.task, 1); | ||
2220 | read_unlock(&tasklist_lock); | ||
2221 | wait_for_completion(&event); | ||
2222 | 2154 | ||
2223 | /* tear down the sysfs device */ | 2155 | /* tear down the sysfs device */ |
2224 | edac_sysfs_memctrl_teardown(); | 2156 | edac_sysfs_memctrl_teardown(); |