1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39#include <linux/capability.h>
40#include <linux/cpu.h>
41#include <linux/types.h>
42#include <linux/proc_fs.h>
43#include <linux/seq_file.h>
44#include <linux/module.h>
45#include <linux/smp.h>
46#include <linux/timer.h>
47#include <linux/vmalloc.h>
48#include <linux/semaphore.h>
49
50#include <asm/sal.h>
51#include <asm/uaccess.h>
52
53MODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>");
54MODULE_DESCRIPTION("/proc interface to IA-64 SAL features");
55MODULE_LICENSE("GPL");
56
57static const struct file_operations proc_salinfo_fops;
58
59typedef struct {
60 const char *name;
61 unsigned long feature;
62 struct proc_dir_entry *entry;
63} salinfo_entry_t;
64
65
66
67
68
69static const salinfo_entry_t salinfo_entries[]={
70 { "bus_lock", IA64_SAL_PLATFORM_FEATURE_BUS_LOCK, },
71 { "irq_redirection", IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT, },
72 { "ipi_redirection", IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT, },
73 { "itc_drift", IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, },
74};
75
76#define NR_SALINFO_ENTRIES ARRAY_SIZE(salinfo_entries)
77
78static char *salinfo_log_name[] = {
79 "mca",
80 "init",
81 "cmc",
82 "cpe",
83};
84
85static struct proc_dir_entry *salinfo_proc_entries[
86 ARRAY_SIZE(salinfo_entries) +
87 ARRAY_SIZE(salinfo_log_name) +
88 (2 * ARRAY_SIZE(salinfo_log_name)) +
89 1];
90
91
92
93
94struct salinfo_data_saved {
95 u8* buffer;
96 u64 size;
97 u64 id;
98 int cpu;
99};
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136enum salinfo_state {
137 STATE_NO_DATA,
138 STATE_LOG_RECORD,
139 STATE_OEMDATA,
140};
141
142struct salinfo_data {
143 cpumask_t cpu_event;
144 struct semaphore mutex;
145 u8 *log_buffer;
146 u64 log_size;
147 u8 *oemdata;
148 u64 oemdata_size;
149 int open;
150 u8 type;
151 u8 saved_num;
152 enum salinfo_state state :8;
153 u8 padding;
154 int cpu_check;
155 struct salinfo_data_saved data_saved[5];
156};
157
158static struct salinfo_data salinfo_data[ARRAY_SIZE(salinfo_log_name)];
159
160static DEFINE_SPINLOCK(data_lock);
161static DEFINE_SPINLOCK(data_saved_lock);
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176int (*salinfo_platform_oemdata)(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size);
177
178struct salinfo_platform_oemdata_parms {
179 const u8 *efi_guid;
180 u8 **oemdata;
181 u64 *oemdata_size;
182 int ret;
183};
184
185
186
187
188
189
190
191
192
193static void
194salinfo_work_to_do(struct salinfo_data *data)
195{
196 (void)(down_trylock(&data->mutex) ?: 0);
197 up(&data->mutex);
198}
199
200static void
201salinfo_platform_oemdata_cpu(void *context)
202{
203 struct salinfo_platform_oemdata_parms *parms = context;
204 parms->ret = salinfo_platform_oemdata(parms->efi_guid, parms->oemdata, parms->oemdata_size);
205}
206
207static void
208shift1_data_saved (struct salinfo_data *data, int shift)
209{
210 memcpy(data->data_saved+shift, data->data_saved+shift+1,
211 (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0]));
212 memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0,
213 sizeof(data->data_saved[0]));
214}
215
216
217
218
219
220
221
222
223
224
225
226
227void
228salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe)
229{
230 struct salinfo_data *data = salinfo_data + type;
231 struct salinfo_data_saved *data_saved;
232 unsigned long flags = 0;
233 int i;
234 int saved_size = ARRAY_SIZE(data->data_saved);
235
236 BUG_ON(type >= ARRAY_SIZE(salinfo_log_name));
237
238 if (irqsafe)
239 spin_lock_irqsave(&data_saved_lock, flags);
240 if (buffer) {
241 for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
242 if (!data_saved->buffer)
243 break;
244 }
245 if (i == saved_size) {
246 if (!data->saved_num) {
247 shift1_data_saved(data, 0);
248 data_saved = data->data_saved + saved_size - 1;
249 } else
250 data_saved = NULL;
251 }
252 if (data_saved) {
253 data_saved->cpu = smp_processor_id();
254 data_saved->id = ((sal_log_record_header_t *)buffer)->id;
255 data_saved->size = size;
256 data_saved->buffer = buffer;
257 }
258 }
259 cpu_set(smp_processor_id(), data->cpu_event);
260 if (irqsafe) {
261 salinfo_work_to_do(data);
262 spin_unlock_irqrestore(&data_saved_lock, flags);
263 }
264}
265
266
267#define SALINFO_TIMER_DELAY (60*HZ)
268static struct timer_list salinfo_timer;
269extern void ia64_mlogbuf_dump(void);
270
271static void
272salinfo_timeout_check(struct salinfo_data *data)
273{
274 unsigned long flags;
275 if (!data->open)
276 return;
277 if (!cpus_empty(data->cpu_event)) {
278 spin_lock_irqsave(&data_saved_lock, flags);
279 salinfo_work_to_do(data);
280 spin_unlock_irqrestore(&data_saved_lock, flags);
281 }
282}
283
284static void
285salinfo_timeout (unsigned long arg)
286{
287 ia64_mlogbuf_dump();
288 salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
289 salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT);
290 salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
291 add_timer(&salinfo_timer);
292}
293
294static int
295salinfo_event_open(struct inode *inode, struct file *file)
296{
297 if (!capable(CAP_SYS_ADMIN))
298 return -EPERM;
299 return 0;
300}
301
302static ssize_t
303salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
304{
305 struct salinfo_data *data = PDE_DATA(file_inode(file));
306 char cmd[32];
307 size_t size;
308 int i, n, cpu = -1;
309
310retry:
311 if (cpus_empty(data->cpu_event) && down_trylock(&data->mutex)) {
312 if (file->f_flags & O_NONBLOCK)
313 return -EAGAIN;
314 if (down_interruptible(&data->mutex))
315 return -EINTR;
316 }
317
318 n = data->cpu_check;
319 for (i = 0; i < nr_cpu_ids; i++) {
320 if (cpu_isset(n, data->cpu_event)) {
321 if (!cpu_online(n)) {
322 cpu_clear(n, data->cpu_event);
323 continue;
324 }
325 cpu = n;
326 break;
327 }
328 if (++n == nr_cpu_ids)
329 n = 0;
330 }
331
332 if (cpu == -1)
333 goto retry;
334
335 ia64_mlogbuf_dump();
336
337
338 data->cpu_check = cpu;
339 if (++data->cpu_check == nr_cpu_ids)
340 data->cpu_check = 0;
341
342 snprintf(cmd, sizeof(cmd), "read %d\n", cpu);
343
344 size = strlen(cmd);
345 if (size > count)
346 size = count;
347 if (copy_to_user(buffer, cmd, size))
348 return -EFAULT;
349
350 return size;
351}
352
353static const struct file_operations salinfo_event_fops = {
354 .open = salinfo_event_open,
355 .read = salinfo_event_read,
356 .llseek = noop_llseek,
357};
358
359static int
360salinfo_log_open(struct inode *inode, struct file *file)
361{
362 struct salinfo_data *data = PDE_DATA(inode);
363
364 if (!capable(CAP_SYS_ADMIN))
365 return -EPERM;
366
367 spin_lock(&data_lock);
368 if (data->open) {
369 spin_unlock(&data_lock);
370 return -EBUSY;
371 }
372 data->open = 1;
373 spin_unlock(&data_lock);
374
375 if (data->state == STATE_NO_DATA &&
376 !(data->log_buffer = vmalloc(ia64_sal_get_state_info_size(data->type)))) {
377 data->open = 0;
378 return -ENOMEM;
379 }
380
381 return 0;
382}
383
384static int
385salinfo_log_release(struct inode *inode, struct file *file)
386{
387 struct salinfo_data *data = PDE_DATA(inode);
388
389 if (data->state == STATE_NO_DATA) {
390 vfree(data->log_buffer);
391 vfree(data->oemdata);
392 data->log_buffer = NULL;
393 data->oemdata = NULL;
394 }
395 spin_lock(&data_lock);
396 data->open = 0;
397 spin_unlock(&data_lock);
398 return 0;
399}
400
401static void
402call_on_cpu(int cpu, void (*fn)(void *), void *arg)
403{
404 cpumask_t save_cpus_allowed = current->cpus_allowed;
405 set_cpus_allowed_ptr(current, cpumask_of(cpu));
406 (*fn)(arg);
407 set_cpus_allowed_ptr(current, &save_cpus_allowed);
408}
409
410static void
411salinfo_log_read_cpu(void *context)
412{
413 struct salinfo_data *data = context;
414 sal_log_record_header_t *rh;
415 data->log_size = ia64_sal_get_state_info(data->type, (u64 *) data->log_buffer);
416 rh = (sal_log_record_header_t *)(data->log_buffer);
417
418 if (rh->severity == sal_log_severity_corrected)
419 ia64_sal_clear_state_info(data->type);
420}
421
422static void
423salinfo_log_new_read(int cpu, struct salinfo_data *data)
424{
425 struct salinfo_data_saved *data_saved;
426 unsigned long flags;
427 int i;
428 int saved_size = ARRAY_SIZE(data->data_saved);
429
430 data->saved_num = 0;
431 spin_lock_irqsave(&data_saved_lock, flags);
432retry:
433 for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
434 if (data_saved->buffer && data_saved->cpu == cpu) {
435 sal_log_record_header_t *rh = (sal_log_record_header_t *)(data_saved->buffer);
436 data->log_size = data_saved->size;
437 memcpy(data->log_buffer, rh, data->log_size);
438 barrier();
439 if (rh->id == data_saved->id) {
440 data->saved_num = i+1;
441 break;
442 }
443
444 shift1_data_saved(data, i);
445 goto retry;
446 }
447 }
448 spin_unlock_irqrestore(&data_saved_lock, flags);
449
450 if (!data->saved_num)
451 call_on_cpu(cpu, salinfo_log_read_cpu, data);
452 if (!data->log_size) {
453 data->state = STATE_NO_DATA;
454 cpu_clear(cpu, data->cpu_event);
455 } else {
456 data->state = STATE_LOG_RECORD;
457 }
458}
459
460static ssize_t
461salinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
462{
463 struct salinfo_data *data = PDE_DATA(file_inode(file));
464 u8 *buf;
465 u64 bufsize;
466
467 if (data->state == STATE_LOG_RECORD) {
468 buf = data->log_buffer;
469 bufsize = data->log_size;
470 } else if (data->state == STATE_OEMDATA) {
471 buf = data->oemdata;
472 bufsize = data->oemdata_size;
473 } else {
474 buf = NULL;
475 bufsize = 0;
476 }
477 return simple_read_from_buffer(buffer, count, ppos, buf, bufsize);
478}
479
480static void
481salinfo_log_clear_cpu(void *context)
482{
483 struct salinfo_data *data = context;
484 ia64_sal_clear_state_info(data->type);
485}
486
487static int
488salinfo_log_clear(struct salinfo_data *data, int cpu)
489{
490 sal_log_record_header_t *rh;
491 unsigned long flags;
492 spin_lock_irqsave(&data_saved_lock, flags);
493 data->state = STATE_NO_DATA;
494 if (!cpu_isset(cpu, data->cpu_event)) {
495 spin_unlock_irqrestore(&data_saved_lock, flags);
496 return 0;
497 }
498 cpu_clear(cpu, data->cpu_event);
499 if (data->saved_num) {
500 shift1_data_saved(data, data->saved_num - 1);
501 data->saved_num = 0;
502 }
503 spin_unlock_irqrestore(&data_saved_lock, flags);
504 rh = (sal_log_record_header_t *)(data->log_buffer);
505
506 if (rh->severity != sal_log_severity_corrected)
507 call_on_cpu(cpu, salinfo_log_clear_cpu, data);
508
509 salinfo_log_new_read(cpu, data);
510 if (data->state == STATE_LOG_RECORD) {
511 spin_lock_irqsave(&data_saved_lock, flags);
512 cpu_set(cpu, data->cpu_event);
513 salinfo_work_to_do(data);
514 spin_unlock_irqrestore(&data_saved_lock, flags);
515 }
516 return 0;
517}
518
519static ssize_t
520salinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
521{
522 struct salinfo_data *data = PDE_DATA(file_inode(file));
523 char cmd[32];
524 size_t size;
525 u32 offset;
526 int cpu;
527
528 size = sizeof(cmd);
529 if (count < size)
530 size = count;
531 if (copy_from_user(cmd, buffer, size))
532 return -EFAULT;
533
534 if (sscanf(cmd, "read %d", &cpu) == 1) {
535 salinfo_log_new_read(cpu, data);
536 } else if (sscanf(cmd, "clear %d", &cpu) == 1) {
537 int ret;
538 if ((ret = salinfo_log_clear(data, cpu)))
539 count = ret;
540 } else if (sscanf(cmd, "oemdata %d %d", &cpu, &offset) == 2) {
541 if (data->state != STATE_LOG_RECORD && data->state != STATE_OEMDATA)
542 return -EINVAL;
543 if (offset > data->log_size - sizeof(efi_guid_t))
544 return -EINVAL;
545 data->state = STATE_OEMDATA;
546 if (salinfo_platform_oemdata) {
547 struct salinfo_platform_oemdata_parms parms = {
548 .efi_guid = data->log_buffer + offset,
549 .oemdata = &data->oemdata,
550 .oemdata_size = &data->oemdata_size
551 };
552 call_on_cpu(cpu, salinfo_platform_oemdata_cpu, &parms);
553 if (parms.ret)
554 count = parms.ret;
555 } else
556 data->oemdata_size = 0;
557 } else
558 return -EINVAL;
559
560 return count;
561}
562
563static const struct file_operations salinfo_data_fops = {
564 .open = salinfo_log_open,
565 .release = salinfo_log_release,
566 .read = salinfo_log_read,
567 .write = salinfo_log_write,
568 .llseek = default_llseek,
569};
570
571static int
572salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
573{
574 unsigned int i, cpu = (unsigned long)hcpu;
575 unsigned long flags;
576 struct salinfo_data *data;
577 switch (action) {
578 case CPU_ONLINE:
579 case CPU_ONLINE_FROZEN:
580 spin_lock_irqsave(&data_saved_lock, flags);
581 for (i = 0, data = salinfo_data;
582 i < ARRAY_SIZE(salinfo_data);
583 ++i, ++data) {
584 cpu_set(cpu, data->cpu_event);
585 salinfo_work_to_do(data);
586 }
587 spin_unlock_irqrestore(&data_saved_lock, flags);
588 break;
589 case CPU_DEAD:
590 case CPU_DEAD_FROZEN:
591 spin_lock_irqsave(&data_saved_lock, flags);
592 for (i = 0, data = salinfo_data;
593 i < ARRAY_SIZE(salinfo_data);
594 ++i, ++data) {
595 struct salinfo_data_saved *data_saved;
596 int j;
597 for (j = ARRAY_SIZE(data->data_saved) - 1, data_saved = data->data_saved + j;
598 j >= 0;
599 --j, --data_saved) {
600 if (data_saved->buffer && data_saved->cpu == cpu) {
601 shift1_data_saved(data, j);
602 }
603 }
604 cpu_clear(cpu, data->cpu_event);
605 }
606 spin_unlock_irqrestore(&data_saved_lock, flags);
607 break;
608 }
609 return NOTIFY_OK;
610}
611
612static struct notifier_block salinfo_cpu_notifier =
613{
614 .notifier_call = salinfo_cpu_callback,
615 .priority = 0,
616};
617
618static int __init
619salinfo_init(void)
620{
621 struct proc_dir_entry *salinfo_dir;
622 struct proc_dir_entry **sdir = salinfo_proc_entries;
623 struct proc_dir_entry *dir, *entry;
624 struct salinfo_data *data;
625 int i, j;
626
627 salinfo_dir = proc_mkdir("sal", NULL);
628 if (!salinfo_dir)
629 return 0;
630
631 for (i=0; i < NR_SALINFO_ENTRIES; i++) {
632
633 *sdir++ = proc_create_data(salinfo_entries[i].name, 0, salinfo_dir,
634 &proc_salinfo_fops,
635 (void *)salinfo_entries[i].feature);
636 }
637
638 cpu_notifier_register_begin();
639
640 for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) {
641 data = salinfo_data + i;
642 data->type = i;
643 sema_init(&data->mutex, 1);
644 dir = proc_mkdir(salinfo_log_name[i], salinfo_dir);
645 if (!dir)
646 continue;
647
648 entry = proc_create_data("event", S_IRUSR, dir,
649 &salinfo_event_fops, data);
650 if (!entry)
651 continue;
652 *sdir++ = entry;
653
654 entry = proc_create_data("data", S_IRUSR | S_IWUSR, dir,
655 &salinfo_data_fops, data);
656 if (!entry)
657 continue;
658 *sdir++ = entry;
659
660
661 for_each_online_cpu(j)
662 cpu_set(j, data->cpu_event);
663
664 *sdir++ = dir;
665 }
666
667 *sdir++ = salinfo_dir;
668
669 init_timer(&salinfo_timer);
670 salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
671 salinfo_timer.function = &salinfo_timeout;
672 add_timer(&salinfo_timer);
673
674 __register_hotcpu_notifier(&salinfo_cpu_notifier);
675
676 cpu_notifier_register_done();
677
678 return 0;
679}
680
681
682
683
684
685static int proc_salinfo_show(struct seq_file *m, void *v)
686{
687 unsigned long data = (unsigned long)v;
688 seq_puts(m, (sal_platform_features & data) ? "1\n" : "0\n");
689 return 0;
690}
691
692static int proc_salinfo_open(struct inode *inode, struct file *file)
693{
694 return single_open(file, proc_salinfo_show, PDE_DATA(inode));
695}
696
697static const struct file_operations proc_salinfo_fops = {
698 .open = proc_salinfo_open,
699 .read = seq_read,
700 .llseek = seq_lseek,
701 .release = single_release,
702};
703
704module_init(salinfo_init);
705