aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ras/cec.c80
1 files changed, 42 insertions, 38 deletions
diff --git a/drivers/ras/cec.c b/drivers/ras/cec.c
index 88e4f3ff0cb8..673f8a128397 100644
--- a/drivers/ras/cec.c
+++ b/drivers/ras/cec.c
@@ -2,6 +2,7 @@
2#include <linux/mm.h> 2#include <linux/mm.h>
3#include <linux/gfp.h> 3#include <linux/gfp.h>
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/workqueue.h>
5 6
6#include <asm/mce.h> 7#include <asm/mce.h>
7 8
@@ -123,16 +124,12 @@ static u64 dfs_pfn;
123/* Amount of errors after which we offline */ 124/* Amount of errors after which we offline */
124static unsigned int count_threshold = COUNT_MASK; 125static unsigned int count_threshold = COUNT_MASK;
125 126
126/* 127/* Each element "decays" each decay_interval which is 24hrs by default. */
127 * The timer "decays" element count each timer_interval which is 24hrs by 128#define CEC_DECAY_DEFAULT_INTERVAL 24 * 60 * 60 /* 24 hrs */
128 * default. 129#define CEC_DECAY_MIN_INTERVAL 1 * 60 * 60 /* 1h */
129 */ 130#define CEC_DECAY_MAX_INTERVAL 30 * 24 * 60 * 60 /* one month */
130 131static struct delayed_work cec_work;
131#define CEC_TIMER_DEFAULT_INTERVAL 24 * 60 * 60 /* 24 hrs */ 132static u64 decay_interval = CEC_DECAY_DEFAULT_INTERVAL;
132#define CEC_TIMER_MIN_INTERVAL 1 * 60 * 60 /* 1h */
133#define CEC_TIMER_MAX_INTERVAL 30 * 24 * 60 * 60 /* one month */
134static struct timer_list cec_timer;
135static u64 timer_interval = CEC_TIMER_DEFAULT_INTERVAL;
136 133
137/* 134/*
138 * Decrement decay value. We're using DECAY_BITS bits to denote decay of an 135 * Decrement decay value. We're using DECAY_BITS bits to denote decay of an
@@ -160,20 +157,21 @@ static void do_spring_cleaning(struct ce_array *ca)
160/* 157/*
161 * @interval in seconds 158 * @interval in seconds
162 */ 159 */
163static void cec_mod_timer(struct timer_list *t, unsigned long interval) 160static void cec_mod_work(unsigned long interval)
164{ 161{
165 unsigned long iv; 162 unsigned long iv;
166 163
167 iv = interval * HZ + jiffies; 164 iv = interval * HZ;
168 165 mod_delayed_work(system_wq, &cec_work, round_jiffies(iv));
169 mod_timer(t, round_jiffies(iv));
170} 166}
171 167
172static void cec_timer_fn(struct timer_list *unused) 168static void cec_work_fn(struct work_struct *work)
173{ 169{
170 mutex_lock(&ce_mutex);
174 do_spring_cleaning(&ce_arr); 171 do_spring_cleaning(&ce_arr);
172 mutex_unlock(&ce_mutex);
175 173
176 cec_mod_timer(&cec_timer, timer_interval); 174 cec_mod_work(decay_interval);
177} 175}
178 176
179/* 177/*
@@ -183,32 +181,38 @@ static void cec_timer_fn(struct timer_list *unused)
183 */ 181 */
184static int __find_elem(struct ce_array *ca, u64 pfn, unsigned int *to) 182static int __find_elem(struct ce_array *ca, u64 pfn, unsigned int *to)
185{ 183{
184 int min = 0, max = ca->n - 1;
186 u64 this_pfn; 185 u64 this_pfn;
187 int min = 0, max = ca->n;
188 186
189 while (min < max) { 187 while (min <= max) {
190 int tmp = (max + min) >> 1; 188 int i = (min + max) >> 1;
191 189
192 this_pfn = PFN(ca->array[tmp]); 190 this_pfn = PFN(ca->array[i]);
193 191
194 if (this_pfn < pfn) 192 if (this_pfn < pfn)
195 min = tmp + 1; 193 min = i + 1;
196 else if (this_pfn > pfn) 194 else if (this_pfn > pfn)
197 max = tmp; 195 max = i - 1;
198 else { 196 else if (this_pfn == pfn) {
199 min = tmp; 197 if (to)
200 break; 198 *to = i;
199
200 return i;
201 } 201 }
202 } 202 }
203 203
204 /*
205 * When the loop terminates without finding @pfn, min has the index of
206 * the element slot where the new @pfn should be inserted. The loop
207 * terminates when min > max, which means the min index points to the
208 * bigger element while the max index to the smaller element, in-between
209 * which the new @pfn belongs to.
210 *
211 * For more details, see exercise 1, Section 6.2.1 in TAOCP, vol. 3.
212 */
204 if (to) 213 if (to)
205 *to = min; 214 *to = min;
206 215
207 this_pfn = PFN(ca->array[min]);
208
209 if (this_pfn == pfn)
210 return min;
211
212 return -ENOKEY; 216 return -ENOKEY;
213} 217}
214 218
@@ -374,15 +378,15 @@ static int decay_interval_set(void *data, u64 val)
374{ 378{
375 *(u64 *)data = val; 379 *(u64 *)data = val;
376 380
377 if (val < CEC_TIMER_MIN_INTERVAL) 381 if (val < CEC_DECAY_MIN_INTERVAL)
378 return -EINVAL; 382 return -EINVAL;
379 383
380 if (val > CEC_TIMER_MAX_INTERVAL) 384 if (val > CEC_DECAY_MAX_INTERVAL)
381 return -EINVAL; 385 return -EINVAL;
382 386
383 timer_interval = val; 387 decay_interval = val;
384 388
385 cec_mod_timer(&cec_timer, timer_interval); 389 cec_mod_work(decay_interval);
386 return 0; 390 return 0;
387} 391}
388DEFINE_DEBUGFS_ATTRIBUTE(decay_interval_ops, u64_get, decay_interval_set, "%lld\n"); 392DEFINE_DEBUGFS_ATTRIBUTE(decay_interval_ops, u64_get, decay_interval_set, "%lld\n");
@@ -426,7 +430,7 @@ static int array_dump(struct seq_file *m, void *v)
426 430
427 seq_printf(m, "Flags: 0x%x\n", ca->flags); 431 seq_printf(m, "Flags: 0x%x\n", ca->flags);
428 432
429 seq_printf(m, "Timer interval: %lld seconds\n", timer_interval); 433 seq_printf(m, "Decay interval: %lld seconds\n", decay_interval);
430 seq_printf(m, "Decays: %lld\n", ca->decays_done); 434 seq_printf(m, "Decays: %lld\n", ca->decays_done);
431 435
432 seq_printf(m, "Action threshold: %d\n", count_threshold); 436 seq_printf(m, "Action threshold: %d\n", count_threshold);
@@ -472,7 +476,7 @@ static int __init create_debugfs_nodes(void)
472 } 476 }
473 477
474 decay = debugfs_create_file("decay_interval", S_IRUSR | S_IWUSR, d, 478 decay = debugfs_create_file("decay_interval", S_IRUSR | S_IWUSR, d,
475 &timer_interval, &decay_interval_ops); 479 &decay_interval, &decay_interval_ops);
476 if (!decay) { 480 if (!decay) {
477 pr_warn("Error creating decay_interval debugfs node!\n"); 481 pr_warn("Error creating decay_interval debugfs node!\n");
478 goto err; 482 goto err;
@@ -508,8 +512,8 @@ void __init cec_init(void)
508 if (create_debugfs_nodes()) 512 if (create_debugfs_nodes())
509 return; 513 return;
510 514
511 timer_setup(&cec_timer, cec_timer_fn, 0); 515 INIT_DELAYED_WORK(&cec_work, cec_work_fn);
512 cec_mod_timer(&cec_timer, CEC_TIMER_DEFAULT_INTERVAL); 516 schedule_delayed_work(&cec_work, CEC_DECAY_DEFAULT_INTERVAL);
513 517
514 pr_info("Correctable Errors collector initialized.\n"); 518 pr_info("Correctable Errors collector initialized.\n");
515} 519}