Re: [PATCH 1/2] usb: dwc3: gadget: set xfer resource per endpoint

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



hi,

Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx> writes:
>> This reverts back to the original buggy behavior. This will fail when
>> a SET_INTERFACE occurs multiple times.
>>
>> You can run testusb to see the failure:
>> testusb -t 9 -c 5000 -s 2048 -a
>
> I came up with something else for this. It's still unstable and I need
> to debug further to figure out where we're wrong. But it seems to me
> that we're following databook down to the last comma with patch
> below. Note that we're partially reverting your original changes and
> adding some extra knowledge about current configuration and interface,
> then we only reassign transfer resources if those change. Care to have a
> look?

here's a version that passes testusb and normal enumeration with g_zero
and g_mass_storage. After some experimenting, it seems like we should
always MODIFY resource allocation, unless we're doing a SetConfiguration
to the same configuration that is already chosen or a SetInterface to
the same interface/alt-setting pair that's already being used. This is
working for me. Can you test on your end too?

8<---------------------------------------------------------------------
From 327475d7f63aa161bdc3bf7f9d693d9aafcd4518 Mon Sep 17 00:00:00 2001
From: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx>
Date: Thu, 2 Jun 2016 12:47:13 +0300
Subject: [PATCH] usb: dwc3: gadget: fix endpoint resource allocation

There were still corner cases which current code
wouldn't cover. This new commit tries to cover them
all by partially reverting commit c450960187f4
("usb: dwc3: Fix assignment of EP transfer
resources") and implementing a new way which follows
Synopsys Databook correctly.

Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx>
---
 drivers/usb/dwc3/core.h   |  8 +++++
 drivers/usb/dwc3/ep0.c    | 41 ++++++++++++++++++++++-
 drivers/usb/dwc3/gadget.c | 84 ++++++++++++++++++-----------------------------
 3 files changed, 80 insertions(+), 53 deletions(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4a5453c36099..8fb6361d719d 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -768,6 +768,9 @@ struct dwc3_scratchpad_array {
  * @test_mode_nr: test feature selector
  * @lpm_nyet_threshold: LPM NYET response threshold
  * @hird_threshold: HIRD threshold
+ * @current_configuration: current configuration number
+ * @current_alt_setting: current alternate setting
+ * @current_interface: current interface number
  * @hsphy_interface: "utmi" or "ulpi"
  * @connected: true when we're connected to a host, false otherwise
  * @delayed_status: true when gadget driver asks for delayed status
@@ -913,6 +916,10 @@ struct dwc3 {
 	u8			lpm_nyet_threshold;
 	u8			hird_threshold;
 
+	u16			current_configuration;
+	u16			current_alt_setting;
+	u16			current_interface;
+
 	const char		*hsphy_interface;
 
 	unsigned		connected:1;
@@ -926,6 +933,7 @@ struct dwc3 {
 	unsigned		pending_events:1;
 	unsigned		pullups_connected:1;
 	unsigned		setup_packet_pending:1;
+	unsigned		start_config_issued:1;
 	unsigned		three_stage_setup:1;
 	unsigned		usb3_lpm_capable:1;
 
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index fe79d771dee4..ff07122db8d3 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -576,6 +576,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 		/* if the cfg matches and the cfg is non zero */
 		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
 
+			if (dwc->current_configuration != cfg)
+				dwc->start_config_issued = false;
+			dwc->current_configuration = cfg;
+
 			/*
 			 * only change state if set_config has already
 			 * been processed. If gadget driver returns
@@ -598,9 +602,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 
 	case USB_STATE_CONFIGURED:
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
-		if (!cfg && !ret)
+		if (!cfg && !ret) {
 			usb_gadget_set_state(&dwc->gadget,
 					USB_STATE_ADDRESS);
+			dwc->current_configuration = 0;
+		}
 		break;
 	default:
 		ret = -EINVAL;
@@ -710,6 +716,35 @@ static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ct
 	return 0;
 }
 
+static int dwc3_ep0_set_interface(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl)
+{
+	int ret;
+	u16 intf;
+	u16 alt;
+
+	intf = le16_to_cpu(ctrl->wIndex);
+	alt = le16_to_cpu(ctrl->wValue);
+
+	ret = dwc3_ep0_delegate_req(dwc, ctrl);
+	if (ret == 0) {
+		u16 curr;
+
+		curr  = dwc->current_interface;
+		if (curr != intf)
+			dwc->start_config_issued = false;
+
+		curr = dwc->current_alt_setting;
+		if (curr != alt)
+			dwc->start_config_issued = false;
+
+		dwc->current_interface = intf;
+		dwc->current_alt_setting = alt;
+	}
+
+	return ret;
+}
+
 static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
 	int ret;
@@ -743,6 +778,10 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 		dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
 		ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
 		break;
+	case USB_REQ_SET_INTERFACE:
+		dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE");
+		ret = dwc3_ep0_set_interface(dwc, ctrl);
+		break;
 	default:
 		dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 32f97c73499c..866470f7207f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -372,66 +372,23 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep)
 	dep->trb_pool_dma = 0;
 }
 
-static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep);
-
-/**
- * dwc3_gadget_start_config - Configure EP resources
- * @dwc: pointer to our controller context structure
- * @dep: endpoint that is being enabled
- *
- * The assignment of transfer resources cannot perfectly follow the
- * data book due to the fact that the controller driver does not have
- * all knowledge of the configuration in advance. It is given this
- * information piecemeal by the composite gadget framework after every
- * SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook
- * programming model in this scenario can cause errors. For two
- * reasons:
- *
- * 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION
- * and SET_INTERFACE (8.1.5). This is incorrect in the scenario of
- * multiple interfaces.
- *
- * 2) The databook does not mention doing more DEPXFERCFG for new
- * endpoint on alt setting (8.1.6).
- *
- * The following simplified method is used instead:
- *
- * All hardware endpoints can be assigned a transfer resource and this
- * setting will stay persistent until either a core reset or
- * hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and
- * do DEPXFERCFG for every hardware endpoint as well. We are
- * guaranteed that there are as many transfer resources as endpoints.
- *
- * This function is called for each endpoint when it is being enabled
- * but is triggered only when called for EP0-out, which always happens
- * first, and which should only happen in one of the above conditions.
- */
 static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
 	struct dwc3_gadget_ep_cmd_params params;
 	u32			cmd;
-	int			i;
-	int			ret;
-
-	if (dep->number)
-		return 0;
 
 	memset(&params, 0x00, sizeof(params));
-	cmd = DWC3_DEPCMD_DEPSTARTCFG;
 
-	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
-		struct dwc3_ep *dep = dwc->eps[i];
-
-		if (!dep)
-			continue;
+	if (dep->number != 1) {
+		cmd = DWC3_DEPCMD_DEPSTARTCFG;
+		/* XferRscIdx == 0 for ep0 and 2 for the remaining */
+		if (dwc->start_config_issued)
+			return 0;
+		dwc->start_config_issued = true;
+		if (dep->number > 1)
+			cmd |= DWC3_DEPCMD_PARAM(2);
 
-		ret = dwc3_gadget_set_xfer_resource(dwc, dep);
-		if (ret)
-			return ret;
+		return dwc3_send_gadget_ep_cmd(dep, cmd, &params);
 	}
 
 	return 0;
@@ -517,6 +474,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
 			&params);
 }
 
+static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc;
+
 /**
  * __dwc3_gadget_ep_enable - Initializes a HW endpoint
  * @dep: endpoint to be initialized
@@ -536,6 +495,19 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 	dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
 
 	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		if (dep->number == 1 && !dwc->start_config_issued) {
+			/*
+			 * According to section 8.1.5 of the databook,
+			 * we must first issue a DEPCFG command to EP1
+			 * with action set to modify
+			 */
+			ret = dwc3_gadget_set_ep_config(dwc, dep,
+					&dwc3_gadget_ep0_desc, NULL, true,
+					false);
+			if (ret)
+				return ret;
+		}
+
 		ret = dwc3_gadget_start_config(dwc, dep);
 		if (ret)
 			return ret;
@@ -550,6 +522,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 		struct dwc3_trb	*trb_st_hw;
 		struct dwc3_trb	*trb_link;
 
+		ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+		if (ret)
+			return ret;
+
 		dep->endpoint.desc = desc;
 		dep->comp_desc = comp_desc;
 		dep->type = usb_endpoint_type(desc);
@@ -1718,6 +1694,8 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
 
 	dwc3_gadget_setup_nump(dwc);
 
+	dwc->start_config_issued = false;
+
 	/* Start with SuperSpeed Default */
 	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
@@ -2373,6 +2351,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
 	dwc3_disconnect_gadget(dwc);
+	dwc->start_config_issued = false;
 
 	dwc->gadget.speed = USB_SPEED_UNKNOWN;
 	dwc->setup_packet_pending = false;
@@ -2420,6 +2399,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 
 	dwc3_stop_active_transfers(dwc);
 	dwc3_clear_stall_all_ep(dwc);
+	dwc->start_config_issued = false;
 
 	dwc3_reset_gadget(dwc);
 
-- 
2.8.3



-- 
balbi

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux