Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1615161 > unrolled thread

[PATCH v3 0/3] usb: dwc3: dual-role support

Started byRoger Quadros <rogerq@ti.com>
First post2017-04-03 14:30 +0200
Last post2017-04-03 14:30 +0200
Articles 20 on this page of 21 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v3 0/3] usb: dwc3: dual-role support Roger Quadros <rogerq@ti.com> - 2017-04-03 14:30 +0200
    [PATCH v3 3/3] usb: dwc3: Add dual-role support Roger Quadros <rogerq@ti.com> - 2017-04-03 14:30 +0200
      Re: [PATCH v3 3/3] usb: dwc3: Add dual-role support kbuild test robot <lkp@intel.com> - 2017-04-03 21:30 +0200
        Re: [PATCH v3 3/3] usb: dwc3: Add dual-role support Roger Quadros <rogerq@ti.com> - 2017-04-04 09:50 +0200
      [PATCH v4 3/3] usb: dwc3: Add dual-role support Roger Quadros <rogerq@ti.com> - 2017-04-04 09:50 +0200
    [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device Roger Quadros <rogerq@ti.com> - 2017-04-03 14:30 +0200
      Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same  gadget device Alan Stern <stern@rowland.harvard.edu> - 2017-04-03 16:20 +0200
        Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device Felipe Balbi <balbi@kernel.org> - 2017-04-04 09:50 +0200
          Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same  gadget device Alan Stern <stern@rowland.harvard.edu> - 2017-04-04 16:20 +0200
            Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device Felipe Balbi <balbi@kernel.org> - 2017-04-05 10:40 +0200
              Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same  gadget device Alan Stern <stern@rowland.harvard.edu> - 2017-04-05 16:20 +0200
                Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device Felipe Balbi <balbi@kernel.org> - 2017-04-10 12:10 +0200
                  Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same  gadget device Alan Stern <stern@rowland.harvard.edu> - 2017-04-10 17:20 +0200
                    Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device Felipe Balbi <balbi@kernel.org> - 2017-04-11 09:40 +0200
                      Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same  gadget device Alan Stern <stern@rowland.harvard.edu> - 2017-04-11 16:20 +0200
                        Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same  gadget device Greg KH <greg@kroah.com> - 2017-04-11 16:20 +0200
                          Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device Felipe Balbi <balbi@kernel.org> - 2017-04-12 08:10 +0200
                            Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same  gadget device Greg KH <greg@kroah.com> - 2017-04-12 08:50 +0200
                              Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device Felipe Balbi <balbi@kernel.org> - 2017-04-12 09:40 +0200
                            Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same  gadget device Alan Stern <stern@rowland.harvard.edu> - 2017-04-12 16:40 +0200
    [PATCH v3 2/3] usb: dwc3: make role-switching work with debugfs/mode Roger Quadros <rogerq@ti.com> - 2017-04-03 14:30 +0200

Page 1 of 2  [1] 2  Next page →


#1615161 — [PATCH v3 0/3] usb: dwc3: dual-role support

FromRoger Quadros <rogerq@ti.com>
Date2017-04-03 14:30 +0200
Subject[PATCH v3 0/3] usb: dwc3: dual-role support
Message-ID<ts9ho-6Oe-11@gated-at.bofh.it>
Hi,

Taking a simplistic approach this time. We don't use the OTG controller
block at all. Instead we just rely on ID events via extcon framework.

I tried to get rid of workqueue but unfortunately it causes too much pain
when the UDC is unregistered.

https://hastebin.com/upugaqogol.xml
https://hastebin.com/yayaduqodo.xml

So I've still kept the workqueue around.

We also have debugfs role switching, but I don't yet see how we
can use this for real testing as I still need to manually plug/unplug
the USB cables (host vs device) to test switching :).

v3:
- restructure and simplify. Remove OTG controller code, only rely on extcon.

cheers,
-roger

Roger Quadros (3):
  usb: udc: allow adding and removing the same gadget device
  usb: dwc3: make role-switching work with debugfs/mode
  usb: dwc3: Add dual-role support

 drivers/usb/dwc3/Makefile     |   4 +
 drivers/usb/dwc3/core.c       |  18 ++---
 drivers/usb/dwc3/core.h       |  22 ++++++
 drivers/usb/dwc3/debugfs.c    |  49 +++++++++++--
 drivers/usb/dwc3/drd.c        | 167 ++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/udc/core.c |   1 +
 6 files changed, 242 insertions(+), 19 deletions(-)
 create mode 100644 drivers/usb/dwc3/drd.c

-- 
2.7.4

[toc] | [next] | [standalone]


#1615162 — [PATCH v3 3/3] usb: dwc3: Add dual-role support

FromRoger Quadros <rogerq@ti.com>
Date2017-04-03 14:30 +0200
Subject[PATCH v3 3/3] usb: dwc3: Add dual-role support
Message-ID<ts9ho-6Oe-9@gated-at.bofh.it>
In reply to#1615161
If dr_mode is "otg" then support dual role mode of operation.
Currently this mode is only supported when an extcon handle is
present in the dwc3 device tree node. This is needed to
get the ID status events of the port.

We're using a workqueue to manage the dual-role state transitions
as the extcon notifier (dwc3_drd_notifier) is called in an atomic
context by extcon_sync() and this doesn't go well with
usb_del_gadget_udc() causing a lockdep and softirq warning.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/dwc3/Makefile |   4 ++
 drivers/usb/dwc3/core.c   |  15 +----
 drivers/usb/dwc3/core.h   |  19 ++++++
 drivers/usb/dwc3/drd.c    | 167 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 193 insertions(+), 12 deletions(-)
 create mode 100644 drivers/usb/dwc3/drd.c

diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index ffca340..f15fabb 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -17,6 +17,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
 	dwc3-y				+= gadget.o ep0.o
 endif
 
+ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
+	dwc3-y				+= drd.o
+endif
+
 ifneq ($(CONFIG_USB_DWC3_ULPI),)
 	dwc3-y				+= ulpi.o
 endif
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index bf917c2..15c05a1 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -864,12 +864,10 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 		}
 		break;
 	case USB_DR_MODE_OTG:
-		/* start in peripheral role by default */
-		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
-		ret = dwc3_gadget_init(dwc);
+		ret = dwc3_drd_init(dwc);
 		if (ret) {
 			if (ret != -EPROBE_DEFER)
-				dev_err(dev, "failed to initialize gadget\n");
+				dev_err(dev, "failed to initialize dual-role\n");
 			return ret;
 		}
 		break;
@@ -891,14 +889,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
 		dwc3_host_exit(dwc);
 		break;
 	case USB_DR_MODE_OTG:
-		/* role might have changed since start */
-		if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) {
-			dwc3_host_exit(dwc);
-			/* Add back UDC to match dwc3_gadget_exit() */
-			usb_add_gadget_udc(dwc->dev, &dwc->gadget);
-		}
-
-		dwc3_gadget_exit(dwc);
+		dwc3_drd_exit(dwc);
 		break;
 	default:
 		/* do nothing */
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index adb04af..8402d8f 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -786,6 +786,10 @@ struct dwc3_scratchpad_array {
  * @revision: revision register contents
  * @dr_mode: requested mode of operation
  * @current_dr_role: current role of operation when in dual-role mode
+ * @edev: extcon handle
+ * @edev_nb: extcon notifier
+ * @drd_work: dual-role work
+ * @drd_prevent_change: flag to prevent dual-role state change
  * @hsphy_mode: UTMI phy mode, one of following:
  *		- USBPHY_INTERFACE_MODE_UTMI
  *		- USBPHY_INTERFACE_MODE_UTMIW
@@ -903,6 +907,11 @@ struct dwc3 {
 
 	enum usb_dr_mode	dr_mode;
 	u32			current_dr_role;
+	struct extcon_dev	*edev;
+	struct notifier_block	edev_nb;
+	bool			drd_prevent_change;
+	struct work_struct	drd_work;
+
 	enum usb_phy_interface	hsphy_mode;
 
 	u32			fladj;
@@ -1225,6 +1234,16 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
 { return 0; }
 #endif
 
+#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_drd_init(struct dwc3 *dwc);
+void dwc3_drd_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_drd_init(struct dwc3 *dwc)
+{ return 0; }
+static void dwc3_drd_exit(struct dwc3 *dwc);
+{ }
+#endif
+
 /* power management interface */
 #if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
 int dwc3_gadget_suspend(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
new file mode 100644
index 0000000..c9b02a3
--- /dev/null
+++ b/drivers/usb/dwc3/drd.c
@@ -0,0 +1,167 @@
+/**
+ * drd.c - DesignWare USB3 DRD Controller Dual-role support
+ *
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/extcon.h>
+
+#include "debug.h"
+#include "core.h"
+#include "gadget.h"
+
+static void dwc3_drd_update(struct dwc3 *dwc)
+{
+	int id;
+	int new_role;
+	unsigned long flags;
+
+	if (dwc->drd_prevent_change)
+		return;
+
+	id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
+	/* Host means ID is 0 */
+	id = !id;
+
+	if (!id)
+		new_role = DWC3_GCTL_PRTCAP_HOST;
+	else
+		new_role = DWC3_GCTL_PRTCAP_DEVICE;
+
+	if (dwc->current_dr_role == new_role)
+		return;
+
+	/* stop old role */
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		dwc3_host_exit(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		usb_del_gadget_udc(&dwc->gadget);
+		break;
+	default:
+		break;
+	}
+
+	/* switch PRTCAP mode. updates current_dr_role */
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_set_mode(dwc, new_role);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	/* start new role */
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		dwc3_host_init(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		dwc3_event_buffers_setup(dwc);
+		usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+		break;
+	default:
+		break;
+	}
+}
+
+static void dwc3_drd_work(struct work_struct *work)
+{
+	struct dwc3 *dwc = container_of(work, struct dwc3,
+					drd_work);
+	dwc3_drd_update(dwc);
+}
+
+static int dwc3_drd_notifier(struct notifier_block *nb,
+			     unsigned long event, void *ptr)
+{
+	struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
+
+	queue_work(system_power_efficient_wq, &dwc->drd_work);
+
+	return NOTIFY_DONE;
+}
+
+int dwc3_drd_init(struct dwc3 *dwc)
+{
+	int ret;
+	int id;
+	struct device *dev = dwc->dev;
+
+	INIT_WORK(&dwc->drd_work, dwc3_drd_work);
+
+	if (dev->of_node) {
+		if (of_property_read_bool(dev->of_node, "extcon"))
+			dwc->edev = extcon_get_edev_by_phandle(dev, 0);
+
+		if (IS_ERR(dwc->edev))
+			return PTR_ERR(dwc->edev);
+	} else {
+		return -ENODEV;
+	}
+
+	dwc->edev_nb.notifier_call = dwc3_drd_notifier;
+	ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
+				       &dwc->edev_nb);
+	if (ret < 0) {
+		dev_err(dwc->dev, "Couldn't register USB-HOST cable notifier\n");
+		return -ENODEV;
+	}
+
+	/* sanity check id & vbus states */
+	id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
+	if (id < 0) {
+		dev_err(dwc->dev, "Invalid USB cable state. ID %d", id);
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	/* start in peripheral role by default */
+	dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+	ret = dwc3_gadget_init(dwc);
+	if (ret)
+		goto fail;
+
+	/* check & update drd state */
+	dwc3_drd_update(dwc);
+
+	return 0;
+
+fail:
+	extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+				   &dwc->edev_nb);
+
+	return ret;
+}
+
+void dwc3_drd_exit(struct dwc3 *dwc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc->drd_prevent_change = true;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+				   &dwc->edev_nb);
+
+	/* role might have changed since start, stop active controller */
+	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) {
+		dwc3_host_exit(dwc);
+		/* Add back UDC to match dwc3_gadget_exit() */
+		usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+	}
+
+	dwc3_gadget_exit(dwc);
+}
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1615511 — Re: [PATCH v3 3/3] usb: dwc3: Add dual-role support

Fromkbuild test robot <lkp@intel.com>
Date2017-04-03 21:30 +0200
SubjectRe: [PATCH v3 3/3] usb: dwc3: Add dual-role support
Message-ID<tsfPP-2Fz-1@gated-at.bofh.it>
In reply to#1615162

[Multipart message — attachments visible in raw view] — view raw

Hi Roger,

[auto build test ERROR on balbi-usb/next]
[also build test ERROR on v4.11-rc5 next-20170403]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Roger-Quadros/usb-dwc3-dual-role-support/20170404-022401
base:   https://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git next
config: i386-randconfig-x010-201714 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All error/warnings (new ones prefixed by >>):

   In file included from drivers/usb/dwc3/core.c:44:0:
>> drivers/usb/dwc3/core.h:1243:1: error: expected identifier or '(' before '{' token
    { }
    ^
>> drivers/usb/dwc3/core.h:1242:13: warning: 'dwc3_drd_exit' used but never defined
    static void dwc3_drd_exit(struct dwc3 *dwc);
                ^~~~~~~~~~~~~
--
   In file included from drivers/usb/dwc3/trace.h:27:0,
                    from drivers/usb/dwc3/trace.c:19:
>> drivers/usb/dwc3/core.h:1243:1: error: expected identifier or '(' before '{' token
    { }
    ^
   In file included from drivers/usb/dwc3/trace.h:27:0,
                    from drivers/usb/dwc3/trace.c:19:
   drivers/usb/dwc3/core.h:1242:13: warning: 'dwc3_drd_exit' declared 'static' but never defined [-Wunused-function]
    static void dwc3_drd_exit(struct dwc3 *dwc);
                ^~~~~~~~~~~~~

vim +1243 drivers/usb/dwc3/core.h

  1236	#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
  1237	int dwc3_drd_init(struct dwc3 *dwc);
  1238	void dwc3_drd_exit(struct dwc3 *dwc);
  1239	#else
  1240	static inline int dwc3_drd_init(struct dwc3 *dwc)
  1241	{ return 0; }
> 1242	static void dwc3_drd_exit(struct dwc3 *dwc);
> 1243	{ }
  1244	#endif
  1245	
  1246	/* power management interface */

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[toc] | [prev] | [next] | [standalone]


#1615760 — Re: [PATCH v3 3/3] usb: dwc3: Add dual-role support

FromRoger Quadros <rogerq@ti.com>
Date2017-04-04 09:50 +0200
SubjectRe: [PATCH v3 3/3] usb: dwc3: Add dual-role support
Message-ID<tsrnY-1QN-17@gated-at.bofh.it>
In reply to#1615511
Felipe,

I'll send a revised patch to fix this.

cheers,
-roger

On 03/04/17 22:21, kbuild test robot wrote:
> Hi Roger,
> 
> [auto build test ERROR on balbi-usb/next]
> [also build test ERROR on v4.11-rc5 next-20170403]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Roger-Quadros/usb-dwc3-dual-role-support/20170404-022401
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git next
> config: i386-randconfig-x010-201714 (attached as .config)
> compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=i386 
> 
> All error/warnings (new ones prefixed by >>):
> 
>    In file included from drivers/usb/dwc3/core.c:44:0:
>>> drivers/usb/dwc3/core.h:1243:1: error: expected identifier or '(' before '{' token
>     { }
>     ^
>>> drivers/usb/dwc3/core.h:1242:13: warning: 'dwc3_drd_exit' used but never defined
>     static void dwc3_drd_exit(struct dwc3 *dwc);
>                 ^~~~~~~~~~~~~
> --
>    In file included from drivers/usb/dwc3/trace.h:27:0,
>                     from drivers/usb/dwc3/trace.c:19:
>>> drivers/usb/dwc3/core.h:1243:1: error: expected identifier or '(' before '{' token
>     { }
>     ^
>    In file included from drivers/usb/dwc3/trace.h:27:0,
>                     from drivers/usb/dwc3/trace.c:19:
>    drivers/usb/dwc3/core.h:1242:13: warning: 'dwc3_drd_exit' declared 'static' but never defined [-Wunused-function]
>     static void dwc3_drd_exit(struct dwc3 *dwc);
>                 ^~~~~~~~~~~~~
> 
> vim +1243 drivers/usb/dwc3/core.h
> 
>   1236	#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
>   1237	int dwc3_drd_init(struct dwc3 *dwc);
>   1238	void dwc3_drd_exit(struct dwc3 *dwc);
>   1239	#else
>   1240	static inline int dwc3_drd_init(struct dwc3 *dwc)
>   1241	{ return 0; }
>> 1242	static void dwc3_drd_exit(struct dwc3 *dwc);
>> 1243	{ }
>   1244	#endif
>   1245	
>   1246	/* power management interface */
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
> 

[toc] | [prev] | [next] | [standalone]


#1615757 — [PATCH v4 3/3] usb: dwc3: Add dual-role support

FromRoger Quadros <rogerq@ti.com>
Date2017-04-04 09:50 +0200
Subject[PATCH v4 3/3] usb: dwc3: Add dual-role support
Message-ID<tsrnX-1QN-11@gated-at.bofh.it>
In reply to#1615162
If dr_mode is "otg" then support dual role mode of operation.
Currently this mode is only supported when an extcon handle is
present in the dwc3 device tree node. This is needed to
get the ID status events of the port.

We're using a workqueue to manage the dual-role state transitions
as the extcon notifier (dwc3_drd_notifier) is called in an atomic
context by extcon_sync() and this doesn't go well with
usb_del_gadget_udc() causing a lockdep and softirq warning.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
v4:
-fix build error if CONFIG_USB_DWC3_DUAL_ROLE is not set

 drivers/usb/dwc3/Makefile |   4 ++
 drivers/usb/dwc3/core.c   |  15 +----
 drivers/usb/dwc3/core.h   |  19 ++++++
 drivers/usb/dwc3/drd.c    | 167 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 193 insertions(+), 12 deletions(-)
 create mode 100644 drivers/usb/dwc3/drd.c

diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index ffca340..f15fabb 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -17,6 +17,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
 	dwc3-y				+= gadget.o ep0.o
 endif
 
+ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
+	dwc3-y				+= drd.o
+endif
+
 ifneq ($(CONFIG_USB_DWC3_ULPI),)
 	dwc3-y				+= ulpi.o
 endif
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index bf917c2..15c05a1 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -864,12 +864,10 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 		}
 		break;
 	case USB_DR_MODE_OTG:
-		/* start in peripheral role by default */
-		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
-		ret = dwc3_gadget_init(dwc);
+		ret = dwc3_drd_init(dwc);
 		if (ret) {
 			if (ret != -EPROBE_DEFER)
-				dev_err(dev, "failed to initialize gadget\n");
+				dev_err(dev, "failed to initialize dual-role\n");
 			return ret;
 		}
 		break;
@@ -891,14 +889,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
 		dwc3_host_exit(dwc);
 		break;
 	case USB_DR_MODE_OTG:
-		/* role might have changed since start */
-		if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) {
-			dwc3_host_exit(dwc);
-			/* Add back UDC to match dwc3_gadget_exit() */
-			usb_add_gadget_udc(dwc->dev, &dwc->gadget);
-		}
-
-		dwc3_gadget_exit(dwc);
+		dwc3_drd_exit(dwc);
 		break;
 	default:
 		/* do nothing */
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index adb04af..b1be4a3 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -786,6 +786,10 @@ struct dwc3_scratchpad_array {
  * @revision: revision register contents
  * @dr_mode: requested mode of operation
  * @current_dr_role: current role of operation when in dual-role mode
+ * @edev: extcon handle
+ * @edev_nb: extcon notifier
+ * @drd_work: dual-role work
+ * @drd_prevent_change: flag to prevent dual-role state change
  * @hsphy_mode: UTMI phy mode, one of following:
  *		- USBPHY_INTERFACE_MODE_UTMI
  *		- USBPHY_INTERFACE_MODE_UTMIW
@@ -903,6 +907,11 @@ struct dwc3 {
 
 	enum usb_dr_mode	dr_mode;
 	u32			current_dr_role;
+	struct extcon_dev	*edev;
+	struct notifier_block	edev_nb;
+	bool			drd_prevent_change;
+	struct work_struct	drd_work;
+
 	enum usb_phy_interface	hsphy_mode;
 
 	u32			fladj;
@@ -1225,6 +1234,16 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
 { return 0; }
 #endif
 
+#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_drd_init(struct dwc3 *dwc);
+void dwc3_drd_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_drd_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_drd_exit(struct dwc3 *dwc)
+{ }
+#endif
+
 /* power management interface */
 #if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
 int dwc3_gadget_suspend(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
new file mode 100644
index 0000000..c9b02a3
--- /dev/null
+++ b/drivers/usb/dwc3/drd.c
@@ -0,0 +1,167 @@
+/**
+ * drd.c - DesignWare USB3 DRD Controller Dual-role support
+ *
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/extcon.h>
+
+#include "debug.h"
+#include "core.h"
+#include "gadget.h"
+
+static void dwc3_drd_update(struct dwc3 *dwc)
+{
+	int id;
+	int new_role;
+	unsigned long flags;
+
+	if (dwc->drd_prevent_change)
+		return;
+
+	id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
+	/* Host means ID is 0 */
+	id = !id;
+
+	if (!id)
+		new_role = DWC3_GCTL_PRTCAP_HOST;
+	else
+		new_role = DWC3_GCTL_PRTCAP_DEVICE;
+
+	if (dwc->current_dr_role == new_role)
+		return;
+
+	/* stop old role */
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		dwc3_host_exit(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		usb_del_gadget_udc(&dwc->gadget);
+		break;
+	default:
+		break;
+	}
+
+	/* switch PRTCAP mode. updates current_dr_role */
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_set_mode(dwc, new_role);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	/* start new role */
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		dwc3_host_init(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		dwc3_event_buffers_setup(dwc);
+		usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+		break;
+	default:
+		break;
+	}
+}
+
+static void dwc3_drd_work(struct work_struct *work)
+{
+	struct dwc3 *dwc = container_of(work, struct dwc3,
+					drd_work);
+	dwc3_drd_update(dwc);
+}
+
+static int dwc3_drd_notifier(struct notifier_block *nb,
+			     unsigned long event, void *ptr)
+{
+	struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
+
+	queue_work(system_power_efficient_wq, &dwc->drd_work);
+
+	return NOTIFY_DONE;
+}
+
+int dwc3_drd_init(struct dwc3 *dwc)
+{
+	int ret;
+	int id;
+	struct device *dev = dwc->dev;
+
+	INIT_WORK(&dwc->drd_work, dwc3_drd_work);
+
+	if (dev->of_node) {
+		if (of_property_read_bool(dev->of_node, "extcon"))
+			dwc->edev = extcon_get_edev_by_phandle(dev, 0);
+
+		if (IS_ERR(dwc->edev))
+			return PTR_ERR(dwc->edev);
+	} else {
+		return -ENODEV;
+	}
+
+	dwc->edev_nb.notifier_call = dwc3_drd_notifier;
+	ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
+				       &dwc->edev_nb);
+	if (ret < 0) {
+		dev_err(dwc->dev, "Couldn't register USB-HOST cable notifier\n");
+		return -ENODEV;
+	}
+
+	/* sanity check id & vbus states */
+	id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
+	if (id < 0) {
+		dev_err(dwc->dev, "Invalid USB cable state. ID %d", id);
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	/* start in peripheral role by default */
+	dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+	ret = dwc3_gadget_init(dwc);
+	if (ret)
+		goto fail;
+
+	/* check & update drd state */
+	dwc3_drd_update(dwc);
+
+	return 0;
+
+fail:
+	extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+				   &dwc->edev_nb);
+
+	return ret;
+}
+
+void dwc3_drd_exit(struct dwc3 *dwc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc->drd_prevent_change = true;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+				   &dwc->edev_nb);
+
+	/* role might have changed since start, stop active controller */
+	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) {
+		dwc3_host_exit(dwc);
+		/* Add back UDC to match dwc3_gadget_exit() */
+		usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+	}
+
+	dwc3_gadget_exit(dwc);
+}
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1615163 — [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromRoger Quadros <rogerq@ti.com>
Date2017-04-03 14:30 +0200
Subject[PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<ts9ho-6Oe-25@gated-at.bofh.it>
In reply to#1615161
allow usb_del_gadget_udc() and usb add_gadget_udc() to be called
repeatedly on the same gadget->dev structure.

We need to clear the gadget->dev structure so that kobject_init()
doesn't complain about already initialized object.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/gadget/udc/core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index d685d82..efce68e 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
 	device_unregister(&gadget->dev);
+	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
 }
 EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1615229 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromAlan Stern <stern@rowland.harvard.edu>
Date2017-04-03 16:20 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tsaZR-7XD-39@gated-at.bofh.it>
In reply to#1615163
On Mon, 3 Apr 2017, Roger Quadros wrote:

> allow usb_del_gadget_udc() and usb add_gadget_udc() to be called
> repeatedly on the same gadget->dev structure.
> 
> We need to clear the gadget->dev structure so that kobject_init()
> doesn't complain about already initialized object.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/usb/gadget/udc/core.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
> index d685d82..efce68e 100644
> --- a/drivers/usb/gadget/udc/core.c
> +++ b/drivers/usb/gadget/udc/core.c
> @@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
>  	flush_work(&gadget->work);
>  	device_unregister(&udc->dev);
>  	device_unregister(&gadget->dev);
> +	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
>  }
>  EXPORT_SYMBOL_GPL(usb_del_gadget_udc);

Isn't this dangerous?  It's quite possible that the device_unregister() 
call on the previous line invokes the gadget->dev.release callback, 
which might deallocate gadget.  If that happens, your new memset will 
oops.

In general, if an object relies on reference counting for its lifetime, 
you cannot register and unregister it more than once.  A typical issue 
is that some code retains a reference to the old instance and tries to 
use it after the new instance has been registered, thereby messing up 
the new instance.  I don't know if that is possible in this case, but 
it is something to watch out for.

Alan Stern

[toc] | [prev] | [next] | [standalone]


#1615754 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromFelipe Balbi <balbi@kernel.org>
Date2017-04-04 09:50 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tsrnX-1QN-1@gated-at.bofh.it>
In reply to#1615229

[Multipart message — attachments visible in raw view] — view raw

Hi,

Alan Stern <stern@rowland.harvard.edu> writes:
> On Mon, 3 Apr 2017, Roger Quadros wrote:
>
>> allow usb_del_gadget_udc() and usb add_gadget_udc() to be called
>> repeatedly on the same gadget->dev structure.
>> 
>> We need to clear the gadget->dev structure so that kobject_init()
>> doesn't complain about already initialized object.
>> 
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  drivers/usb/gadget/udc/core.c | 1 +
>>  1 file changed, 1 insertion(+)
>> 
>> diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
>> index d685d82..efce68e 100644
>> --- a/drivers/usb/gadget/udc/core.c
>> +++ b/drivers/usb/gadget/udc/core.c
>> @@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
>>  	flush_work(&gadget->work);
>>  	device_unregister(&udc->dev);
>>  	device_unregister(&gadget->dev);
>> +	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
>>  }
>>  EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
>
> Isn't this dangerous?  It's quite possible that the device_unregister() 

not on the gadget API, no.

> call on the previous line invokes the gadget->dev.release callback, 
> which might deallocate gadget.  If that happens, your new memset will 
> oops.

that won't happen. struct usb_gadget is a member of the UDC's private
structure, like this:

struct dwc3 {
	[...]
	struct usb_gadget	gadget;
	struct usb_gadget_driver *gadget_driver;
	[...]
};

I'm actually thinking that struct usb_gadget shouldn't have a struct
device at all. Just a pointer to a device, that would solve all these
issues.

-- 
balbi

[toc] | [prev] | [next] | [standalone]


#1616061 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromAlan Stern <stern@rowland.harvard.edu>
Date2017-04-04 16:20 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tsxtn-5Xs-1@gated-at.bofh.it>
In reply to#1615754
On Tue, 4 Apr 2017, Felipe Balbi wrote:

> Hi,
> 
> Alan Stern <stern@rowland.harvard.edu> writes:
> > On Mon, 3 Apr 2017, Roger Quadros wrote:
> >
> >> allow usb_del_gadget_udc() and usb add_gadget_udc() to be called
> >> repeatedly on the same gadget->dev structure.
> >> 
> >> We need to clear the gadget->dev structure so that kobject_init()
> >> doesn't complain about already initialized object.
> >> 
> >> Signed-off-by: Roger Quadros <rogerq@ti.com>
> >> ---
> >>  drivers/usb/gadget/udc/core.c | 1 +
> >>  1 file changed, 1 insertion(+)
> >> 
> >> diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
> >> index d685d82..efce68e 100644
> >> --- a/drivers/usb/gadget/udc/core.c
> >> +++ b/drivers/usb/gadget/udc/core.c
> >> @@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
> >>  	flush_work(&gadget->work);
> >>  	device_unregister(&udc->dev);
> >>  	device_unregister(&gadget->dev);
> >> +	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
> >>  }
> >>  EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
> >
> > Isn't this dangerous?  It's quite possible that the device_unregister() 
> 
> not on the gadget API, no.
> 
> > call on the previous line invokes the gadget->dev.release callback, 
> > which might deallocate gadget.  If that happens, your new memset will 
> > oops.
> 
> that won't happen. struct usb_gadget is a member of the UDC's private
> structure, like this:
> 
> struct dwc3 {
> 	[...]
> 	struct usb_gadget	gadget;
> 	struct usb_gadget_driver *gadget_driver;
> 	[...]
> };

Yes.  So what?  Can't the UDC driver use the refcount inside struct 
usb_gadget to control the lifetime of its private structure?

(By the way, can you tell what's going on in net2280.c?  I must be
missing something; it looks like gadget_release() would quickly run
into problems because it calls dev_get_drvdata() for &gadget->dev, but
net2280_probe() never calls dev_set_drvdata() for that device.  
Furthermore, net2280_remove() continues to reference the net2280 struct
after calling usb_del_gadget_udc(), and it never does seem to do a
final put.)

> I'm actually thinking that struct usb_gadget shouldn't have a struct
> device at all. Just a pointer to a device, that would solve all these
> issues.

A pointer to which device?  The UDC?  That would change the directory 
layout in sysfs.

Or a pointer to a separate dynamically allocated device (the way struct 
usb_hcd contains a pointer to the root hub device)?  That would work.  
If the UDC driver wanted to re-register the gadget, it would have to 
allocate a new device.

Alan Stern

[toc] | [prev] | [next] | [standalone]


#1616688 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromFelipe Balbi <balbi@kernel.org>
Date2017-04-05 10:40 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tsODT-f3-3@gated-at.bofh.it>
In reply to#1616061

[Multipart message — attachments visible in raw view] — view raw

Hi,

Alan Stern <stern@rowland.harvard.edu> writes:
>> >> allow usb_del_gadget_udc() and usb add_gadget_udc() to be called
>> >> repeatedly on the same gadget->dev structure.
>> >> 
>> >> We need to clear the gadget->dev structure so that kobject_init()
>> >> doesn't complain about already initialized object.
>> >> 
>> >> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> >> ---
>> >>  drivers/usb/gadget/udc/core.c | 1 +
>> >>  1 file changed, 1 insertion(+)
>> >> 
>> >> diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
>> >> index d685d82..efce68e 100644
>> >> --- a/drivers/usb/gadget/udc/core.c
>> >> +++ b/drivers/usb/gadget/udc/core.c
>> >> @@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
>> >>  	flush_work(&gadget->work);
>> >>  	device_unregister(&udc->dev);
>> >>  	device_unregister(&gadget->dev);
>> >> +	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
>> >>  }
>> >>  EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
>> >
>> > Isn't this dangerous?  It's quite possible that the device_unregister() 
>> 
>> not on the gadget API, no.
>> 
>> > call on the previous line invokes the gadget->dev.release callback, 
>> > which might deallocate gadget.  If that happens, your new memset will 
>> > oops.
>> 
>> that won't happen. struct usb_gadget is a member of the UDC's private
>> structure, like this:
>> 
>> struct dwc3 {
>> 	[...]
>> 	struct usb_gadget	gadget;
>> 	struct usb_gadget_driver *gadget_driver;
>> 	[...]
>> };
>
> Yes.  So what?  Can't the UDC driver use the refcount inside struct 
> usb_gadget to control the lifetime of its private structure?

nope, not being used. At least not yet.

> (By the way, can you tell what's going on in net2280.c?  I must be
> missing something; it looks like gadget_release() would quickly run
> into problems because it calls dev_get_drvdata() for &gadget->dev, but
> net2280_probe() never calls dev_set_drvdata() for that device.  
> Furthermore, net2280_remove() continues to reference the net2280 struct
> after calling usb_del_gadget_udc(), and it never does seem to do a
> final put.)

static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	struct net2280		*dev;
	unsigned long		resource, len;
	void			__iomem *base = NULL;
	int			retval, i;

	/* alloc, and start init */
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (dev == NULL) {
		retval = -ENOMEM;
		goto done;
	}

	pci_set_drvdata(pdev, dev);
	^^^^^^^^^^^^^^^^^^^^^^^^^^^

>> I'm actually thinking that struct usb_gadget shouldn't have a struct
>> device at all. Just a pointer to a device, that would solve all these
>> issues.
>
> A pointer to which device?  The UDC?  That would change the directory 
> layout in sysfs.

indeed. Would that be a problem?

> Or a pointer to a separate dynamically allocated device (the way struct 
> usb_hcd contains a pointer to the root hub device)?  That would work.  
> If the UDC driver wanted to re-register the gadget, it would have to 
> allocate a new device.

That could be done as well, if maintaining the directory structure is a
must.

-- 
balbi

[toc] | [prev] | [next] | [standalone]


#1616984 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromAlan Stern <stern@rowland.harvard.edu>
Date2017-04-05 16:20 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tsTWV-3H6-9@gated-at.bofh.it>
In reply to#1616688
On Wed, 5 Apr 2017, Felipe Balbi wrote:

> >> >> --- a/drivers/usb/gadget/udc/core.c
> >> >> +++ b/drivers/usb/gadget/udc/core.c
> >> >> @@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
> >> >>  	flush_work(&gadget->work);
> >> >>  	device_unregister(&udc->dev);
> >> >>  	device_unregister(&gadget->dev);
> >> >> +	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
> >> >>  }
> >> >>  EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
> >> >
> >> > Isn't this dangerous?  It's quite possible that the device_unregister() 
> >> 
> >> not on the gadget API, no.
> >> 
> >> > call on the previous line invokes the gadget->dev.release callback, 
> >> > which might deallocate gadget.  If that happens, your new memset will 
> >> > oops.
> >> 
> >> that won't happen. struct usb_gadget is a member of the UDC's private
> >> structure, like this:
> >> 
> >> struct dwc3 {
> >> 	[...]
> >> 	struct usb_gadget	gadget;
> >> 	struct usb_gadget_driver *gadget_driver;
> >> 	[...]
> >> };
> >
> > Yes.  So what?  Can't the UDC driver use the refcount inside struct 
> > usb_gadget to control the lifetime of its private structure?
> 
> nope, not being used. At least not yet.

I'm not convinced (yet)...

> > (By the way, can you tell what's going on in net2280.c?  I must be
> > missing something; it looks like gadget_release() would quickly run
> > into problems because it calls dev_get_drvdata() for &gadget->dev, but
> > net2280_probe() never calls dev_set_drvdata() for that device.  
> > Furthermore, net2280_remove() continues to reference the net2280 struct
> > after calling usb_del_gadget_udc(), and it never does seem to do a
> > final put.)
> 
> static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> {
> 	struct net2280		*dev;
> 	unsigned long		resource, len;
> 	void			__iomem *base = NULL;
> 	int			retval, i;
> 
> 	/* alloc, and start init */
> 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> 	if (dev == NULL) {
> 		retval = -ENOMEM;
> 		goto done;
> 	}
> 
> 	pci_set_drvdata(pdev, dev);
> 	^^^^^^^^^^^^^^^^^^^^^^^^^^^

That sets the driver data in the struct pci_dev, not in
dev->gadget.dev.  As far as I can see, _nothing_ in the driver sets the 
driver data in dev->gadget.dev.

(Even after all these years, I still get bothered by the way Dave 
Brownell used to call everything "dev"...  IIRC, at one time he had a 
line of code that went something like:  dev->dev.dev = &pdev->dev !)

> >> I'm actually thinking that struct usb_gadget shouldn't have a struct
> >> device at all. Just a pointer to a device, that would solve all these
> >> issues.
> >
> > A pointer to which device?  The UDC?  That would change the directory 
> > layout in sysfs.
> 
> indeed. Would that be a problem?

Possibly for some userspace tool.

> > Or a pointer to a separate dynamically allocated device (the way struct 
> > usb_hcd contains a pointer to the root hub device)?  That would work.  
> > If the UDC driver wanted to re-register the gadget, it would have to 
> > allocate a new device.
> 
> That could be done as well, if maintaining the directory structure is a
> must.

Alan Stern

[toc] | [prev] | [next] | [standalone]


#1619775 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromFelipe Balbi <balbi@kernel.org>
Date2017-04-10 12:10 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tuEqK-7Kj-19@gated-at.bofh.it>
In reply to#1616984

[Multipart message — attachments visible in raw view] — view raw

Hi,

Alan Stern <stern@rowland.harvard.edu> writes:
> On Wed, 5 Apr 2017, Felipe Balbi wrote:
>
>> >> >> --- a/drivers/usb/gadget/udc/core.c
>> >> >> +++ b/drivers/usb/gadget/udc/core.c
>> >> >> @@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
>> >> >>  	flush_work(&gadget->work);
>> >> >>  	device_unregister(&udc->dev);
>> >> >>  	device_unregister(&gadget->dev);
>> >> >> +	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
>> >> >>  }
>> >> >>  EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
>> >> >
>> >> > Isn't this dangerous?  It's quite possible that the device_unregister() 
>> >> 
>> >> not on the gadget API, no.
>> >> 
>> >> > call on the previous line invokes the gadget->dev.release callback, 
>> >> > which might deallocate gadget.  If that happens, your new memset will 
>> >> > oops.
>> >> 
>> >> that won't happen. struct usb_gadget is a member of the UDC's private
>> >> structure, like this:
>> >> 
>> >> struct dwc3 {
>> >> 	[...]
>> >> 	struct usb_gadget	gadget;
>> >> 	struct usb_gadget_driver *gadget_driver;
>> >> 	[...]
>> >> };
>> >
>> > Yes.  So what?  Can't the UDC driver use the refcount inside struct 
>> > usb_gadget to control the lifetime of its private structure?
>> 
>> nope, not being used. At least not yet.
>
> I'm not convinced (yet)...
>
>> > (By the way, can you tell what's going on in net2280.c?  I must be
>> > missing something; it looks like gadget_release() would quickly run
>> > into problems because it calls dev_get_drvdata() for &gadget->dev, but
>> > net2280_probe() never calls dev_set_drvdata() for that device.  
>> > Furthermore, net2280_remove() continues to reference the net2280 struct
>> > after calling usb_del_gadget_udc(), and it never does seem to do a
>> > final put.)
>> 
>> static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>> {
>> 	struct net2280		*dev;
>> 	unsigned long		resource, len;
>> 	void			__iomem *base = NULL;
>> 	int			retval, i;
>> 
>> 	/* alloc, and start init */
>> 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
>> 	if (dev == NULL) {
>> 		retval = -ENOMEM;
>> 		goto done;
>> 	}
>> 
>> 	pci_set_drvdata(pdev, dev);
>> 	^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> That sets the driver data in the struct pci_dev, not in
> dev->gadget.dev.  As far as I can see, _nothing_ in the driver sets the 
> driver data in dev->gadget.dev.

hmmm, indeed. The same is happening with other callers of
usb_add_gadget_udc_release().

I guess this should be enough?

@@ -3557,7 +3557,7 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
 
 static void gadget_release(struct device *_dev)
 {
-	struct net2280	*dev = dev_get_drvdata(_dev);
+	struct net2280	*dev = dev_get_drvdata(_dev->parent);
 
 	kfree(dev);
 }


> (Even after all these years, I still get bothered by the way Dave 
> Brownell used to call everything "dev"...  IIRC, at one time he had a 
> line of code that went something like:  dev->dev.dev = &pdev->dev !)

:-)

>> >> I'm actually thinking that struct usb_gadget shouldn't have a struct
>> >> device at all. Just a pointer to a device, that would solve all these
>> >> issues.
>> >
>> > A pointer to which device?  The UDC?  That would change the directory 
>> > layout in sysfs.
>> 
>> indeed. Would that be a problem?
>
> Possibly for some userspace tool.

yeah, we can do dynamic allocation of the device pointer, no issue.

-- 
balbi

[toc] | [prev] | [next] | [standalone]


#1620017 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromAlan Stern <stern@rowland.harvard.edu>
Date2017-04-10 17:20 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tuJgK-2nZ-9@gated-at.bofh.it>
In reply to#1619775
On Mon, 10 Apr 2017, Felipe Balbi wrote:

> Hi,
> 
> Alan Stern <stern@rowland.harvard.edu> writes:
> > On Wed, 5 Apr 2017, Felipe Balbi wrote:
> >
> >> >> >> --- a/drivers/usb/gadget/udc/core.c
> >> >> >> +++ b/drivers/usb/gadget/udc/core.c
> >> >> >> @@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
> >> >> >>  	flush_work(&gadget->work);
> >> >> >>  	device_unregister(&udc->dev);
> >> >> >>  	device_unregister(&gadget->dev);
> >> >> >> +	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
> >> >> >>  }
> >> >> >>  EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
> >> >> >
> >> >> > Isn't this dangerous?  It's quite possible that the device_unregister() 
> >> >> 
> >> >> not on the gadget API, no.
> >> >> 
> >> >> > call on the previous line invokes the gadget->dev.release callback, 
> >> >> > which might deallocate gadget.  If that happens, your new memset will 
> >> >> > oops.
> >> >> 
> >> >> that won't happen. struct usb_gadget is a member of the UDC's private
> >> >> structure, like this:
> >> >> 
> >> >> struct dwc3 {
> >> >> 	[...]
> >> >> 	struct usb_gadget	gadget;
> >> >> 	struct usb_gadget_driver *gadget_driver;
> >> >> 	[...]
> >> >> };
> >> >
> >> > Yes.  So what?  Can't the UDC driver use the refcount inside struct 
> >> > usb_gadget to control the lifetime of its private structure?
> >> 
> >> nope, not being used. At least not yet.
> >
> > I'm not convinced (yet)...
> >
> >> > (By the way, can you tell what's going on in net2280.c?  I must be
> >> > missing something; it looks like gadget_release() would quickly run
> >> > into problems because it calls dev_get_drvdata() for &gadget->dev, but
> >> > net2280_probe() never calls dev_set_drvdata() for that device.  
> >> > Furthermore, net2280_remove() continues to reference the net2280 struct
> >> > after calling usb_del_gadget_udc(), and it never does seem to do a
> >> > final put.)
> >> 
> >> static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> >> {
> >> 	struct net2280		*dev;
> >> 	unsigned long		resource, len;
> >> 	void			__iomem *base = NULL;
> >> 	int			retval, i;
> >> 
> >> 	/* alloc, and start init */
> >> 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> >> 	if (dev == NULL) {
> >> 		retval = -ENOMEM;
> >> 		goto done;
> >> 	}
> >> 
> >> 	pci_set_drvdata(pdev, dev);
> >> 	^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >
> > That sets the driver data in the struct pci_dev, not in
> > dev->gadget.dev.  As far as I can see, _nothing_ in the driver sets the 
> > driver data in dev->gadget.dev.
> 
> hmmm, indeed. The same is happening with other callers of
> usb_add_gadget_udc_release().
> 
> I guess this should be enough?
> 
> @@ -3557,7 +3557,7 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
>  
>  static void gadget_release(struct device *_dev)
>  {
> -	struct net2280	*dev = dev_get_drvdata(_dev);
> +	struct net2280	*dev = dev_get_drvdata(_dev->parent);
>  
>  	kfree(dev);
>  }

Oddly enough, yes.  But it doesn't explain why this code doesn't blow 
up every time it gets called, in its current form.

And it doesn't help with the fact that net2280_remove() continues to 
access the private data structure after calling usb_del_gadget_udc().  
Strictly speaking, that routine should do

	get_device(&dev->gadget.dev);

at the start, with a corresponding put_device() at the end.

There's another problem.  Suppose a call to 
usb_add_gadget_udc_release() fails.  At the end of that routine, the 
error pathway does put_device(&gadget->dev).  This will invoke the 
release callback, deallocating the private data structure without 
giving the caller (i.e., the UDC driver) a chance to clean up.

Alan Stern

[toc] | [prev] | [next] | [standalone]


#1620985 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromFelipe Balbi <balbi@kernel.org>
Date2017-04-11 09:40 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tuYz8-3XH-27@gated-at.bofh.it>
In reply to#1620017

[Multipart message — attachments visible in raw view] — view raw

Hi,

Alan Stern <stern@rowland.harvard.edu> writes:
>> >> >> >> --- a/drivers/usb/gadget/udc/core.c
>> >> >> >> +++ b/drivers/usb/gadget/udc/core.c
>> >> >> >> @@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
>> >> >> >>  	flush_work(&gadget->work);
>> >> >> >>  	device_unregister(&udc->dev);
>> >> >> >>  	device_unregister(&gadget->dev);
>> >> >> >> +	memset(&gadget->dev, 0x00, sizeof(gadget->dev));
>> >> >> >>  }
>> >> >> >>  EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
>> >> >> >
>> >> >> > Isn't this dangerous?  It's quite possible that the device_unregister() 
>> >> >> 
>> >> >> not on the gadget API, no.
>> >> >> 
>> >> >> > call on the previous line invokes the gadget->dev.release callback, 
>> >> >> > which might deallocate gadget.  If that happens, your new memset will 
>> >> >> > oops.
>> >> >> 
>> >> >> that won't happen. struct usb_gadget is a member of the UDC's private
>> >> >> structure, like this:
>> >> >> 
>> >> >> struct dwc3 {
>> >> >> 	[...]
>> >> >> 	struct usb_gadget	gadget;
>> >> >> 	struct usb_gadget_driver *gadget_driver;
>> >> >> 	[...]
>> >> >> };
>> >> >
>> >> > Yes.  So what?  Can't the UDC driver use the refcount inside struct 
>> >> > usb_gadget to control the lifetime of its private structure?
>> >> 
>> >> nope, not being used. At least not yet.
>> >
>> > I'm not convinced (yet)...
>> >
>> >> > (By the way, can you tell what's going on in net2280.c?  I must be
>> >> > missing something; it looks like gadget_release() would quickly run
>> >> > into problems because it calls dev_get_drvdata() for &gadget->dev, but
>> >> > net2280_probe() never calls dev_set_drvdata() for that device.  
>> >> > Furthermore, net2280_remove() continues to reference the net2280 struct
>> >> > after calling usb_del_gadget_udc(), and it never does seem to do a
>> >> > final put.)
>> >> 
>> >> static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>> >> {
>> >> 	struct net2280		*dev;
>> >> 	unsigned long		resource, len;
>> >> 	void			__iomem *base = NULL;
>> >> 	int			retval, i;
>> >> 
>> >> 	/* alloc, and start init */
>> >> 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
>> >> 	if (dev == NULL) {
>> >> 		retval = -ENOMEM;
>> >> 		goto done;
>> >> 	}
>> >> 
>> >> 	pci_set_drvdata(pdev, dev);
>> >> 	^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> >
>> > That sets the driver data in the struct pci_dev, not in
>> > dev->gadget.dev.  As far as I can see, _nothing_ in the driver sets the 
>> > driver data in dev->gadget.dev.
>> 
>> hmmm, indeed. The same is happening with other callers of
>> usb_add_gadget_udc_release().
>> 
>> I guess this should be enough?
>> 
>> @@ -3557,7 +3557,7 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
>>  
>>  static void gadget_release(struct device *_dev)
>>  {
>> -	struct net2280	*dev = dev_get_drvdata(_dev);
>> +	struct net2280	*dev = dev_get_drvdata(_dev->parent);
>>  
>>  	kfree(dev);
>>  }
>
> Oddly enough, yes.  But it doesn't explain why this code doesn't blow 
> up every time it gets called, in its current form.

Well, it does :-)

dev_get_drvdata(_dev) -> NULL -> kfree(NULL)

We're just leaking memory. I guess a patch like below would be best:

diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index 3828c2ec8623..4dc04253da61 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -3555,13 +3555,6 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
 
 /*-------------------------------------------------------------------------*/
 
-static void gadget_release(struct device *_dev)
-{
-	struct net2280	*dev = dev_get_drvdata(_dev);
-
-	kfree(dev);
-}
-
 /* tear down the binding between this driver and the pci device */
 
 static void net2280_remove(struct pci_dev *pdev)
@@ -3598,6 +3591,8 @@ static void net2280_remove(struct pci_dev *pdev)
 	device_remove_file(&pdev->dev, &dev_attr_registers);
 
 	ep_info(dev, "unbind\n");
+
+	kfree(dev);
 }
 
 /* wrap this driver around the specified device, but
@@ -3775,8 +3770,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (retval)
 		goto done;
 
-	retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
-			gadget_release);
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
 	if (retval)
 		goto done;
 	return 0;

> And it doesn't help with the fact that net2280_remove() continues to 
> access the private data structure after calling usb_del_gadget_udc().  
> Strictly speaking, that routine should do
>
> 	get_device(&dev->gadget.dev);
>
> at the start, with a corresponding put_device() at the end.
>
> There's another problem.  Suppose a call to 
> usb_add_gadget_udc_release() fails.  At the end of that routine, the 
> error pathway does put_device(&gadget->dev).  This will invoke the 
> release callback, deallocating the private data structure without 
> giving the caller (i.e., the UDC driver) a chance to clean up.

it won't deallocate anything :-) dev_set_drvdata() was never called,
we will endup with kfree(NULL) which is safe and just silently returns.

-- 
balbi

[toc] | [prev] | [next] | [standalone]


#1621335 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromAlan Stern <stern@rowland.harvard.edu>
Date2017-04-11 16:20 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tv4Oe-85I-25@gated-at.bofh.it>
In reply to#1620985
On Tue, 11 Apr 2017, Felipe Balbi wrote:

> > Oddly enough, yes.  But it doesn't explain why this code doesn't blow 
> > up every time it gets called, in its current form.
> 
> Well, it does :-)
> 
> dev_get_drvdata(_dev) -> NULL -> kfree(NULL)
> 
> We're just leaking memory. I guess a patch like below would be best:
> 
> diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
> index 3828c2ec8623..4dc04253da61 100644
> --- a/drivers/usb/gadget/udc/net2280.c
> +++ b/drivers/usb/gadget/udc/net2280.c
> @@ -3555,13 +3555,6 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
>  
>  /*-------------------------------------------------------------------------*/
>  
> -static void gadget_release(struct device *_dev)
> -{
> -	struct net2280	*dev = dev_get_drvdata(_dev);
> -
> -	kfree(dev);
> -}
> -
>  /* tear down the binding between this driver and the pci device */
>  
>  static void net2280_remove(struct pci_dev *pdev)
> @@ -3598,6 +3591,8 @@ static void net2280_remove(struct pci_dev *pdev)
>  	device_remove_file(&pdev->dev, &dev_attr_registers);
>  
>  	ep_info(dev, "unbind\n");
> +
> +	kfree(dev);
>  }
>  
>  /* wrap this driver around the specified device, but
> @@ -3775,8 +3770,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	if (retval)
>  		goto done;
>  
> -	retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
> -			gadget_release);
> +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
>  	if (retval)
>  		goto done;
>  	return 0;

Maybe...  But I can't shake the feeling that Greg KH would strongly 
disagree.  Hasn't he said, many times in the past, that any dynamically 
allocated device structure _must_ have a real release routine?  
usb_udc_nop_release() doesn't qualify.

The issue is outstanding references to gadget.dev.  The driver core
does not guarantee that all references will have been dropped by the
time device_unregister() returns.  So what if some other part of the
kernel still has a reference to gadget.dev when we reach the end of
net2280_remove() and deallocate the private structure?

Unless you can be certain that there are no outstanding references when
the gadget is unregistered, this approach isn't safe.  (And even if you
can be certain, how can you know that future changes to the kernel
won't affect the situation?)

> > And it doesn't help with the fact that net2280_remove() continues to 
> > access the private data structure after calling usb_del_gadget_udc().  
> > Strictly speaking, that routine should do
> >
> > 	get_device(&dev->gadget.dev);
> >
> > at the start, with a corresponding put_device() at the end.
> >
> > There's another problem.  Suppose a call to 
> > usb_add_gadget_udc_release() fails.  At the end of that routine, the 
> > error pathway does put_device(&gadget->dev).  This will invoke the 
> > release callback, deallocating the private data structure without 
> > giving the caller (i.e., the UDC driver) a chance to clean up.
> 
> it won't deallocate anything :-) dev_set_drvdata() was never called,
> we will endup with kfree(NULL) which is safe and just silently returns.

But if you change gadget_release() to use the parent's drvdata field, 
like you proposed earlier, and fix up the refcounting in 
net2280_remove() so that the structure doesn't get deallocated too 
quickly, then this does become a real problem.

And it can affect other UDC drivers, not just net2280.

Alan Stern

[toc] | [prev] | [next] | [standalone]


#1621339 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromGreg KH <greg@kroah.com>
Date2017-04-11 16:20 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tv4Of-85I-37@gated-at.bofh.it>
In reply to#1621335
On Tue, Apr 11, 2017 at 10:12:01AM -0400, Alan Stern wrote:
> On Tue, 11 Apr 2017, Felipe Balbi wrote:
> 
> > > Oddly enough, yes.  But it doesn't explain why this code doesn't blow 
> > > up every time it gets called, in its current form.
> > 
> > Well, it does :-)
> > 
> > dev_get_drvdata(_dev) -> NULL -> kfree(NULL)
> > 
> > We're just leaking memory. I guess a patch like below would be best:
> > 
> > diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
> > index 3828c2ec8623..4dc04253da61 100644
> > --- a/drivers/usb/gadget/udc/net2280.c
> > +++ b/drivers/usb/gadget/udc/net2280.c
> > @@ -3555,13 +3555,6 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
> >  
> >  /*-------------------------------------------------------------------------*/
> >  
> > -static void gadget_release(struct device *_dev)
> > -{
> > -	struct net2280	*dev = dev_get_drvdata(_dev);
> > -
> > -	kfree(dev);
> > -}
> > -
> >  /* tear down the binding between this driver and the pci device */
> >  
> >  static void net2280_remove(struct pci_dev *pdev)
> > @@ -3598,6 +3591,8 @@ static void net2280_remove(struct pci_dev *pdev)
> >  	device_remove_file(&pdev->dev, &dev_attr_registers);
> >  
> >  	ep_info(dev, "unbind\n");
> > +
> > +	kfree(dev);
> >  }
> >  
> >  /* wrap this driver around the specified device, but
> > @@ -3775,8 +3770,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> >  	if (retval)
> >  		goto done;
> >  
> > -	retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
> > -			gadget_release);
> > +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
> >  	if (retval)
> >  		goto done;
> >  	return 0;
> 
> Maybe...  But I can't shake the feeling that Greg KH would strongly 
> disagree.  Hasn't he said, many times in the past, that any dynamically 
> allocated device structure _must_ have a real release routine?  
> usb_udc_nop_release() doesn't qualify.

Aw, I wanted to publically yell at someone like the kernel documentation
says I am allowed to do so if anyone does such a foolish thing :)

[toc] | [prev] | [next] | [standalone]


#1621824 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromFelipe Balbi <balbi@kernel.org>
Date2017-04-12 08:10 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tvjDz-Xu-1@gated-at.bofh.it>
In reply to#1621339

[Multipart message — attachments visible in raw view] — view raw

Hi,

Greg KH <greg@kroah.com> writes:
> On Tue, Apr 11, 2017 at 10:12:01AM -0400, Alan Stern wrote:
>> On Tue, 11 Apr 2017, Felipe Balbi wrote:
>> 
>> > > Oddly enough, yes.  But it doesn't explain why this code doesn't blow 
>> > > up every time it gets called, in its current form.
>> > 
>> > Well, it does :-)
>> > 
>> > dev_get_drvdata(_dev) -> NULL -> kfree(NULL)
>> > 
>> > We're just leaking memory. I guess a patch like below would be best:
>> > 
>> > diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
>> > index 3828c2ec8623..4dc04253da61 100644
>> > --- a/drivers/usb/gadget/udc/net2280.c
>> > +++ b/drivers/usb/gadget/udc/net2280.c
>> > @@ -3555,13 +3555,6 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
>> >  
>> >  /*-------------------------------------------------------------------------*/
>> >  
>> > -static void gadget_release(struct device *_dev)
>> > -{
>> > -	struct net2280	*dev = dev_get_drvdata(_dev);
>> > -
>> > -	kfree(dev);
>> > -}
>> > -
>> >  /* tear down the binding between this driver and the pci device */
>> >  
>> >  static void net2280_remove(struct pci_dev *pdev)
>> > @@ -3598,6 +3591,8 @@ static void net2280_remove(struct pci_dev *pdev)
>> >  	device_remove_file(&pdev->dev, &dev_attr_registers);
>> >  
>> >  	ep_info(dev, "unbind\n");
>> > +
>> > +	kfree(dev);
>> >  }
>> >  
>> >  /* wrap this driver around the specified device, but
>> > @@ -3775,8 +3770,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>> >  	if (retval)
>> >  		goto done;
>> >  
>> > -	retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
>> > -			gadget_release);
>> > +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
>> >  	if (retval)
>> >  		goto done;
>> >  	return 0;
>> 
>> Maybe...  But I can't shake the feeling that Greg KH would strongly 
>> disagree.  Hasn't he said, many times in the past, that any dynamically 
>> allocated device structure _must_ have a real release routine?  
>> usb_udc_nop_release() doesn't qualify.
>
> Aw, I wanted to publically yell at someone like the kernel documentation
> says I am allowed to do so if anyone does such a foolish thing :)

heh, except that we're not dynamically allocating struct device at all
:-) Here's what we have for most UDCs (net2280.c included):

	struct my_udc {
        	struct gadget gadget;
                [...]
	};

	probe()
        {
        	struct my_udc *u;

		u = kzalloc(sizeof(*u), GFP_KERNEL);
                [...]
		return 0;
	}

Now, if this kzalloc() would be replaced with devm_kzalloc() wouldn't
this result on a functionally equivalent execution to the patch I
proposed above?

Iff we change struct gadget to contain a struct device *dev instead of a
struct device dev, then sure, we will need to cope with proper
->release() implementations.

As it is, it brings nothing to the table, IMO.

-- 
balbi

[toc] | [prev] | [next] | [standalone]


#1621844 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromGreg KH <greg@kroah.com>
Date2017-04-12 08:50 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tvkgi-1az-19@gated-at.bofh.it>
In reply to#1621824
On Wed, Apr 12, 2017 at 09:01:44AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Greg KH <greg@kroah.com> writes:
> > On Tue, Apr 11, 2017 at 10:12:01AM -0400, Alan Stern wrote:
> >> On Tue, 11 Apr 2017, Felipe Balbi wrote:
> >> 
> >> > > Oddly enough, yes.  But it doesn't explain why this code doesn't blow 
> >> > > up every time it gets called, in its current form.
> >> > 
> >> > Well, it does :-)
> >> > 
> >> > dev_get_drvdata(_dev) -> NULL -> kfree(NULL)
> >> > 
> >> > We're just leaking memory. I guess a patch like below would be best:
> >> > 
> >> > diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
> >> > index 3828c2ec8623..4dc04253da61 100644
> >> > --- a/drivers/usb/gadget/udc/net2280.c
> >> > +++ b/drivers/usb/gadget/udc/net2280.c
> >> > @@ -3555,13 +3555,6 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
> >> >  
> >> >  /*-------------------------------------------------------------------------*/
> >> >  
> >> > -static void gadget_release(struct device *_dev)
> >> > -{
> >> > -	struct net2280	*dev = dev_get_drvdata(_dev);
> >> > -
> >> > -	kfree(dev);
> >> > -}
> >> > -
> >> >  /* tear down the binding between this driver and the pci device */
> >> >  
> >> >  static void net2280_remove(struct pci_dev *pdev)
> >> > @@ -3598,6 +3591,8 @@ static void net2280_remove(struct pci_dev *pdev)
> >> >  	device_remove_file(&pdev->dev, &dev_attr_registers);
> >> >  
> >> >  	ep_info(dev, "unbind\n");
> >> > +
> >> > +	kfree(dev);
> >> >  }
> >> >  
> >> >  /* wrap this driver around the specified device, but
> >> > @@ -3775,8 +3770,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> >> >  	if (retval)
> >> >  		goto done;
> >> >  
> >> > -	retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
> >> > -			gadget_release);
> >> > +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
> >> >  	if (retval)
> >> >  		goto done;
> >> >  	return 0;
> >> 
> >> Maybe...  But I can't shake the feeling that Greg KH would strongly 
> >> disagree.  Hasn't he said, many times in the past, that any dynamically 
> >> allocated device structure _must_ have a real release routine?  
> >> usb_udc_nop_release() doesn't qualify.
> >
> > Aw, I wanted to publically yell at someone like the kernel documentation
> > says I am allowed to do so if anyone does such a foolish thing :)
> 
> heh, except that we're not dynamically allocating struct device at all
> :-)

Please don't say that, that's even worse :(

> Here's what we have for most UDCs (net2280.c included):
> 
> 	struct my_udc {
>         	struct gadget gadget;
>                 [...]
> 	};
> 
> 	probe()
>         {
>         	struct my_udc *u;
> 
> 		u = kzalloc(sizeof(*u), GFP_KERNEL);
>                 [...]
> 		return 0;
> 	}
> 
> Now, if this kzalloc() would be replaced with devm_kzalloc() wouldn't
> this result on a functionally equivalent execution to the patch I
> proposed above?
> 
> Iff we change struct gadget to contain a struct device *dev instead of a
> struct device dev, then sure, we will need to cope with proper
> ->release() implementations.
> 
> As it is, it brings nothing to the table, IMO.

You always have to have a release function for a kobject, no matter
where it is, as it is being reference counted.  To not do so, is a huge
indication of a problem in the design.

thanks,

greg k-h

[toc] | [prev] | [next] | [standalone]


#1621878 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromFelipe Balbi <balbi@kernel.org>
Date2017-04-12 09:40 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tvl2F-1FX-3@gated-at.bofh.it>
In reply to#1621844

[Multipart message — attachments visible in raw view] — view raw

Hi,

Greg KH <greg@kroah.com> writes:
>> Here's what we have for most UDCs (net2280.c included):
>> 
>> 	struct my_udc {
>>         	struct gadget gadget;
>>                 [...]
>> 	};
>> 
>> 	probe()
>>         {
>>         	struct my_udc *u;
>> 
>> 		u = kzalloc(sizeof(*u), GFP_KERNEL);
>>                 [...]
>> 		return 0;
>> 	}
>> 
>> Now, if this kzalloc() would be replaced with devm_kzalloc() wouldn't
>> this result on a functionally equivalent execution to the patch I
>> proposed above?
>> 
>> Iff we change struct gadget to contain a struct device *dev instead of a
>> struct device dev, then sure, we will need to cope with proper
>> ->release() implementations.
>> 
>> As it is, it brings nothing to the table, IMO.
>
> You always have to have a release function for a kobject, no matter
> where it is, as it is being reference counted.  To not do so, is a huge
> indication of a problem in the design.

okay, this goes all the way back to when Dave B wrote the API, it has
always had empty ->release() functions (not all UDCs, though). I'll make
sure to review all of this for v4.13.

-- 
balbi

[toc] | [prev] | [next] | [standalone]


#1622183 — Re: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device

FromAlan Stern <stern@rowland.harvard.edu>
Date2017-04-12 16:40 +0200
SubjectRe: [PATCH v3 1/3] usb: udc: allow adding and removing the same gadget device
Message-ID<tvrB8-5Bn-9@gated-at.bofh.it>
In reply to#1621824
On Wed, 12 Apr 2017, Felipe Balbi wrote:

> >> Maybe...  But I can't shake the feeling that Greg KH would strongly 
> >> disagree.  Hasn't he said, many times in the past, that any dynamically 
> >> allocated device structure _must_ have a real release routine?  
> >> usb_udc_nop_release() doesn't qualify.
> >
> > Aw, I wanted to publically yell at someone like the kernel documentation
> > says I am allowed to do so if anyone does such a foolish thing :)
> 
> heh, except that we're not dynamically allocating struct device at all
> :-) Here's what we have for most UDCs (net2280.c included):
> 
> 	struct my_udc {
>         	struct gadget gadget;
>                 [...]
> 	};
> 
> 	probe()
>         {
>         	struct my_udc *u;
> 
> 		u = kzalloc(sizeof(*u), GFP_KERNEL);
>                 [...]
> 		return 0;
> 	}

Allow me to point out that the struct device is embedded inside the
struct gadget (actually struct usb_gadget) embedded inside the struct
my_udc, which _is_ dynamically allocated.  Therefore the struct device
is located in dynamically allocated memory.

> Now, if this kzalloc() would be replaced with devm_kzalloc() wouldn't
> this result on a functionally equivalent execution to the patch I
> proposed above?

It would, and it would be equally wrong.

Alan Stern

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web