| .. | .. |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * S/390 debug facility |
|---|
| 4 | 4 | * |
|---|
| 5 | | - * Copyright IBM Corp. 1999, 2012 |
|---|
| 5 | + * Copyright IBM Corp. 1999, 2020 |
|---|
| 6 | 6 | * |
|---|
| 7 | 7 | * Author(s): Michael Holzheu (holzheu@de.ibm.com), |
|---|
| 8 | 8 | * Holger Smolinski (Holger.Smolinski@de.ibm.com) |
|---|
| .. | .. |
|---|
| 24 | 24 | #include <linux/export.h> |
|---|
| 25 | 25 | #include <linux/init.h> |
|---|
| 26 | 26 | #include <linux/fs.h> |
|---|
| 27 | +#include <linux/minmax.h> |
|---|
| 27 | 28 | #include <linux/debugfs.h> |
|---|
| 28 | 29 | |
|---|
| 29 | 30 | #include <asm/debug.h> |
|---|
| .. | .. |
|---|
| 90 | 91 | size_t user_buf_size, loff_t *offset); |
|---|
| 91 | 92 | static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view, |
|---|
| 92 | 93 | char *out_buf, const char *in_buf); |
|---|
| 93 | | -static int debug_raw_format_fn(debug_info_t *id, |
|---|
| 94 | | - struct debug_view *view, char *out_buf, |
|---|
| 95 | | - const char *in_buf); |
|---|
| 96 | | -static int debug_raw_header_fn(debug_info_t *id, struct debug_view *view, |
|---|
| 97 | | - int area, debug_entry_t *entry, char *out_buf); |
|---|
| 98 | | - |
|---|
| 99 | 94 | static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view, |
|---|
| 100 | 95 | char *out_buf, debug_sprintf_entry_t *curr_event); |
|---|
| 96 | +static void debug_areas_swap(debug_info_t *a, debug_info_t *b); |
|---|
| 97 | +static void debug_events_append(debug_info_t *dest, debug_info_t *src); |
|---|
| 101 | 98 | |
|---|
| 102 | 99 | /* globals */ |
|---|
| 103 | | - |
|---|
| 104 | | -struct debug_view debug_raw_view = { |
|---|
| 105 | | - "raw", |
|---|
| 106 | | - NULL, |
|---|
| 107 | | - &debug_raw_header_fn, |
|---|
| 108 | | - &debug_raw_format_fn, |
|---|
| 109 | | - NULL, |
|---|
| 110 | | - NULL |
|---|
| 111 | | -}; |
|---|
| 112 | | -EXPORT_SYMBOL(debug_raw_view); |
|---|
| 113 | 100 | |
|---|
| 114 | 101 | struct debug_view debug_hex_ascii_view = { |
|---|
| 115 | 102 | "hex_ascii", |
|---|
| .. | .. |
|---|
| 327 | 314 | goto out; |
|---|
| 328 | 315 | |
|---|
| 329 | 316 | rc->mode = mode & ~S_IFMT; |
|---|
| 330 | | - |
|---|
| 331 | | - /* create root directory */ |
|---|
| 332 | | - rc->debugfs_root_entry = debugfs_create_dir(rc->name, |
|---|
| 333 | | - debug_debugfs_root_entry); |
|---|
| 334 | | - |
|---|
| 335 | | - /* append new element to linked list */ |
|---|
| 336 | | - if (!debug_area_first) { |
|---|
| 337 | | - /* first element in list */ |
|---|
| 338 | | - debug_area_first = rc; |
|---|
| 339 | | - rc->prev = NULL; |
|---|
| 340 | | - } else { |
|---|
| 341 | | - /* append element to end of list */ |
|---|
| 342 | | - debug_area_last->next = rc; |
|---|
| 343 | | - rc->prev = debug_area_last; |
|---|
| 344 | | - } |
|---|
| 345 | | - debug_area_last = rc; |
|---|
| 346 | | - rc->next = NULL; |
|---|
| 347 | | - |
|---|
| 348 | 317 | refcount_set(&rc->ref_count, 1); |
|---|
| 349 | 318 | out: |
|---|
| 350 | 319 | return rc; |
|---|
| .. | .. |
|---|
| 404 | 373 | */ |
|---|
| 405 | 374 | static void debug_info_put(debug_info_t *db_info) |
|---|
| 406 | 375 | { |
|---|
| 407 | | - int i; |
|---|
| 408 | | - |
|---|
| 409 | 376 | if (!db_info) |
|---|
| 410 | 377 | return; |
|---|
| 411 | | - if (refcount_dec_and_test(&db_info->ref_count)) { |
|---|
| 412 | | - for (i = 0; i < DEBUG_MAX_VIEWS; i++) { |
|---|
| 413 | | - if (!db_info->views[i]) |
|---|
| 414 | | - continue; |
|---|
| 415 | | - debugfs_remove(db_info->debugfs_entries[i]); |
|---|
| 416 | | - } |
|---|
| 417 | | - debugfs_remove(db_info->debugfs_root_entry); |
|---|
| 418 | | - if (db_info == debug_area_first) |
|---|
| 419 | | - debug_area_first = db_info->next; |
|---|
| 420 | | - if (db_info == debug_area_last) |
|---|
| 421 | | - debug_area_last = db_info->prev; |
|---|
| 422 | | - if (db_info->prev) |
|---|
| 423 | | - db_info->prev->next = db_info->next; |
|---|
| 424 | | - if (db_info->next) |
|---|
| 425 | | - db_info->next->prev = db_info->prev; |
|---|
| 378 | + if (refcount_dec_and_test(&db_info->ref_count)) |
|---|
| 426 | 379 | debug_info_free(db_info); |
|---|
| 427 | | - } |
|---|
| 428 | 380 | } |
|---|
| 429 | 381 | |
|---|
| 430 | 382 | /* |
|---|
| .. | .. |
|---|
| 449 | 401 | act_entry = (debug_entry_t *) ((char *)id_snap->areas[p_info->act_area] |
|---|
| 450 | 402 | [p_info->act_page] + p_info->act_entry); |
|---|
| 451 | 403 | |
|---|
| 452 | | - if (act_entry->id.stck == 0LL) |
|---|
| 404 | + if (act_entry->clock == 0LL) |
|---|
| 453 | 405 | goto out; /* empty entry */ |
|---|
| 454 | 406 | if (view->header_proc) |
|---|
| 455 | 407 | len += view->header_proc(id_snap, view, p_info->act_area, |
|---|
| .. | .. |
|---|
| 648 | 600 | return 0; /* success */ |
|---|
| 649 | 601 | } |
|---|
| 650 | 602 | |
|---|
| 651 | | -/* |
|---|
| 652 | | - * debug_register_mode: |
|---|
| 653 | | - * - Creates and initializes debug area for the caller |
|---|
| 654 | | - * The mode parameter allows to specify access rights for the s390dbf files |
|---|
| 655 | | - * - Returns handle for debug area |
|---|
| 603 | +/* Create debugfs entries and add to internal list. */ |
|---|
| 604 | +static void _debug_register(debug_info_t *id) |
|---|
| 605 | +{ |
|---|
| 606 | + /* create root directory */ |
|---|
| 607 | + id->debugfs_root_entry = debugfs_create_dir(id->name, |
|---|
| 608 | + debug_debugfs_root_entry); |
|---|
| 609 | + |
|---|
| 610 | + /* append new element to linked list */ |
|---|
| 611 | + if (!debug_area_first) { |
|---|
| 612 | + /* first element in list */ |
|---|
| 613 | + debug_area_first = id; |
|---|
| 614 | + id->prev = NULL; |
|---|
| 615 | + } else { |
|---|
| 616 | + /* append element to end of list */ |
|---|
| 617 | + debug_area_last->next = id; |
|---|
| 618 | + id->prev = debug_area_last; |
|---|
| 619 | + } |
|---|
| 620 | + debug_area_last = id; |
|---|
| 621 | + id->next = NULL; |
|---|
| 622 | + |
|---|
| 623 | + debug_register_view(id, &debug_level_view); |
|---|
| 624 | + debug_register_view(id, &debug_flush_view); |
|---|
| 625 | + debug_register_view(id, &debug_pages_view); |
|---|
| 626 | +} |
|---|
| 627 | + |
|---|
| 628 | +/** |
|---|
| 629 | + * debug_register_mode() - creates and initializes debug area. |
|---|
| 630 | + * |
|---|
| 631 | + * @name: Name of debug log (e.g. used for debugfs entry) |
|---|
| 632 | + * @pages_per_area: Number of pages, which will be allocated per area |
|---|
| 633 | + * @nr_areas: Number of debug areas |
|---|
| 634 | + * @buf_size: Size of data area in each debug entry |
|---|
| 635 | + * @mode: File mode for debugfs files. E.g. S_IRWXUGO |
|---|
| 636 | + * @uid: User ID for debugfs files. Currently only 0 is supported. |
|---|
| 637 | + * @gid: Group ID for debugfs files. Currently only 0 is supported. |
|---|
| 638 | + * |
|---|
| 639 | + * Return: |
|---|
| 640 | + * - Handle for generated debug area |
|---|
| 641 | + * - %NULL if register failed |
|---|
| 642 | + * |
|---|
| 643 | + * Allocates memory for a debug log. |
|---|
| 644 | + * Must not be called within an interrupt handler. |
|---|
| 656 | 645 | */ |
|---|
| 657 | 646 | debug_info_t *debug_register_mode(const char *name, int pages_per_area, |
|---|
| 658 | 647 | int nr_areas, int buf_size, umode_t mode, |
|---|
| .. | .. |
|---|
| 665 | 654 | if ((uid != 0) || (gid != 0)) |
|---|
| 666 | 655 | pr_warn("Root becomes the owner of all s390dbf files in sysfs\n"); |
|---|
| 667 | 656 | BUG_ON(!initialized); |
|---|
| 668 | | - mutex_lock(&debug_mutex); |
|---|
| 669 | 657 | |
|---|
| 670 | 658 | /* create new debug_info */ |
|---|
| 671 | 659 | rc = debug_info_create(name, pages_per_area, nr_areas, buf_size, mode); |
|---|
| 672 | | - if (!rc) |
|---|
| 673 | | - goto out; |
|---|
| 674 | | - debug_register_view(rc, &debug_level_view); |
|---|
| 675 | | - debug_register_view(rc, &debug_flush_view); |
|---|
| 676 | | - debug_register_view(rc, &debug_pages_view); |
|---|
| 677 | | -out: |
|---|
| 678 | | - if (!rc) |
|---|
| 660 | + if (rc) { |
|---|
| 661 | + mutex_lock(&debug_mutex); |
|---|
| 662 | + _debug_register(rc); |
|---|
| 663 | + mutex_unlock(&debug_mutex); |
|---|
| 664 | + } else { |
|---|
| 679 | 665 | pr_err("Registering debug feature %s failed\n", name); |
|---|
| 680 | | - mutex_unlock(&debug_mutex); |
|---|
| 666 | + } |
|---|
| 681 | 667 | return rc; |
|---|
| 682 | 668 | } |
|---|
| 683 | 669 | EXPORT_SYMBOL(debug_register_mode); |
|---|
| 684 | 670 | |
|---|
| 685 | | -/* |
|---|
| 686 | | - * debug_register: |
|---|
| 687 | | - * - creates and initializes debug area for the caller |
|---|
| 688 | | - * - returns handle for debug area |
|---|
| 671 | +/** |
|---|
| 672 | + * debug_register() - creates and initializes debug area with default file mode. |
|---|
| 673 | + * |
|---|
| 674 | + * @name: Name of debug log (e.g. used for debugfs entry) |
|---|
| 675 | + * @pages_per_area: Number of pages, which will be allocated per area |
|---|
| 676 | + * @nr_areas: Number of debug areas |
|---|
| 677 | + * @buf_size: Size of data area in each debug entry |
|---|
| 678 | + * |
|---|
| 679 | + * Return: |
|---|
| 680 | + * - Handle for generated debug area |
|---|
| 681 | + * - %NULL if register failed |
|---|
| 682 | + * |
|---|
| 683 | + * Allocates memory for a debug log. |
|---|
| 684 | + * The debugfs file mode access permissions are read and write for user. |
|---|
| 685 | + * Must not be called within an interrupt handler. |
|---|
| 689 | 686 | */ |
|---|
| 690 | 687 | debug_info_t *debug_register(const char *name, int pages_per_area, |
|---|
| 691 | 688 | int nr_areas, int buf_size) |
|---|
| .. | .. |
|---|
| 695 | 692 | } |
|---|
| 696 | 693 | EXPORT_SYMBOL(debug_register); |
|---|
| 697 | 694 | |
|---|
| 698 | | -/* |
|---|
| 699 | | - * debug_unregister: |
|---|
| 700 | | - * - give back debug area |
|---|
| 695 | +/* Remove debugfs entries and remove from internal list. */ |
|---|
| 696 | +static void _debug_unregister(debug_info_t *id) |
|---|
| 697 | +{ |
|---|
| 698 | + int i; |
|---|
| 699 | + |
|---|
| 700 | + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { |
|---|
| 701 | + if (!id->views[i]) |
|---|
| 702 | + continue; |
|---|
| 703 | + debugfs_remove(id->debugfs_entries[i]); |
|---|
| 704 | + } |
|---|
| 705 | + debugfs_remove(id->debugfs_root_entry); |
|---|
| 706 | + if (id == debug_area_first) |
|---|
| 707 | + debug_area_first = id->next; |
|---|
| 708 | + if (id == debug_area_last) |
|---|
| 709 | + debug_area_last = id->prev; |
|---|
| 710 | + if (id->prev) |
|---|
| 711 | + id->prev->next = id->next; |
|---|
| 712 | + if (id->next) |
|---|
| 713 | + id->next->prev = id->prev; |
|---|
| 714 | +} |
|---|
| 715 | + |
|---|
| 716 | +/** |
|---|
| 717 | + * debug_unregister() - give back debug area. |
|---|
| 718 | + * |
|---|
| 719 | + * @id: handle for debug log |
|---|
| 720 | + * |
|---|
| 721 | + * Return: |
|---|
| 722 | + * none |
|---|
| 701 | 723 | */ |
|---|
| 702 | 724 | void debug_unregister(debug_info_t *id) |
|---|
| 703 | 725 | { |
|---|
| 704 | 726 | if (!id) |
|---|
| 705 | 727 | return; |
|---|
| 706 | 728 | mutex_lock(&debug_mutex); |
|---|
| 707 | | - debug_info_put(id); |
|---|
| 729 | + _debug_unregister(id); |
|---|
| 708 | 730 | mutex_unlock(&debug_mutex); |
|---|
| 731 | + |
|---|
| 732 | + debug_info_put(id); |
|---|
| 709 | 733 | } |
|---|
| 710 | 734 | EXPORT_SYMBOL(debug_unregister); |
|---|
| 711 | 735 | |
|---|
| .. | .. |
|---|
| 715 | 739 | */ |
|---|
| 716 | 740 | static int debug_set_size(debug_info_t *id, int nr_areas, int pages_per_area) |
|---|
| 717 | 741 | { |
|---|
| 718 | | - debug_entry_t ***new_areas; |
|---|
| 742 | + debug_info_t *new_id; |
|---|
| 719 | 743 | unsigned long flags; |
|---|
| 720 | | - int rc = 0; |
|---|
| 721 | 744 | |
|---|
| 722 | 745 | if (!id || (nr_areas <= 0) || (pages_per_area < 0)) |
|---|
| 723 | 746 | return -EINVAL; |
|---|
| 724 | | - if (pages_per_area > 0) { |
|---|
| 725 | | - new_areas = debug_areas_alloc(pages_per_area, nr_areas); |
|---|
| 726 | | - if (!new_areas) { |
|---|
| 727 | | - pr_info("Allocating memory for %i pages failed\n", |
|---|
| 728 | | - pages_per_area); |
|---|
| 729 | | - rc = -ENOMEM; |
|---|
| 730 | | - goto out; |
|---|
| 731 | | - } |
|---|
| 732 | | - } else { |
|---|
| 733 | | - new_areas = NULL; |
|---|
| 747 | + |
|---|
| 748 | + new_id = debug_info_alloc("", pages_per_area, nr_areas, id->buf_size, |
|---|
| 749 | + id->level, ALL_AREAS); |
|---|
| 750 | + if (!new_id) { |
|---|
| 751 | + pr_info("Allocating memory for %i pages failed\n", |
|---|
| 752 | + pages_per_area); |
|---|
| 753 | + return -ENOMEM; |
|---|
| 734 | 754 | } |
|---|
| 755 | + |
|---|
| 735 | 756 | spin_lock_irqsave(&id->lock, flags); |
|---|
| 736 | | - debug_areas_free(id); |
|---|
| 737 | | - id->areas = new_areas; |
|---|
| 738 | | - id->nr_areas = nr_areas; |
|---|
| 739 | | - id->pages_per_area = pages_per_area; |
|---|
| 740 | | - id->active_area = 0; |
|---|
| 741 | | - memset(id->active_entries, 0, sizeof(int)*id->nr_areas); |
|---|
| 742 | | - memset(id->active_pages, 0, sizeof(int)*id->nr_areas); |
|---|
| 757 | + debug_events_append(new_id, id); |
|---|
| 758 | + debug_areas_swap(new_id, id); |
|---|
| 759 | + debug_info_free(new_id); |
|---|
| 743 | 760 | spin_unlock_irqrestore(&id->lock, flags); |
|---|
| 744 | 761 | pr_info("%s: set new size (%i pages)\n", id->name, pages_per_area); |
|---|
| 745 | | -out: |
|---|
| 746 | | - return rc; |
|---|
| 762 | + |
|---|
| 763 | + return 0; |
|---|
| 747 | 764 | } |
|---|
| 748 | 765 | |
|---|
| 749 | | -/* |
|---|
| 750 | | - * debug_set_level: |
|---|
| 751 | | - * - set actual debug level |
|---|
| 766 | +/** |
|---|
| 767 | + * debug_set_level() - Sets new actual debug level if new_level is valid. |
|---|
| 768 | + * |
|---|
| 769 | + * @id: handle for debug log |
|---|
| 770 | + * @new_level: new debug level |
|---|
| 771 | + * |
|---|
| 772 | + * Return: |
|---|
| 773 | + * none |
|---|
| 752 | 774 | */ |
|---|
| 753 | 775 | void debug_set_level(debug_info_t *id, int new_level) |
|---|
| 754 | 776 | { |
|---|
| .. | .. |
|---|
| 805 | 827 | id->active_entries[id->active_area]); |
|---|
| 806 | 828 | } |
|---|
| 807 | 829 | |
|---|
| 830 | +/* Swap debug areas of a and b. */ |
|---|
| 831 | +static void debug_areas_swap(debug_info_t *a, debug_info_t *b) |
|---|
| 832 | +{ |
|---|
| 833 | + swap(a->nr_areas, b->nr_areas); |
|---|
| 834 | + swap(a->pages_per_area, b->pages_per_area); |
|---|
| 835 | + swap(a->areas, b->areas); |
|---|
| 836 | + swap(a->active_area, b->active_area); |
|---|
| 837 | + swap(a->active_pages, b->active_pages); |
|---|
| 838 | + swap(a->active_entries, b->active_entries); |
|---|
| 839 | +} |
|---|
| 840 | + |
|---|
| 841 | +/* Append all debug events in active area from source to destination log. */ |
|---|
| 842 | +static void debug_events_append(debug_info_t *dest, debug_info_t *src) |
|---|
| 843 | +{ |
|---|
| 844 | + debug_entry_t *from, *to, *last; |
|---|
| 845 | + |
|---|
| 846 | + if (!src->areas || !dest->areas) |
|---|
| 847 | + return; |
|---|
| 848 | + |
|---|
| 849 | + /* Loop over all entries in src, starting with oldest. */ |
|---|
| 850 | + from = get_active_entry(src); |
|---|
| 851 | + last = from; |
|---|
| 852 | + do { |
|---|
| 853 | + if (from->clock != 0LL) { |
|---|
| 854 | + to = get_active_entry(dest); |
|---|
| 855 | + memset(to, 0, dest->entry_size); |
|---|
| 856 | + memcpy(to, from, min(src->entry_size, |
|---|
| 857 | + dest->entry_size)); |
|---|
| 858 | + proceed_active_entry(dest); |
|---|
| 859 | + } |
|---|
| 860 | + |
|---|
| 861 | + proceed_active_entry(src); |
|---|
| 862 | + from = get_active_entry(src); |
|---|
| 863 | + } while (from != last); |
|---|
| 864 | +} |
|---|
| 865 | + |
|---|
| 808 | 866 | /* |
|---|
| 809 | 867 | * debug_finish_entry: |
|---|
| 810 | 868 | * - set timestamp, caller address, cpu number etc. |
|---|
| .. | .. |
|---|
| 813 | 871 | static inline void debug_finish_entry(debug_info_t *id, debug_entry_t *active, |
|---|
| 814 | 872 | int level, int exception) |
|---|
| 815 | 873 | { |
|---|
| 816 | | - active->id.stck = get_tod_clock_fast() - |
|---|
| 817 | | - *(unsigned long long *) &tod_clock_base[1]; |
|---|
| 818 | | - active->id.fields.cpuid = smp_processor_id(); |
|---|
| 874 | + unsigned char clk[STORE_CLOCK_EXT_SIZE]; |
|---|
| 875 | + unsigned long timestamp; |
|---|
| 876 | + |
|---|
| 877 | + get_tod_clock_ext(clk); |
|---|
| 878 | + timestamp = *(unsigned long *) &clk[0] >> 4; |
|---|
| 879 | + timestamp -= TOD_UNIX_EPOCH >> 12; |
|---|
| 880 | + active->clock = timestamp; |
|---|
| 881 | + active->cpu = smp_processor_id(); |
|---|
| 819 | 882 | active->caller = __builtin_return_address(0); |
|---|
| 820 | | - active->id.fields.exception = exception; |
|---|
| 821 | | - active->id.fields.level = level; |
|---|
| 883 | + active->exception = exception; |
|---|
| 884 | + active->level = level; |
|---|
| 822 | 885 | proceed_active_entry(id); |
|---|
| 823 | 886 | if (exception) |
|---|
| 824 | 887 | proceed_active_area(id); |
|---|
| .. | .. |
|---|
| 836 | 899 | * if debug_active is already off |
|---|
| 837 | 900 | */ |
|---|
| 838 | 901 | static int s390dbf_procactive(struct ctl_table *table, int write, |
|---|
| 839 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 902 | + void *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 840 | 903 | { |
|---|
| 841 | 904 | if (!write || debug_stoppable || !debug_active) |
|---|
| 842 | 905 | return proc_dointvec(table, write, buffer, lenp, ppos); |
|---|
| .. | .. |
|---|
| 874 | 937 | |
|---|
| 875 | 938 | static struct ctl_table_header *s390dbf_sysctl_header; |
|---|
| 876 | 939 | |
|---|
| 940 | +/** |
|---|
| 941 | + * debug_stop_all() - stops the debug feature if stopping is allowed. |
|---|
| 942 | + * |
|---|
| 943 | + * Return: |
|---|
| 944 | + * - none |
|---|
| 945 | + * |
|---|
| 946 | + * Currently used in case of a kernel oops. |
|---|
| 947 | + */ |
|---|
| 877 | 948 | void debug_stop_all(void) |
|---|
| 878 | 949 | { |
|---|
| 879 | 950 | if (debug_stoppable) |
|---|
| .. | .. |
|---|
| 881 | 952 | } |
|---|
| 882 | 953 | EXPORT_SYMBOL(debug_stop_all); |
|---|
| 883 | 954 | |
|---|
| 955 | +/** |
|---|
| 956 | + * debug_set_critical() - event/exception functions try lock instead of spin. |
|---|
| 957 | + * |
|---|
| 958 | + * Return: |
|---|
| 959 | + * - none |
|---|
| 960 | + * |
|---|
| 961 | + * Currently used in case of stopping all CPUs but the current one. |
|---|
| 962 | + * Once in this state, functions to write a debug entry for an |
|---|
| 963 | + * event or exception no longer spin on the debug area lock, |
|---|
| 964 | + * but only try to get it and fail if they do not get the lock. |
|---|
| 965 | + */ |
|---|
| 884 | 966 | void debug_set_critical(void) |
|---|
| 885 | 967 | { |
|---|
| 886 | 968 | debug_critical = 1; |
|---|
| .. | .. |
|---|
| 1037 | 1119 | } |
|---|
| 1038 | 1120 | EXPORT_SYMBOL(__debug_sprintf_exception); |
|---|
| 1039 | 1121 | |
|---|
| 1040 | | -/* |
|---|
| 1041 | | - * debug_register_view: |
|---|
| 1122 | +/** |
|---|
| 1123 | + * debug_register_view() - registers new debug view and creates debugfs |
|---|
| 1124 | + * dir entry |
|---|
| 1125 | + * |
|---|
| 1126 | + * @id: handle for debug log |
|---|
| 1127 | + * @view: pointer to debug view struct |
|---|
| 1128 | + * |
|---|
| 1129 | + * Return: |
|---|
| 1130 | + * - 0 : ok |
|---|
| 1131 | + * - < 0: Error |
|---|
| 1042 | 1132 | */ |
|---|
| 1043 | 1133 | int debug_register_view(debug_info_t *id, struct debug_view *view) |
|---|
| 1044 | 1134 | { |
|---|
| .. | .. |
|---|
| 1057 | 1147 | mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); |
|---|
| 1058 | 1148 | pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry, |
|---|
| 1059 | 1149 | id, &debug_file_ops); |
|---|
| 1060 | | - if (!pde) { |
|---|
| 1061 | | - pr_err("Registering view %s/%s failed due to out of " |
|---|
| 1062 | | - "memory\n", id->name, view->name); |
|---|
| 1063 | | - rc = -1; |
|---|
| 1064 | | - goto out; |
|---|
| 1065 | | - } |
|---|
| 1066 | 1150 | spin_lock_irqsave(&id->lock, flags); |
|---|
| 1067 | 1151 | for (i = 0; i < DEBUG_MAX_VIEWS; i++) { |
|---|
| 1068 | 1152 | if (!id->views[i]) |
|---|
| .. | .. |
|---|
| 1084 | 1168 | } |
|---|
| 1085 | 1169 | EXPORT_SYMBOL(debug_register_view); |
|---|
| 1086 | 1170 | |
|---|
| 1087 | | -/* |
|---|
| 1088 | | - * debug_unregister_view: |
|---|
| 1171 | +/** |
|---|
| 1172 | + * debug_unregister_view() - unregisters debug view and removes debugfs |
|---|
| 1173 | + * dir entry |
|---|
| 1174 | + * |
|---|
| 1175 | + * @id: handle for debug log |
|---|
| 1176 | + * @view: pointer to debug view struct |
|---|
| 1177 | + * |
|---|
| 1178 | + * Return: |
|---|
| 1179 | + * - 0 : ok |
|---|
| 1180 | + * - < 0: Error |
|---|
| 1089 | 1181 | */ |
|---|
| 1090 | 1182 | int debug_unregister_view(debug_info_t *id, struct debug_view *view) |
|---|
| 1091 | 1183 | { |
|---|
| .. | .. |
|---|
| 1325 | 1417 | } |
|---|
| 1326 | 1418 | |
|---|
| 1327 | 1419 | /* |
|---|
| 1328 | | - * prints debug header in raw format |
|---|
| 1329 | | - */ |
|---|
| 1330 | | -static int debug_raw_header_fn(debug_info_t *id, struct debug_view *view, |
|---|
| 1331 | | - int area, debug_entry_t *entry, char *out_buf) |
|---|
| 1332 | | -{ |
|---|
| 1333 | | - int rc; |
|---|
| 1334 | | - |
|---|
| 1335 | | - rc = sizeof(debug_entry_t); |
|---|
| 1336 | | - memcpy(out_buf, entry, sizeof(debug_entry_t)); |
|---|
| 1337 | | - return rc; |
|---|
| 1338 | | -} |
|---|
| 1339 | | - |
|---|
| 1340 | | -/* |
|---|
| 1341 | | - * prints debug data in raw format |
|---|
| 1342 | | - */ |
|---|
| 1343 | | -static int debug_raw_format_fn(debug_info_t *id, struct debug_view *view, |
|---|
| 1344 | | - char *out_buf, const char *in_buf) |
|---|
| 1345 | | -{ |
|---|
| 1346 | | - int rc; |
|---|
| 1347 | | - |
|---|
| 1348 | | - rc = id->buf_size; |
|---|
| 1349 | | - memcpy(out_buf, in_buf, id->buf_size); |
|---|
| 1350 | | - return rc; |
|---|
| 1351 | | -} |
|---|
| 1352 | | - |
|---|
| 1353 | | -/* |
|---|
| 1354 | 1420 | * prints debug data in hex/ascii format |
|---|
| 1355 | 1421 | */ |
|---|
| 1356 | 1422 | static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view, |
|---|
| .. | .. |
|---|
| 1379 | 1445 | int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view, |
|---|
| 1380 | 1446 | int area, debug_entry_t *entry, char *out_buf) |
|---|
| 1381 | 1447 | { |
|---|
| 1382 | | - unsigned long base, sec, usec; |
|---|
| 1448 | + unsigned long sec, usec; |
|---|
| 1383 | 1449 | unsigned long caller; |
|---|
| 1384 | 1450 | unsigned int level; |
|---|
| 1385 | 1451 | char *except_str; |
|---|
| 1386 | 1452 | int rc = 0; |
|---|
| 1387 | 1453 | |
|---|
| 1388 | | - level = entry->id.fields.level; |
|---|
| 1389 | | - base = (*(unsigned long *) &tod_clock_base[0]) >> 4; |
|---|
| 1390 | | - sec = (entry->id.stck >> 12) + base - (TOD_UNIX_EPOCH >> 12); |
|---|
| 1454 | + level = entry->level; |
|---|
| 1455 | + sec = entry->clock; |
|---|
| 1391 | 1456 | usec = do_div(sec, USEC_PER_SEC); |
|---|
| 1392 | 1457 | |
|---|
| 1393 | | - if (entry->id.fields.exception) |
|---|
| 1458 | + if (entry->exception) |
|---|
| 1394 | 1459 | except_str = "*"; |
|---|
| 1395 | 1460 | else |
|---|
| 1396 | 1461 | except_str = "-"; |
|---|
| 1397 | 1462 | caller = (unsigned long) entry->caller; |
|---|
| 1398 | | - rc += sprintf(out_buf, "%02i %011ld:%06lu %1u %1s %02i %pK ", |
|---|
| 1463 | + rc += sprintf(out_buf, "%02i %011ld:%06lu %1u %1s %04u %pK ", |
|---|
| 1399 | 1464 | area, sec, usec, level, except_str, |
|---|
| 1400 | | - entry->id.fields.cpuid, (void *)caller); |
|---|
| 1465 | + entry->cpu, (void *)caller); |
|---|
| 1401 | 1466 | return rc; |
|---|
| 1402 | 1467 | } |
|---|
| 1403 | 1468 | EXPORT_SYMBOL(debug_dflt_header_fn); |
|---|