diff options
-rw-r--r-- | Documentation/ramoops.txt | 25 | ||||
-rw-r--r-- | fs/pstore/ram.c | 37 | ||||
-rw-r--r-- | include/linux/pstore_ram.h | 1 |
3 files changed, 59 insertions, 4 deletions
diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt index 59a74a8ee2e5..197ad59ab9bf 100644 --- a/Documentation/ramoops.txt +++ b/Documentation/ramoops.txt | |||
@@ -94,3 +94,28 @@ timestamp and a new line. The dump then continues with the actual data. | |||
94 | The dump data can be read from the pstore filesystem. The format for these | 94 | The dump data can be read from the pstore filesystem. The format for these |
95 | files is "dmesg-ramoops-N", where N is the record number in memory. To delete | 95 | files is "dmesg-ramoops-N", where N is the record number in memory. To delete |
96 | a stored record from RAM, simply unlink the respective pstore file. | 96 | a stored record from RAM, simply unlink the respective pstore file. |
97 | |||
98 | 5. Persistent function tracing | ||
99 | |||
100 | Persistent function tracing might be useful for debugging software or hardware | ||
101 | related hangs. The functions call chain log is stored in a "ftrace-ramoops" | ||
102 | file. Here is an example of usage: | ||
103 | |||
104 | # mount -t debugfs debugfs /sys/kernel/debug/ | ||
105 | # cd /sys/kernel/debug/tracing | ||
106 | # echo function > current_tracer | ||
107 | # echo 1 > options/func_pstore | ||
108 | # reboot -f | ||
109 | [...] | ||
110 | # mount -t pstore pstore /mnt/ | ||
111 | # tail /mnt/ftrace-ramoops | ||
112 | 0 ffffffff8101ea64 ffffffff8101bcda native_apic_mem_read <- disconnect_bsp_APIC+0x6a/0xc0 | ||
113 | 0 ffffffff8101ea44 ffffffff8101bcf6 native_apic_mem_write <- disconnect_bsp_APIC+0x86/0xc0 | ||
114 | 0 ffffffff81020084 ffffffff8101a4b5 hpet_disable <- native_machine_shutdown+0x75/0x90 | ||
115 | 0 ffffffff81005f94 ffffffff8101a4bb iommu_shutdown_noop <- native_machine_shutdown+0x7b/0x90 | ||
116 | 0 ffffffff8101a6a1 ffffffff8101a437 native_machine_emergency_restart <- native_machine_restart+0x37/0x40 | ||
117 | 0 ffffffff811f9876 ffffffff8101a73a acpi_reboot <- native_machine_emergency_restart+0xaa/0x1e0 | ||
118 | 0 ffffffff8101a514 ffffffff8101a772 mach_reboot_fixups <- native_machine_emergency_restart+0xe2/0x1e0 | ||
119 | 0 ffffffff811d9c54 ffffffff8101a7a0 __const_udelay <- native_machine_emergency_restart+0x110/0x1e0 | ||
120 | 0 ffffffff811d9c34 ffffffff811d9c80 __delay <- __const_udelay+0x30/0x40 | ||
121 | 0 ffffffff811d9d14 ffffffff811d9c3f delay_tsc <- __delay+0xf/0x20 | ||
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 74f4111bd0da..1dd108e0cc60 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c | |||
@@ -45,6 +45,10 @@ static ulong ramoops_console_size = MIN_MEM_SIZE; | |||
45 | module_param_named(console_size, ramoops_console_size, ulong, 0400); | 45 | module_param_named(console_size, ramoops_console_size, ulong, 0400); |
46 | MODULE_PARM_DESC(console_size, "size of kernel console log"); | 46 | MODULE_PARM_DESC(console_size, "size of kernel console log"); |
47 | 47 | ||
48 | static ulong ramoops_ftrace_size = MIN_MEM_SIZE; | ||
49 | module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400); | ||
50 | MODULE_PARM_DESC(ftrace_size, "size of ftrace log"); | ||
51 | |||
48 | static ulong mem_address; | 52 | static ulong mem_address; |
49 | module_param(mem_address, ulong, 0400); | 53 | module_param(mem_address, ulong, 0400); |
50 | MODULE_PARM_DESC(mem_address, | 54 | MODULE_PARM_DESC(mem_address, |
@@ -70,16 +74,19 @@ MODULE_PARM_DESC(ramoops_ecc, | |||
70 | struct ramoops_context { | 74 | struct ramoops_context { |
71 | struct persistent_ram_zone **przs; | 75 | struct persistent_ram_zone **przs; |
72 | struct persistent_ram_zone *cprz; | 76 | struct persistent_ram_zone *cprz; |
77 | struct persistent_ram_zone *fprz; | ||
73 | phys_addr_t phys_addr; | 78 | phys_addr_t phys_addr; |
74 | unsigned long size; | 79 | unsigned long size; |
75 | size_t record_size; | 80 | size_t record_size; |
76 | size_t console_size; | 81 | size_t console_size; |
82 | size_t ftrace_size; | ||
77 | int dump_oops; | 83 | int dump_oops; |
78 | int ecc_size; | 84 | int ecc_size; |
79 | unsigned int max_dump_cnt; | 85 | unsigned int max_dump_cnt; |
80 | unsigned int dump_write_cnt; | 86 | unsigned int dump_write_cnt; |
81 | unsigned int dump_read_cnt; | 87 | unsigned int dump_read_cnt; |
82 | unsigned int console_read_cnt; | 88 | unsigned int console_read_cnt; |
89 | unsigned int ftrace_read_cnt; | ||
83 | struct pstore_info pstore; | 90 | struct pstore_info pstore; |
84 | }; | 91 | }; |
85 | 92 | ||
@@ -138,6 +145,9 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, | |||
138 | prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, | 145 | prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, |
139 | 1, id, type, PSTORE_TYPE_CONSOLE, 0); | 146 | 1, id, type, PSTORE_TYPE_CONSOLE, 0); |
140 | if (!prz) | 147 | if (!prz) |
148 | prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt, | ||
149 | 1, id, type, PSTORE_TYPE_FTRACE, 0); | ||
150 | if (!prz) | ||
141 | return 0; | 151 | return 0; |
142 | 152 | ||
143 | /* TODO(kees): Bogus time for the moment. */ | 153 | /* TODO(kees): Bogus time for the moment. */ |
@@ -186,6 +196,11 @@ static int ramoops_pstore_write_buf(enum pstore_type_id type, | |||
186 | return -ENOMEM; | 196 | return -ENOMEM; |
187 | persistent_ram_write(cxt->cprz, buf, size); | 197 | persistent_ram_write(cxt->cprz, buf, size); |
188 | return 0; | 198 | return 0; |
199 | } else if (type == PSTORE_TYPE_FTRACE) { | ||
200 | if (!cxt->fprz) | ||
201 | return -ENOMEM; | ||
202 | persistent_ram_write(cxt->fprz, buf, size); | ||
203 | return 0; | ||
189 | } | 204 | } |
190 | 205 | ||
191 | if (type != PSTORE_TYPE_DMESG) | 206 | if (type != PSTORE_TYPE_DMESG) |
@@ -235,6 +250,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, | |||
235 | case PSTORE_TYPE_CONSOLE: | 250 | case PSTORE_TYPE_CONSOLE: |
236 | prz = cxt->cprz; | 251 | prz = cxt->cprz; |
237 | break; | 252 | break; |
253 | case PSTORE_TYPE_FTRACE: | ||
254 | prz = cxt->fprz; | ||
255 | break; | ||
238 | default: | 256 | default: |
239 | return -EINVAL; | 257 | return -EINVAL; |
240 | } | 258 | } |
@@ -348,7 +366,8 @@ static int __devinit ramoops_probe(struct platform_device *pdev) | |||
348 | if (cxt->max_dump_cnt) | 366 | if (cxt->max_dump_cnt) |
349 | goto fail_out; | 367 | goto fail_out; |
350 | 368 | ||
351 | if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size)) { | 369 | if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && |
370 | !pdata->ftrace_size)) { | ||
352 | pr_err("The memory size and the record/console size must be " | 371 | pr_err("The memory size and the record/console size must be " |
353 | "non-zero\n"); | 372 | "non-zero\n"); |
354 | goto fail_out; | 373 | goto fail_out; |
@@ -357,18 +376,20 @@ static int __devinit ramoops_probe(struct platform_device *pdev) | |||
357 | pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); | 376 | pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); |
358 | pdata->record_size = rounddown_pow_of_two(pdata->record_size); | 377 | pdata->record_size = rounddown_pow_of_two(pdata->record_size); |
359 | pdata->console_size = rounddown_pow_of_two(pdata->console_size); | 378 | pdata->console_size = rounddown_pow_of_two(pdata->console_size); |
379 | pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); | ||
360 | 380 | ||
361 | cxt->dump_read_cnt = 0; | 381 | cxt->dump_read_cnt = 0; |
362 | cxt->size = pdata->mem_size; | 382 | cxt->size = pdata->mem_size; |
363 | cxt->phys_addr = pdata->mem_address; | 383 | cxt->phys_addr = pdata->mem_address; |
364 | cxt->record_size = pdata->record_size; | 384 | cxt->record_size = pdata->record_size; |
365 | cxt->console_size = pdata->console_size; | 385 | cxt->console_size = pdata->console_size; |
386 | cxt->ftrace_size = pdata->ftrace_size; | ||
366 | cxt->dump_oops = pdata->dump_oops; | 387 | cxt->dump_oops = pdata->dump_oops; |
367 | cxt->ecc_size = pdata->ecc_size; | 388 | cxt->ecc_size = pdata->ecc_size; |
368 | 389 | ||
369 | paddr = cxt->phys_addr; | 390 | paddr = cxt->phys_addr; |
370 | 391 | ||
371 | dump_mem_sz = cxt->size - cxt->console_size; | 392 | dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size; |
372 | err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); | 393 | err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); |
373 | if (err) | 394 | if (err) |
374 | goto fail_out; | 395 | goto fail_out; |
@@ -377,9 +398,14 @@ static int __devinit ramoops_probe(struct platform_device *pdev) | |||
377 | if (err) | 398 | if (err) |
378 | goto fail_init_cprz; | 399 | goto fail_init_cprz; |
379 | 400 | ||
380 | if (!cxt->przs && !cxt->cprz) { | 401 | err = ramoops_init_prz(dev, cxt, &cxt->fprz, &paddr, cxt->ftrace_size); |
402 | if (err) | ||
403 | goto fail_init_fprz; | ||
404 | |||
405 | if (!cxt->przs && !cxt->cprz && !cxt->fprz) { | ||
381 | pr_err("memory size too small, minimum is %lu\n", | 406 | pr_err("memory size too small, minimum is %lu\n", |
382 | cxt->console_size + cxt->record_size); | 407 | cxt->console_size + cxt->record_size + |
408 | cxt->ftrace_size); | ||
383 | goto fail_cnt; | 409 | goto fail_cnt; |
384 | } | 410 | } |
385 | 411 | ||
@@ -426,6 +452,8 @@ fail_clear: | |||
426 | cxt->pstore.bufsize = 0; | 452 | cxt->pstore.bufsize = 0; |
427 | cxt->max_dump_cnt = 0; | 453 | cxt->max_dump_cnt = 0; |
428 | fail_cnt: | 454 | fail_cnt: |
455 | kfree(cxt->fprz); | ||
456 | fail_init_fprz: | ||
429 | kfree(cxt->cprz); | 457 | kfree(cxt->cprz); |
430 | fail_init_cprz: | 458 | fail_init_cprz: |
431 | ramoops_free_przs(cxt); | 459 | ramoops_free_przs(cxt); |
@@ -480,6 +508,7 @@ static void ramoops_register_dummy(void) | |||
480 | dummy_data->mem_address = mem_address; | 508 | dummy_data->mem_address = mem_address; |
481 | dummy_data->record_size = record_size; | 509 | dummy_data->record_size = record_size; |
482 | dummy_data->console_size = ramoops_console_size; | 510 | dummy_data->console_size = ramoops_console_size; |
511 | dummy_data->ftrace_size = ramoops_ftrace_size; | ||
483 | dummy_data->dump_oops = dump_oops; | 512 | dummy_data->dump_oops = dump_oops; |
484 | /* | 513 | /* |
485 | * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC | 514 | * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC |
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index dcf805f56bc6..af848e1593b9 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h | |||
@@ -72,6 +72,7 @@ struct ramoops_platform_data { | |||
72 | unsigned long mem_address; | 72 | unsigned long mem_address; |
73 | unsigned long record_size; | 73 | unsigned long record_size; |
74 | unsigned long console_size; | 74 | unsigned long console_size; |
75 | unsigned long ftrace_size; | ||
75 | int dump_oops; | 76 | int dump_oops; |
76 | int ecc_size; | 77 | int ecc_size; |
77 | }; | 78 | }; |