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 <linux/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 wait_queue_head_t read_wait;
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
185static void
186salinfo_platform_oemdata_cpu(void *context)
187{
188 struct salinfo_platform_oemdata_parms *parms = context;
189 parms->ret = salinfo_platform_oemdata(parms->efi_guid, parms->oemdata, parms->oemdata_size);
190}
191
192static void
193shift1_data_saved (struct salinfo_data *data, int shift)
194{
195 memcpy(data->data_saved+shift, data->data_saved+shift+1,
196 (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0]));
197 memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0,
198 sizeof(data->data_saved[0]));
199}
200
201
202
203
204
205
206
207
208
209
210
211
212void
213salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe)
214{
215 struct salinfo_data *data = salinfo_data + type;
216 struct salinfo_data_saved *data_saved;
217 unsigned long flags = 0;
218 int i;
219 int saved_size = ARRAY_SIZE(data->data_saved);
220
221 BUG_ON(type >= ARRAY_SIZE(salinfo_log_name));
222
223 if (irqsafe)
224 spin_lock_irqsave(&data_saved_lock, flags);
225 if (buffer) {
226 for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
227 if (!data_saved->buffer)
228 break;
229 }
230 if (i == saved_size) {
231 if (!data->saved_num) {
232 shift1_data_saved(data, 0);
233 data_saved = data->data_saved + saved_size - 1;
234 } else
235 data_saved = NULL;
236 }
237 if (data_saved) {
238 data_saved->cpu = smp_processor_id();
239 data_saved->id = ((sal_log_record_header_t *)buffer)->id;
240 data_saved->size = size;
241 data_saved->buffer = buffer;
242 }
243 }
244 cpumask_set_cpu(smp_processor_id(), &data->cpu_event);
245 if (irqsafe) {
246 wake_up_interruptible(&data->read_wait);
247 spin_unlock_irqrestore(&data_saved_lock, flags);
248 }
249}
250
251
252#define SALINFO_TIMER_DELAY (60*HZ)
253static struct timer_list salinfo_timer;
254extern void ia64_mlogbuf_dump(void);
255
256static void
257salinfo_timeout_check(struct salinfo_data *data)
258{
259 if (!data->open)
260 return;
261 if (!cpumask_empty(&data->cpu_event))
262 wake_up_interruptible(&data->read_wait);
263}
264
265static void
266salinfo_timeout (unsigned long arg)
267{
268 ia64_mlogbuf_dump();
269 salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
270 salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT);
271 salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
272 add_timer(&salinfo_timer);
273}
274
275static int
276salinfo_event_open(struct inode *inode, struct file *file)
277{
278 if (!capable(CAP_SYS_ADMIN))
279 return -EPERM;
280 return 0;
281}
282
283static ssize_t
284salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
285{
286 struct salinfo_data *data = PDE_DATA(file_inode(file));
287 char cmd[32];
288 size_t size;
289 int i, n, cpu = -1;
290
291retry:
292 if (cpumask_empty(&data->cpu_event)) {
293 if (file->f_flags & O_NONBLOCK)
294 return -EAGAIN;
295 if (wait_event_interruptible(data->read_wait,
296 !cpumask_empty(&data->cpu_event)))
297 return -EINTR;
298 }
299
300 n = data->cpu_check;
301 for (i = 0; i < nr_cpu_ids; i++) {
302 if (cpumask_test_cpu(n, &data->cpu_event)) {
303 if (!cpu_online(n)) {
304 cpumask_clear_cpu(n, &data->cpu_event);
305 continue;
306 }
307 cpu = n;
308 break;
309 }
310 if (++n == nr_cpu_ids)
311 n = 0;
312 }
313
314 if (cpu == -1)
315 goto retry;
316
317 ia64_mlogbuf_dump();
318
319
320 data->cpu_check = cpu;
321 if (++data->cpu_check == nr_cpu_ids)
322 data->cpu_check = 0;
323
324 snprintf(cmd, sizeof(cmd), "read %d\n", cpu);
325
326 size = strlen(cmd);
327 if (size > count)
328 size = count;
329 if (copy_to_user(buffer, cmd, size))
330 return -EFAULT;
331
332 return size;
333}
334
335static const struct file_operations salinfo_event_fops = {
336 .open = salinfo_event_open,
337 .read = salinfo_event_read,
338 .llseek = noop_llseek,
339};
340
341static int
342salinfo_log_open(struct inode *inode, struct file *file)
343{
344 struct salinfo_data *data = PDE_DATA(inode);
345
346 if (!capable(CAP_SYS_ADMIN))
347 return -EPERM;
348
349 spin_lock(&data_lock);
350 if (data->open) {
351 spin_unlock(&data_lock);
352 return -EBUSY;
353 }
354 data->open = 1;
355 spin_unlock(&data_lock);
356
357 if (data->state == STATE_NO_DATA &&
358 !(data->log_buffer = vmalloc(ia64_sal_get_state_info_size(data->type)))) {
359 data->open = 0;
360 return -ENOMEM;
361 }
362
363 return 0;
364}
365
366static int
367salinfo_log_release(struct inode *inode, struct file *file)
368{
369 struct salinfo_data *data = PDE_DATA(inode);
370
371 if (data->state == STATE_NO_DATA) {
372 vfree(data->log_buffer);
373 vfree(data->oemdata);
374 data->log_buffer = NULL;
375 data->oemdata = NULL;
376 }
377 spin_lock(&data_lock);
378 data->open = 0;
379 spin_unlock(&data_lock);
380 return 0;
381}
382
383static void
384call_on_cpu(int cpu, void (*fn)(void *), void *arg)
385{
386 cpumask_t save_cpus_allowed = current->cpus_allowed;
387 set_cpus_allowed_ptr(current, cpumask_of(cpu));
388 (*fn)(arg);
389 set_cpus_allowed_ptr(current, &save_cpus_allowed);
390}
391
392static void
393salinfo_log_read_cpu(void *context)
394{
395 struct salinfo_data *data = context;
396 sal_log_record_header_t *rh;
397 data->log_size = ia64_sal_get_state_info(data->type, (u64 *) data->log_buffer);
398 rh = (sal_log_record_header_t *)(data->log_buffer);
399
400 if (rh->severity == sal_log_severity_corrected)
401 ia64_sal_clear_state_info(data->type);
402}
403
404static void
405salinfo_log_new_read(int cpu, struct salinfo_data *data)
406{
407 struct salinfo_data_saved *data_saved;
408 unsigned long flags;
409 int i;
410 int saved_size = ARRAY_SIZE(data->data_saved);
411
412 data->saved_num = 0;
413 spin_lock_irqsave(&data_saved_lock, flags);
414retry:
415 for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
416 if (data_saved->buffer && data_saved->cpu == cpu) {
417 sal_log_record_header_t *rh = (sal_log_record_header_t *)(data_saved->buffer);
418 data->log_size = data_saved->size;
419 memcpy(data->log_buffer, rh, data->log_size);
420 barrier();
421 if (rh->id == data_saved->id) {
422 data->saved_num = i+1;
423 break;
424 }
425
426 shift1_data_saved(data, i);
427 goto retry;
428 }
429 }
430 spin_unlock_irqrestore(&data_saved_lock, flags);
431
432 if (!data->saved_num)
433 call_on_cpu(cpu, salinfo_log_read_cpu, data);
434 if (!data->log_size) {
435 data->state = STATE_NO_DATA;
436 cpumask_clear_cpu(cpu, &data->cpu_event);
437 } else {
438 data->state = STATE_LOG_RECORD;
439 }
440}
441
442static ssize_t
443salinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
444{
445 struct salinfo_data *data = PDE_DATA(file_inode(file));
446 u8 *buf;
447 u64 bufsize;
448
449 if (data->state == STATE_LOG_RECORD) {
450 buf = data->log_buffer;
451 bufsize = data->log_size;
452 } else if (data->state == STATE_OEMDATA) {
453 buf = data->oemdata;
454 bufsize = data->oemdata_size;
455 } else {
456 buf = NULL;
457 bufsize = 0;
458 }
459 return simple_read_from_buffer(buffer, count, ppos, buf, bufsize);
460}
461
462static void
463salinfo_log_clear_cpu(void *context)
464{
465 struct salinfo_data *data = context;
466 ia64_sal_clear_state_info(data->type);
467}
468
469static int
470salinfo_log_clear(struct salinfo_data *data, int cpu)
471{
472 sal_log_record_header_t *rh;
473 unsigned long flags;
474 spin_lock_irqsave(&data_saved_lock, flags);
475 data->state = STATE_NO_DATA;
476 if (!cpumask_test_cpu(cpu, &data->cpu_event)) {
477 spin_unlock_irqrestore(&data_saved_lock, flags);
478 return 0;
479 }
480 cpumask_clear_cpu(cpu, &data->cpu_event);
481 if (data->saved_num) {
482 shift1_data_saved(data, data->saved_num - 1);
483 data->saved_num = 0;
484 }
485 spin_unlock_irqrestore(&data_saved_lock, flags);
486 rh = (sal_log_record_header_t *)(data->log_buffer);
487
488 if (rh->severity != sal_log_severity_corrected)
489 call_on_cpu(cpu, salinfo_log_clear_cpu, data);
490
491 salinfo_log_new_read(cpu, data);
492 if (data->state == STATE_LOG_RECORD) {
493 spin_lock_irqsave(&data_saved_lock, flags);
494 cpumask_set_cpu(cpu, &data->cpu_event);
495 wake_up_interruptible(&data->read_wait);
496 spin_unlock_irqrestore(&data_saved_lock, flags);
497 }
498 return 0;
499}
500
501static ssize_t
502salinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
503{
504 struct salinfo_data *data = PDE_DATA(file_inode(file));
505 char cmd[32];
506 size_t size;
507 u32 offset;
508 int cpu;
509
510 size = sizeof(cmd);
511 if (count < size)
512 size = count;
513 if (copy_from_user(cmd, buffer, size))
514 return -EFAULT;
515
516 if (sscanf(cmd, "read %d", &cpu) == 1) {
517 salinfo_log_new_read(cpu, data);
518 } else if (sscanf(cmd, "clear %d", &cpu) == 1) {
519 int ret;
520 if ((ret = salinfo_log_clear(data, cpu)))
521 count = ret;
522 } else if (sscanf(cmd, "oemdata %d %d", &cpu, &offset) == 2) {
523 if (data->state != STATE_LOG_RECORD && data->state != STATE_OEMDATA)
524 return -EINVAL;
525 if (offset > data->log_size - sizeof(efi_guid_t))
526 return -EINVAL;
527 data->state = STATE_OEMDATA;
528 if (salinfo_platform_oemdata) {
529 struct salinfo_platform_oemdata_parms parms = {
530 .efi_guid = data->log_buffer + offset,
531 .oemdata = &data->oemdata,
532 .oemdata_size = &data->oemdata_size
533 };
534 call_on_cpu(cpu, salinfo_platform_oemdata_cpu, &parms);
535 if (parms.ret)
536 count = parms.ret;
537 } else
538 data->oemdata_size = 0;
539 } else
540 return -EINVAL;
541
542 return count;
543}
544
545static const struct file_operations salinfo_data_fops = {
546 .open = salinfo_log_open,
547 .release = salinfo_log_release,
548 .read = salinfo_log_read,
549 .write = salinfo_log_write,
550 .llseek = default_llseek,
551};
552
553static int salinfo_cpu_online(unsigned int cpu)
554{
555 unsigned int i, end = ARRAY_SIZE(salinfo_data);
556 struct salinfo_data *data;
557
558 spin_lock_irq(&data_saved_lock);
559 for (i = 0, data = salinfo_data; i < end; ++i, ++data) {
560 cpumask_set_cpu(cpu, &data->cpu_event);
561 wake_up_interruptible(&data->read_wait);
562 }
563 spin_unlock_irq(&data_saved_lock);
564 return 0;
565}
566
567static int salinfo_cpu_pre_down(unsigned int cpu)
568{
569 unsigned int i, end = ARRAY_SIZE(salinfo_data);
570 struct salinfo_data *data;
571
572 spin_lock_irq(&data_saved_lock);
573 for (i = 0, data = salinfo_data; i < end; ++i, ++data) {
574 struct salinfo_data_saved *data_saved;
575 int j = ARRAY_SIZE(data->data_saved) - 1;
576
577 for (data_saved = data->data_saved + j; j >= 0;
578 --j, --data_saved) {
579 if (data_saved->buffer && data_saved->cpu == cpu)
580 shift1_data_saved(data, j);
581 }
582 cpumask_clear_cpu(cpu, &data->cpu_event);
583 }
584 spin_unlock_irq(&data_saved_lock);
585 return 0;
586}
587
588static int __init
589salinfo_init(void)
590{
591 struct proc_dir_entry *salinfo_dir;
592 struct proc_dir_entry **sdir = salinfo_proc_entries;
593 struct proc_dir_entry *dir, *entry;
594 struct salinfo_data *data;
595 int i;
596
597 salinfo_dir = proc_mkdir("sal", NULL);
598 if (!salinfo_dir)
599 return 0;
600
601 for (i=0; i < NR_SALINFO_ENTRIES; i++) {
602
603 *sdir++ = proc_create_data(salinfo_entries[i].name, 0, salinfo_dir,
604 &proc_salinfo_fops,
605 (void *)salinfo_entries[i].feature);
606 }
607
608 for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) {
609 data = salinfo_data + i;
610 data->type = i;
611 init_waitqueue_head(&data->read_wait);
612 dir = proc_mkdir(salinfo_log_name[i], salinfo_dir);
613 if (!dir)
614 continue;
615
616 entry = proc_create_data("event", S_IRUSR, dir,
617 &salinfo_event_fops, data);
618 if (!entry)
619 continue;
620 *sdir++ = entry;
621
622 entry = proc_create_data("data", S_IRUSR | S_IWUSR, dir,
623 &salinfo_data_fops, data);
624 if (!entry)
625 continue;
626 *sdir++ = entry;
627
628 *sdir++ = dir;
629 }
630
631 *sdir++ = salinfo_dir;
632
633 init_timer(&salinfo_timer);
634 salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
635 salinfo_timer.function = &salinfo_timeout;
636 add_timer(&salinfo_timer);
637
638 i = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "ia64/salinfo:online",
639 salinfo_cpu_online, salinfo_cpu_pre_down);
640 WARN_ON(i < 0);
641 return 0;
642}
643
644
645
646
647
648static int proc_salinfo_show(struct seq_file *m, void *v)
649{
650 unsigned long data = (unsigned long)v;
651 seq_puts(m, (sal_platform_features & data) ? "1\n" : "0\n");
652 return 0;
653}
654
655static int proc_salinfo_open(struct inode *inode, struct file *file)
656{
657 return single_open(file, proc_salinfo_show, PDE_DATA(inode));
658}
659
660static const struct file_operations proc_salinfo_fops = {
661 .open = proc_salinfo_open,
662 .read = seq_read,
663 .llseek = seq_lseek,
664 .release = single_release,
665};
666
667module_init(salinfo_init);
668