mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 19:36:35 +08:00
Fix some NAK race conditions in control transfers (there are more)
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5058 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
@@ -3192,4 +3192,12 @@
|
|||||||
* arch/arm/src/lpc17xx/lpc17_ethernet.c: Conditionally elide setting PHY
|
* arch/arm/src/lpc17xx/lpc17_ethernet.c: Conditionally elide setting PHY
|
||||||
speed/duplex. This does not work for certain PHYs. Still some unresolved
|
speed/duplex. This does not work for certain PHYs. Still some unresolved
|
||||||
issues (also from Kate).
|
issues (also from Kate).
|
||||||
|
* tools/Config.mk, Makefile, configs/*/Make.defs: Add a new Makefile
|
||||||
|
fragement to de-quoate certain strings from the Kconfig logic that
|
||||||
|
need to be used at path segments (Richard Cochran).
|
||||||
|
* arch/arm/src/stm32/stm32_usbotghost.c: The STM32 USB host driver only
|
||||||
|
works with debug turned on. The problem appears to be that with debug
|
||||||
|
OFF, there are more NAKs occuring in more places than before and this
|
||||||
|
reveals a variety of errors. This check in improves NAK robustness
|
||||||
|
for control transfers but does not resolve all of the issues.
|
||||||
|
|
||||||
|
|||||||
@@ -141,14 +141,15 @@
|
|||||||
#define STM32_EP0_MAX_PACKET_SIZE 64 /* EP0 FS max packet size */
|
#define STM32_EP0_MAX_PACKET_SIZE 64 /* EP0 FS max packet size */
|
||||||
#define STM32_MAX_TX_FIFOS 15 /* Max number of TX FIFOs */
|
#define STM32_MAX_TX_FIFOS 15 /* Max number of TX FIFOs */
|
||||||
#define STM32_MAX_PKTCOUNT 256 /* Max packet count */
|
#define STM32_MAX_PKTCOUNT 256 /* Max packet count */
|
||||||
#define STM32_RETRY_COUNT 3 /* Number of retries */
|
#define STM32_RETRY_COUNT 3 /* Number of ctrl transfer retries */
|
||||||
#define STM32_DEF_DEVADDR 0 /* Default device address */
|
#define STM32_DEF_DEVADDR 0 /* Default device address */
|
||||||
|
|
||||||
/* Delays **********************************************************************/
|
/* Delays **********************************************************************/
|
||||||
|
|
||||||
#define STM32_READY_DELAY 200000 /* In loop counts */
|
#define STM32_READY_DELAY 200000 /* In loop counts */
|
||||||
#define STM32_FLUSH_DELAY 200000 /* In loop counts */
|
#define STM32_FLUSH_DELAY 200000 /* In loop counts */
|
||||||
#define STM32_NOTREADY_DELAY 5000 /* In frames */
|
#define STM32_SETUP_DELAY 5000 /* In frames */
|
||||||
|
#define STM32_DATANAK_DELAY 5000 /* In frames */
|
||||||
|
|
||||||
/* Ever-present MIN/MAX macros */
|
/* Ever-present MIN/MAX macros */
|
||||||
|
|
||||||
@@ -376,10 +377,11 @@ static void stm32_disconnect(FAR struct usbhost_driver_s *drvr);
|
|||||||
/* Initialization **************************************************************/
|
/* Initialization **************************************************************/
|
||||||
|
|
||||||
static void stm32_portreset(FAR struct stm32_usbhost_s *priv);
|
static void stm32_portreset(FAR struct stm32_usbhost_s *priv);
|
||||||
static inline void stm32_flush_txfifos(uint32_t txfnum);
|
static void stm32_flush_txfifos(uint32_t txfnum);
|
||||||
static inline void stm32_flush_rxfifo(void);
|
static void stm32_flush_rxfifo(void);
|
||||||
static void stm32_vbusdrive(FAR struct stm32_usbhost_s *priv, bool state);
|
static void stm32_vbusdrive(FAR struct stm32_usbhost_s *priv, bool state);
|
||||||
static void stm32_host_initialize(FAR struct stm32_usbhost_s *priv);
|
static void stm32_host_initialize(FAR struct stm32_usbhost_s *priv);
|
||||||
|
|
||||||
static inline void stm32_sw_initialize(FAR struct stm32_usbhost_s *priv);
|
static inline void stm32_sw_initialize(FAR struct stm32_usbhost_s *priv);
|
||||||
static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv);
|
static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv);
|
||||||
|
|
||||||
@@ -1196,14 +1198,15 @@ static int stm32_ctrl_sendsetup(FAR struct stm32_usbhost_s *priv,
|
|||||||
FAR const struct usb_ctrlreq_s *req)
|
FAR const struct usb_ctrlreq_s *req)
|
||||||
{
|
{
|
||||||
FAR struct stm32_chan_s *chan;
|
FAR struct stm32_chan_s *chan;
|
||||||
uint16_t start = stm32_getframe();
|
uint16_t start;
|
||||||
uint16_t elapsed;
|
uint16_t elapsed;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
chan = &priv->chan[priv->ep0out];
|
|
||||||
|
|
||||||
/* Loop while the device reports NAK (and a timeout is not exceeded */
|
/* Loop while the device reports NAK (and a timeout is not exceeded */
|
||||||
|
|
||||||
|
chan = &priv->chan[priv->ep0out];
|
||||||
|
start = stm32_getframe();
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
/* Send the SETUP packet */
|
/* Send the SETUP packet */
|
||||||
@@ -1248,11 +1251,11 @@ static int stm32_ctrl_sendsetup(FAR struct stm32_usbhost_s *priv,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the elpased time (in frames) */
|
/* Get the elapsed time (in frames) */
|
||||||
|
|
||||||
elapsed = stm32_getframe() - start;
|
elapsed = stm32_getframe() - start;
|
||||||
}
|
}
|
||||||
while (elapsed < STM32_NOTREADY_DELAY);
|
while (elapsed < STM32_SETUP_DELAY);
|
||||||
|
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
@@ -3284,6 +3287,8 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr,
|
|||||||
{
|
{
|
||||||
struct stm32_usbhost_s *priv = (struct stm32_usbhost_s *)drvr;
|
struct stm32_usbhost_s *priv = (struct stm32_usbhost_s *)drvr;
|
||||||
uint16_t buflen;
|
uint16_t buflen;
|
||||||
|
uint16_t start;
|
||||||
|
uint16_t elapsed;
|
||||||
int retries;
|
int retries;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -3300,7 +3305,7 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr,
|
|||||||
|
|
||||||
stm32_takesem(&priv->exclsem);
|
stm32_takesem(&priv->exclsem);
|
||||||
|
|
||||||
/* Loop, retrying until the retry count expires */
|
/* Loop, retrying until the retry time expires */
|
||||||
|
|
||||||
for (retries = 0; retries < STM32_RETRY_COUNT; retries++)
|
for (retries = 0; retries < STM32_RETRY_COUNT; retries++)
|
||||||
{
|
{
|
||||||
@@ -3308,38 +3313,55 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr,
|
|||||||
|
|
||||||
ret = stm32_ctrl_sendsetup(priv, req);
|
ret = stm32_ctrl_sendsetup(priv, req);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
udbg("stm32_ctrl_sendsetup failed: %d\n", ret);
|
udbg("stm32_ctrl_sendsetup failed: %d\n", ret);
|
||||||
return ret;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the IN data phase (if any) */
|
/* Get the start time. Loop again until the timeout expires */
|
||||||
|
|
||||||
if (buflen > 0)
|
start = stm32_getframe();
|
||||||
|
do
|
||||||
{
|
{
|
||||||
ret = stm32_ctrl_recvdata(priv, buffer, buflen);
|
/* Handle the IN data phase (if any) */
|
||||||
if (ret < 0)
|
|
||||||
|
if (buflen > 0)
|
||||||
{
|
{
|
||||||
udbg("stm32_ctrl_recvdata failed: %d\n", ret);
|
ret = stm32_ctrl_recvdata(priv, buffer, buflen);
|
||||||
continue;
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
udbg("stm32_ctrl_recvdata failed: %d\n", ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle the status OUT phase */
|
||||||
|
|
||||||
|
if (ret == OK)
|
||||||
|
{
|
||||||
|
priv->chan[priv->ep0out].outdata1 ^= true;
|
||||||
|
ret = stm32_ctrl_senddata(priv, NULL, 0);
|
||||||
|
if (ret == OK)
|
||||||
|
{
|
||||||
|
/* All success transactions exit here */
|
||||||
|
|
||||||
|
stm32_givesem(&priv->exclsem);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
udbg("stm32_ctrl_senddata failed: %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the elapsed time (in frames) */
|
||||||
|
|
||||||
|
elapsed = stm32_getframe() - start;
|
||||||
}
|
}
|
||||||
|
while (elapsed < STM32_DATANAK_DELAY);
|
||||||
/* Handle the status OUT phase */
|
|
||||||
|
|
||||||
priv->chan[priv->ep0out].outdata1 ^= true;
|
|
||||||
ret = stm32_ctrl_senddata(priv, NULL, 0);
|
|
||||||
if (ret == OK)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
udbg("stm32_ctrl_senddata failed: %d\n", ret);
|
|
||||||
ret = -ETIMEDOUT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* All failures exit here after all retries and timeouts have been exhausted */
|
||||||
|
|
||||||
stm32_givesem(&priv->exclsem);
|
stm32_givesem(&priv->exclsem);
|
||||||
return ret;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr,
|
static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr,
|
||||||
@@ -3348,6 +3370,8 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr,
|
|||||||
{
|
{
|
||||||
struct stm32_usbhost_s *priv = (struct stm32_usbhost_s *)drvr;
|
struct stm32_usbhost_s *priv = (struct stm32_usbhost_s *)drvr;
|
||||||
uint16_t buflen;
|
uint16_t buflen;
|
||||||
|
uint16_t start;
|
||||||
|
uint16_t elapsed;
|
||||||
int retries;
|
int retries;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -3364,12 +3388,14 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr,
|
|||||||
|
|
||||||
stm32_takesem(&priv->exclsem);
|
stm32_takesem(&priv->exclsem);
|
||||||
|
|
||||||
/* Loop, retrying until the retry count expires */
|
/* Loop, retrying until the retry time expires */
|
||||||
|
|
||||||
for (retries = 0; retries < STM32_RETRY_COUNT; retries++)
|
for (retries = 0; retries < STM32_RETRY_COUNT; retries++)
|
||||||
{
|
{
|
||||||
/* Send the SETUP request */
|
/* Send the SETUP request */
|
||||||
|
|
||||||
|
/* Send the SETUP request */
|
||||||
|
|
||||||
ret = stm32_ctrl_sendsetup(priv, req);
|
ret = stm32_ctrl_sendsetup(priv, req);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
@@ -3377,35 +3403,52 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the data OUT phase (if any) */
|
/* Get the start time. Loop again until the timeout expires */
|
||||||
|
|
||||||
if (buflen > 0)
|
start = stm32_getframe();
|
||||||
|
do
|
||||||
{
|
{
|
||||||
/* Start DATA out transfer (only one DATA packet) */
|
/* Handle the data OUT phase (if any) */
|
||||||
|
|
||||||
priv->chan[priv->ep0out].outdata1 = true;
|
if (buflen > 0)
|
||||||
ret = stm32_ctrl_senddata(priv, NULL, 0);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
{
|
||||||
udbg("stm32_ctrl_senddata failed: %d\n", ret);
|
/* Start DATA out transfer (only one DATA packet) */
|
||||||
continue;
|
|
||||||
|
priv->chan[priv->ep0out].outdata1 = true;
|
||||||
|
ret = stm32_ctrl_senddata(priv, NULL, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
udbg("stm32_ctrl_senddata failed: %d\n", ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle the status IN phase */
|
/* Handle the status IN phase */
|
||||||
|
|
||||||
ret = stm32_ctrl_recvdata(priv, NULL, 0);
|
if (ret == OK)
|
||||||
if (ret == OK)
|
{
|
||||||
{
|
ret = stm32_ctrl_recvdata(priv, NULL, 0);
|
||||||
break;
|
if (ret == OK)
|
||||||
}
|
{
|
||||||
|
/* All success transactins exit here */
|
||||||
|
|
||||||
udbg("stm32_ctrl_recvdata failed: %d\n", ret);
|
stm32_givesem(&priv->exclsem);
|
||||||
ret = -ETIMEDOUT;
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
udbg("stm32_ctrl_recvdata failed: %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the elapsed time (in frames) */
|
||||||
|
|
||||||
|
elapsed = stm32_getframe() - start;
|
||||||
|
}
|
||||||
|
while (elapsed < STM32_DATANAK_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* All failures exit here after all retries and timeouts have been exhausted */
|
||||||
|
|
||||||
stm32_givesem(&priv->exclsem);
|
stm32_givesem(&priv->exclsem);
|
||||||
return ret;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@@ -3660,7 +3703,7 @@ static void stm32_portreset(FAR struct stm32_usbhost_s *priv)
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
static inline void stm32_flush_txfifos(uint32_t txfnum)
|
static void stm32_flush_txfifos(uint32_t txfnum)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
uint32_t timeout;
|
uint32_t timeout;
|
||||||
@@ -3700,7 +3743,7 @@ static inline void stm32_flush_txfifos(uint32_t txfnum)
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
static inline void stm32_flush_rxfifo(void)
|
static void stm32_flush_rxfifo(void)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
uint32_t timeout;
|
uint32_t timeout;
|
||||||
|
|||||||
Reference in New Issue
Block a user