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