.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
---|
3 | 4 | <http://rt2x00.serialmonkey.com> |
---|
4 | 5 | |
---|
5 | | - This program is free software; you can redistribute it and/or modify |
---|
6 | | - it under the terms of the GNU General Public License as published by |
---|
7 | | - the Free Software Foundation; either version 2 of the License, or |
---|
8 | | - (at your option) any later version. |
---|
9 | | - |
---|
10 | | - This program is distributed in the hope that it will be useful, |
---|
11 | | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | | - GNU General Public License for more details. |
---|
14 | | - |
---|
15 | | - You should have received a copy of the GNU General Public License |
---|
16 | | - along with this program; if not, see <http://www.gnu.org/licenses/>. |
---|
17 | 6 | */ |
---|
18 | 7 | |
---|
19 | 8 | /* |
---|
.. | .. |
---|
63 | 52 | * - chipset file |
---|
64 | 53 | * - device state flags file |
---|
65 | 54 | * - device capability flags file |
---|
| 55 | + * - hardware restart file |
---|
66 | 56 | * - register folder |
---|
67 | 57 | * - csr offset/value files |
---|
68 | 58 | * - eeprom offset/value files |
---|
.. | .. |
---|
75 | 65 | * - crypto stats file |
---|
76 | 66 | */ |
---|
77 | 67 | struct dentry *driver_folder; |
---|
78 | | - struct dentry *driver_entry; |
---|
79 | | - struct dentry *chipset_entry; |
---|
80 | | - struct dentry *dev_flags; |
---|
81 | | - struct dentry *cap_flags; |
---|
82 | | - struct dentry *register_folder; |
---|
83 | | - struct dentry *csr_off_entry; |
---|
84 | | - struct dentry *csr_val_entry; |
---|
85 | | - struct dentry *eeprom_off_entry; |
---|
86 | | - struct dentry *eeprom_val_entry; |
---|
87 | | - struct dentry *bbp_off_entry; |
---|
88 | | - struct dentry *bbp_val_entry; |
---|
89 | | - struct dentry *rf_off_entry; |
---|
90 | | - struct dentry *rf_val_entry; |
---|
91 | | - struct dentry *rfcsr_off_entry; |
---|
92 | | - struct dentry *rfcsr_val_entry; |
---|
93 | | - struct dentry *queue_folder; |
---|
94 | | - struct dentry *queue_frame_dump_entry; |
---|
95 | | - struct dentry *queue_stats_entry; |
---|
96 | | - struct dentry *crypto_stats_entry; |
---|
97 | 68 | |
---|
98 | 69 | /* |
---|
99 | 70 | * The frame dump file only allows a single reader, |
---|
.. | .. |
---|
464 | 435 | \ |
---|
465 | 436 | size = sprintf(line, __format, value); \ |
---|
466 | 437 | \ |
---|
467 | | - if (copy_to_user(buf, line, size)) \ |
---|
468 | | - return -EFAULT; \ |
---|
469 | | - \ |
---|
470 | | - *offset += size; \ |
---|
471 | | - return size; \ |
---|
| 438 | + return simple_read_from_buffer(buf, length, offset, line, size); \ |
---|
472 | 439 | } |
---|
473 | 440 | |
---|
474 | 441 | #define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \ |
---|
.. | .. |
---|
545 | 512 | |
---|
546 | 513 | size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags); |
---|
547 | 514 | |
---|
548 | | - if (copy_to_user(buf, line, size)) |
---|
549 | | - return -EFAULT; |
---|
550 | | - |
---|
551 | | - *offset += size; |
---|
552 | | - return size; |
---|
| 515 | + return simple_read_from_buffer(buf, length, offset, line, size); |
---|
553 | 516 | } |
---|
554 | 517 | |
---|
555 | 518 | static const struct file_operations rt2x00debug_fop_dev_flags = { |
---|
.. | .. |
---|
574 | 537 | |
---|
575 | 538 | size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags); |
---|
576 | 539 | |
---|
577 | | - if (copy_to_user(buf, line, size)) |
---|
578 | | - return -EFAULT; |
---|
579 | | - |
---|
580 | | - *offset += size; |
---|
581 | | - return size; |
---|
| 540 | + return simple_read_from_buffer(buf, length, offset, line, size); |
---|
582 | 541 | } |
---|
583 | 542 | |
---|
584 | 543 | static const struct file_operations rt2x00debug_fop_cap_flags = { |
---|
.. | .. |
---|
589 | 548 | .llseek = default_llseek, |
---|
590 | 549 | }; |
---|
591 | 550 | |
---|
592 | | -static struct dentry *rt2x00debug_create_file_driver(const char *name, |
---|
593 | | - struct rt2x00debug_intf |
---|
594 | | - *intf, |
---|
595 | | - struct debugfs_blob_wrapper |
---|
596 | | - *blob) |
---|
| 551 | +static ssize_t rt2x00debug_write_restart_hw(struct file *file, |
---|
| 552 | + const char __user *buf, |
---|
| 553 | + size_t length, |
---|
| 554 | + loff_t *offset) |
---|
| 555 | +{ |
---|
| 556 | + struct rt2x00debug_intf *intf = file->private_data; |
---|
| 557 | + struct rt2x00_dev *rt2x00dev = intf->rt2x00dev; |
---|
| 558 | + static unsigned long last_reset = INITIAL_JIFFIES; |
---|
| 559 | + |
---|
| 560 | + if (!rt2x00_has_cap_restart_hw(rt2x00dev)) |
---|
| 561 | + return -EOPNOTSUPP; |
---|
| 562 | + |
---|
| 563 | + if (time_before(jiffies, last_reset + msecs_to_jiffies(2000))) |
---|
| 564 | + return -EBUSY; |
---|
| 565 | + |
---|
| 566 | + last_reset = jiffies; |
---|
| 567 | + |
---|
| 568 | + ieee80211_restart_hw(rt2x00dev->hw); |
---|
| 569 | + return length; |
---|
| 570 | +} |
---|
| 571 | + |
---|
| 572 | +static const struct file_operations rt2x00debug_restart_hw = { |
---|
| 573 | + .owner = THIS_MODULE, |
---|
| 574 | + .write = rt2x00debug_write_restart_hw, |
---|
| 575 | + .open = simple_open, |
---|
| 576 | + .llseek = generic_file_llseek, |
---|
| 577 | +}; |
---|
| 578 | + |
---|
| 579 | +static void rt2x00debug_create_file_driver(const char *name, |
---|
| 580 | + struct rt2x00debug_intf *intf, |
---|
| 581 | + struct debugfs_blob_wrapper *blob) |
---|
597 | 582 | { |
---|
598 | 583 | char *data; |
---|
599 | 584 | |
---|
600 | 585 | data = kzalloc(3 * MAX_LINE_LENGTH, GFP_KERNEL); |
---|
601 | 586 | if (!data) |
---|
602 | | - return NULL; |
---|
| 587 | + return; |
---|
603 | 588 | |
---|
604 | 589 | blob->data = data; |
---|
605 | 590 | data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name); |
---|
606 | 591 | data += sprintf(data, "version:\t%s\n", DRV_VERSION); |
---|
607 | 592 | blob->size = strlen(blob->data); |
---|
608 | 593 | |
---|
609 | | - return debugfs_create_blob(name, 0400, intf->driver_folder, blob); |
---|
| 594 | + debugfs_create_blob(name, 0400, intf->driver_folder, blob); |
---|
610 | 595 | } |
---|
611 | 596 | |
---|
612 | | -static struct dentry *rt2x00debug_create_file_chipset(const char *name, |
---|
613 | | - struct rt2x00debug_intf |
---|
614 | | - *intf, |
---|
615 | | - struct |
---|
616 | | - debugfs_blob_wrapper |
---|
617 | | - *blob) |
---|
| 597 | +static void rt2x00debug_create_file_chipset(const char *name, |
---|
| 598 | + struct rt2x00debug_intf *intf, |
---|
| 599 | + struct debugfs_blob_wrapper *blob) |
---|
618 | 600 | { |
---|
619 | 601 | const struct rt2x00debug *debug = intf->debug; |
---|
620 | 602 | char *data; |
---|
621 | 603 | |
---|
622 | 604 | data = kzalloc(9 * MAX_LINE_LENGTH, GFP_KERNEL); |
---|
623 | 605 | if (!data) |
---|
624 | | - return NULL; |
---|
| 606 | + return; |
---|
625 | 607 | |
---|
626 | 608 | blob->data = data; |
---|
627 | 609 | data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt); |
---|
.. | .. |
---|
647 | 629 | |
---|
648 | 630 | blob->size = strlen(blob->data); |
---|
649 | 631 | |
---|
650 | | - return debugfs_create_blob(name, 0400, intf->driver_folder, blob); |
---|
| 632 | + debugfs_create_blob(name, 0400, intf->driver_folder, blob); |
---|
651 | 633 | } |
---|
652 | 634 | |
---|
653 | 635 | void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) |
---|
654 | 636 | { |
---|
655 | 637 | const struct rt2x00debug *debug = rt2x00dev->ops->debugfs; |
---|
656 | 638 | struct rt2x00debug_intf *intf; |
---|
| 639 | + struct dentry *queue_folder; |
---|
| 640 | + struct dentry *register_folder; |
---|
657 | 641 | |
---|
658 | 642 | intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL); |
---|
659 | 643 | if (!intf) { |
---|
.. | .. |
---|
668 | 652 | intf->driver_folder = |
---|
669 | 653 | debugfs_create_dir(intf->rt2x00dev->ops->name, |
---|
670 | 654 | rt2x00dev->hw->wiphy->debugfsdir); |
---|
671 | | - if (IS_ERR(intf->driver_folder) || !intf->driver_folder) |
---|
672 | | - goto exit; |
---|
673 | 655 | |
---|
674 | | - intf->driver_entry = |
---|
675 | | - rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob); |
---|
676 | | - if (IS_ERR(intf->driver_entry) || !intf->driver_entry) |
---|
677 | | - goto exit; |
---|
| 656 | + rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob); |
---|
| 657 | + rt2x00debug_create_file_chipset("chipset", intf, &intf->chipset_blob); |
---|
| 658 | + debugfs_create_file("dev_flags", 0400, intf->driver_folder, intf, |
---|
| 659 | + &rt2x00debug_fop_dev_flags); |
---|
| 660 | + debugfs_create_file("cap_flags", 0400, intf->driver_folder, intf, |
---|
| 661 | + &rt2x00debug_fop_cap_flags); |
---|
| 662 | + debugfs_create_file("restart_hw", 0200, intf->driver_folder, intf, |
---|
| 663 | + &rt2x00debug_restart_hw); |
---|
678 | 664 | |
---|
679 | | - intf->chipset_entry = |
---|
680 | | - rt2x00debug_create_file_chipset("chipset", |
---|
681 | | - intf, &intf->chipset_blob); |
---|
682 | | - if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry) |
---|
683 | | - goto exit; |
---|
684 | | - |
---|
685 | | - intf->dev_flags = debugfs_create_file("dev_flags", 0400, |
---|
686 | | - intf->driver_folder, intf, |
---|
687 | | - &rt2x00debug_fop_dev_flags); |
---|
688 | | - if (IS_ERR(intf->dev_flags) || !intf->dev_flags) |
---|
689 | | - goto exit; |
---|
690 | | - |
---|
691 | | - intf->cap_flags = debugfs_create_file("cap_flags", 0400, |
---|
692 | | - intf->driver_folder, intf, |
---|
693 | | - &rt2x00debug_fop_cap_flags); |
---|
694 | | - if (IS_ERR(intf->cap_flags) || !intf->cap_flags) |
---|
695 | | - goto exit; |
---|
696 | | - |
---|
697 | | - intf->register_folder = |
---|
698 | | - debugfs_create_dir("register", intf->driver_folder); |
---|
699 | | - if (IS_ERR(intf->register_folder) || !intf->register_folder) |
---|
700 | | - goto exit; |
---|
| 665 | + register_folder = debugfs_create_dir("register", intf->driver_folder); |
---|
701 | 666 | |
---|
702 | 667 | #define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ |
---|
703 | 668 | ({ \ |
---|
704 | 669 | if (debug->__name.read) { \ |
---|
705 | | - (__intf)->__name##_off_entry = \ |
---|
706 | | - debugfs_create_u32(__stringify(__name) "_offset", \ |
---|
707 | | - 0600, \ |
---|
708 | | - (__intf)->register_folder, \ |
---|
709 | | - &(__intf)->offset_##__name); \ |
---|
710 | | - if (IS_ERR((__intf)->__name##_off_entry) || \ |
---|
711 | | - !(__intf)->__name##_off_entry) \ |
---|
712 | | - goto exit; \ |
---|
| 670 | + debugfs_create_u32(__stringify(__name) "_offset", 0600, \ |
---|
| 671 | + register_folder, \ |
---|
| 672 | + &(__intf)->offset_##__name); \ |
---|
713 | 673 | \ |
---|
714 | | - (__intf)->__name##_val_entry = \ |
---|
715 | | - debugfs_create_file(__stringify(__name) "_value", \ |
---|
716 | | - 0600, \ |
---|
717 | | - (__intf)->register_folder, \ |
---|
718 | | - (__intf), \ |
---|
719 | | - &rt2x00debug_fop_##__name); \ |
---|
720 | | - if (IS_ERR((__intf)->__name##_val_entry) || \ |
---|
721 | | - !(__intf)->__name##_val_entry) \ |
---|
722 | | - goto exit; \ |
---|
| 674 | + debugfs_create_file(__stringify(__name) "_value", 0600, \ |
---|
| 675 | + register_folder, (__intf), \ |
---|
| 676 | + &rt2x00debug_fop_##__name); \ |
---|
723 | 677 | } \ |
---|
724 | 678 | }) |
---|
725 | 679 | |
---|
.. | .. |
---|
731 | 685 | |
---|
732 | 686 | #undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY |
---|
733 | 687 | |
---|
734 | | - intf->queue_folder = |
---|
735 | | - debugfs_create_dir("queue", intf->driver_folder); |
---|
736 | | - if (IS_ERR(intf->queue_folder) || !intf->queue_folder) |
---|
737 | | - goto exit; |
---|
| 688 | + queue_folder = debugfs_create_dir("queue", intf->driver_folder); |
---|
738 | 689 | |
---|
739 | | - intf->queue_frame_dump_entry = |
---|
740 | | - debugfs_create_file("dump", 0400, intf->queue_folder, |
---|
741 | | - intf, &rt2x00debug_fop_queue_dump); |
---|
742 | | - if (IS_ERR(intf->queue_frame_dump_entry) |
---|
743 | | - || !intf->queue_frame_dump_entry) |
---|
744 | | - goto exit; |
---|
| 690 | + debugfs_create_file("dump", 0400, queue_folder, intf, |
---|
| 691 | + &rt2x00debug_fop_queue_dump); |
---|
745 | 692 | |
---|
746 | 693 | skb_queue_head_init(&intf->frame_dump_skbqueue); |
---|
747 | 694 | init_waitqueue_head(&intf->frame_dump_waitqueue); |
---|
748 | 695 | |
---|
749 | | - intf->queue_stats_entry = |
---|
750 | | - debugfs_create_file("queue", 0400, intf->queue_folder, |
---|
751 | | - intf, &rt2x00debug_fop_queue_stats); |
---|
| 696 | + debugfs_create_file("queue", 0400, queue_folder, intf, |
---|
| 697 | + &rt2x00debug_fop_queue_stats); |
---|
752 | 698 | |
---|
753 | 699 | #ifdef CONFIG_RT2X00_LIB_CRYPTO |
---|
754 | 700 | if (rt2x00_has_cap_hw_crypto(rt2x00dev)) |
---|
755 | | - intf->crypto_stats_entry = |
---|
756 | | - debugfs_create_file("crypto", 0444, intf->queue_folder, |
---|
757 | | - intf, |
---|
758 | | - &rt2x00debug_fop_crypto_stats); |
---|
| 701 | + debugfs_create_file("crypto", 0444, queue_folder, intf, |
---|
| 702 | + &rt2x00debug_fop_crypto_stats); |
---|
759 | 703 | #endif |
---|
760 | 704 | |
---|
761 | 705 | return; |
---|
762 | | - |
---|
763 | | -exit: |
---|
764 | | - rt2x00debug_deregister(rt2x00dev); |
---|
765 | | - rt2x00_err(rt2x00dev, "Failed to register debug handler\n"); |
---|
766 | 706 | } |
---|
767 | 707 | |
---|
768 | 708 | void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) |
---|
.. | .. |
---|
774 | 714 | |
---|
775 | 715 | skb_queue_purge(&intf->frame_dump_skbqueue); |
---|
776 | 716 | |
---|
777 | | -#ifdef CONFIG_RT2X00_LIB_CRYPTO |
---|
778 | | - debugfs_remove(intf->crypto_stats_entry); |
---|
779 | | -#endif |
---|
780 | | - debugfs_remove(intf->queue_stats_entry); |
---|
781 | | - debugfs_remove(intf->queue_frame_dump_entry); |
---|
782 | | - debugfs_remove(intf->queue_folder); |
---|
783 | | - debugfs_remove(intf->rfcsr_val_entry); |
---|
784 | | - debugfs_remove(intf->rfcsr_off_entry); |
---|
785 | | - debugfs_remove(intf->rf_val_entry); |
---|
786 | | - debugfs_remove(intf->rf_off_entry); |
---|
787 | | - debugfs_remove(intf->bbp_val_entry); |
---|
788 | | - debugfs_remove(intf->bbp_off_entry); |
---|
789 | | - debugfs_remove(intf->eeprom_val_entry); |
---|
790 | | - debugfs_remove(intf->eeprom_off_entry); |
---|
791 | | - debugfs_remove(intf->csr_val_entry); |
---|
792 | | - debugfs_remove(intf->csr_off_entry); |
---|
793 | | - debugfs_remove(intf->register_folder); |
---|
794 | | - debugfs_remove(intf->dev_flags); |
---|
795 | | - debugfs_remove(intf->cap_flags); |
---|
796 | | - debugfs_remove(intf->chipset_entry); |
---|
797 | | - debugfs_remove(intf->driver_entry); |
---|
798 | | - debugfs_remove(intf->driver_folder); |
---|
| 717 | + debugfs_remove_recursive(intf->driver_folder); |
---|
799 | 718 | kfree(intf->chipset_blob.data); |
---|
800 | 719 | kfree(intf->driver_blob.data); |
---|
801 | 720 | kfree(intf); |
---|