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