Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: dwc3: debugfs: Add and remove endpoint dirs dynamically

The DWC3 DebugFS directory and files are currently created once
during probe. This includes creation of subdirectories for each
of the gadget's endpoints. This works fine for peripheral-only
controllers, as dwc3_core_init_mode() calls dwc3_gadget_init()
just prior to calling dwc3_debugfs_init().

However, for dual-role controllers, dwc3_core_init_mode() will
instead call dwc3_drd_init() which is problematic in a few ways.
First, the initial state must be determined, then dwc3_set_mode()
will have to schedule drd_work and by then dwc3_debugfs_init()
could have already been invoked. Even if the initial mode is
peripheral, dwc3_gadget_init() happens after the DebugFS files
are created, and worse so if the initial state is host and the
controller switches to peripheral much later. And secondly,
even if the gadget endpoints' debug entries were successfully
created, if the controller exits peripheral mode, its dwc3_eps
are freed so the debug files would now hold stale references.

So it is best if the DebugFS endpoint entries are created and
removed dynamically at the same time the underlying dwc3_eps are.
Do this by calling dwc3_debugfs_create_endpoint_dir() as each
endpoint is created, and conversely remove the DebugFS entry when
the endpoint is freed.

Fixes: 41ce1456e1db ("usb: dwc3: core: make dwc3_set_mode() work properly")
Cc: stable <stable@vger.kernel.org>
Reviewed-by: Peter Chen <peter.chen@kernel.org>
Signed-off-by: Jack Pham <jackp@codeaurora.org>
Link: https://lore.kernel.org/r/20210529192932.22912-1-jackp@codeaurora.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Jack Pham and committed by
Greg Kroah-Hartman
8d396bb0 6490fa56

+8 -19
+3
drivers/usb/dwc3/debug.h
··· 413 413 414 414 415 415 #ifdef CONFIG_DEBUG_FS 416 + extern void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep); 416 417 extern void dwc3_debugfs_init(struct dwc3 *d); 417 418 extern void dwc3_debugfs_exit(struct dwc3 *d); 418 419 #else 420 + static inline void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep) 421 + { } 419 422 static inline void dwc3_debugfs_init(struct dwc3 *d) 420 423 { } 421 424 static inline void dwc3_debugfs_exit(struct dwc3 *d)
+2 -19
drivers/usb/dwc3/debugfs.c
··· 886 886 } 887 887 } 888 888 889 - static void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep, 890 - struct dentry *parent) 889 + void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep) 891 890 { 892 891 struct dentry *dir; 893 892 894 - dir = debugfs_create_dir(dep->name, parent); 893 + dir = debugfs_create_dir(dep->name, dep->dwc->root); 895 894 dwc3_debugfs_create_endpoint_files(dep, dir); 896 - } 897 - 898 - static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc, 899 - struct dentry *parent) 900 - { 901 - int i; 902 - 903 - for (i = 0; i < dwc->num_eps; i++) { 904 - struct dwc3_ep *dep = dwc->eps[i]; 905 - 906 - if (!dep) 907 - continue; 908 - 909 - dwc3_debugfs_create_endpoint_dir(dep, parent); 910 - } 911 895 } 912 896 913 897 void dwc3_debugfs_init(struct dwc3 *dwc) ··· 924 940 &dwc3_testmode_fops); 925 941 debugfs_create_file("link_state", 0644, root, dwc, 926 942 &dwc3_link_state_fops); 927 - dwc3_debugfs_create_endpoint_dirs(dwc, root); 928 943 } 929 944 } 930 945
+3
drivers/usb/dwc3/gadget.c
··· 2753 2753 INIT_LIST_HEAD(&dep->started_list); 2754 2754 INIT_LIST_HEAD(&dep->cancelled_list); 2755 2755 2756 + dwc3_debugfs_create_endpoint_dir(dep); 2757 + 2756 2758 return 0; 2757 2759 } 2758 2760 ··· 2798 2796 list_del(&dep->endpoint.ep_list); 2799 2797 } 2800 2798 2799 + debugfs_remove_recursive(debugfs_lookup(dep->name, dwc->root)); 2801 2800 kfree(dep); 2802 2801 } 2803 2802 }