STM32, STM32 F7, and STM32 L4: Back out part of 3331e9c49a
. Returning immediately int he case of a NAK makes the Mass Storage Class driver unreliable. The retry/timeout logic is necessary. This implementation tries to implement a compromise: If a NAK is received after some data is received, then the partial data received is returned as with 3331e9c49a
. If if a NAK is received with no data, then no longer returns the NAK error immediately but retries until data is received or a timeout occurs. Initial testing indicates that this fixes the issues the MSC. However, I hae concerns that if multiple sectors are read in one transfer, there could be NAKs between sectors as well and, in that case, then change will still cause failures.
This commit is contained in:
parent
d49ea44df2
commit
a3b4475474
@ -1827,6 +1827,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
FAR uint8_t *buffer, size_t buflen)
|
||||
{
|
||||
FAR struct stm32_chan_s *chan;
|
||||
systime_t start;
|
||||
ssize_t xfrd;
|
||||
int ret;
|
||||
|
||||
@ -1841,6 +1842,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
chan->xfrd = 0;
|
||||
xfrd = 0;
|
||||
|
||||
start = clock_systimer();
|
||||
while (chan->xfrd < chan->buflen)
|
||||
{
|
||||
/* Set up for the wait BEFORE starting the transfer */
|
||||
@ -1865,11 +1867,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
|
||||
ret = stm32_chan_wait(priv, chan);
|
||||
|
||||
/* EAGAIN indicates that the device NAKed the transfer. In the case
|
||||
* of a NAK, we do not retry but rather assume that the transfer is
|
||||
* commplete and return the data that we have received. Retry could
|
||||
* be handled in class driver.
|
||||
*/
|
||||
/* EAGAIN indicates that the device NAKed the transfer. */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
@ -1889,21 +1887,43 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No... Break out and return the NAK */
|
||||
/* Get the elapsed time. Has the timeout elapsed?
|
||||
* if not then try again.
|
||||
*/
|
||||
|
||||
return (ssize_t)ret;
|
||||
systime_t elapsed = clock_systimer() - start;
|
||||
if (elapsed >= STM32_DATANAK_DELAY)
|
||||
{
|
||||
/* Timeout out... break out returning the NAK as
|
||||
* as a failure.
|
||||
*/
|
||||
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some unexpected, fatal error occurred. */
|
||||
|
||||
usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret);
|
||||
usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret);
|
||||
|
||||
/* Break out and return the error */
|
||||
/* Break out and return the error */
|
||||
|
||||
uerr("ERROR: stm32_chan_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
uerr("ERROR: stm32_chan_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Successfully received another chunk of data... add that to the
|
||||
* runing total. Then continue reading until we read 'buflen'
|
||||
* bytes of data or until the the devices NAKs (implying a short
|
||||
* packet).
|
||||
*/
|
||||
|
||||
xfrd += chan->xfrd;
|
||||
xfrd += chan->xfrd;
|
||||
}
|
||||
}
|
||||
|
||||
return xfrd;
|
||||
|
@ -1832,6 +1832,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
FAR uint8_t *buffer, size_t buflen)
|
||||
{
|
||||
FAR struct stm32_chan_s *chan;
|
||||
systime_t start;
|
||||
ssize_t xfrd;
|
||||
int ret;
|
||||
|
||||
@ -1846,6 +1847,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
chan->xfrd = 0;
|
||||
xfrd = 0;
|
||||
|
||||
start = clock_systimer();
|
||||
while (chan->xfrd < chan->buflen)
|
||||
{
|
||||
/* Set up for the wait BEFORE starting the transfer */
|
||||
@ -1870,11 +1872,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
|
||||
ret = stm32_chan_wait(priv, chan);
|
||||
|
||||
/* EAGAIN indicates that the device NAKed the transfer. In the case
|
||||
* of a NAK, we do not retry but rather assume that the transfer is
|
||||
* commplete and return the data that we have received. Retry could
|
||||
* be handled in class driver.
|
||||
*/
|
||||
/* EAGAIN indicates that the device NAKed the transfer. */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
@ -1894,21 +1892,43 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No... Break out and return the NAK */
|
||||
/* Get the elapsed time. Has the timeout elapsed?
|
||||
* if not then try again.
|
||||
*/
|
||||
|
||||
return (ssize_t)ret;
|
||||
systime_t elapsed = clock_systimer() - start;
|
||||
if (elapsed >= STM32_DATANAK_DELAY)
|
||||
{
|
||||
/* Timeout out... break out returning the NAK as
|
||||
* as a failure.
|
||||
*/
|
||||
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some unexpected, fatal error occurred. */
|
||||
|
||||
usbhost_trace1(OTGHS_TRACE1_TRNSFRFAILED, ret);
|
||||
usbhost_trace1(OTGHS_TRACE1_TRNSFRFAILED, ret);
|
||||
|
||||
/* Break out and return the error */
|
||||
/* Break out and return the error */
|
||||
|
||||
uerr("ERROR: stm32_chan_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
uerr("ERROR: stm32_chan_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Successfully received another chunk of data... add that to the
|
||||
* runing total. Then continue reading until we read 'buflen'
|
||||
* bytes of data or until the the devices NAKs (implying a short
|
||||
* packet).
|
||||
*/
|
||||
|
||||
xfrd += chan->xfrd;
|
||||
xfrd += chan->xfrd;
|
||||
}
|
||||
}
|
||||
|
||||
return xfrd;
|
||||
|
@ -1826,6 +1826,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
FAR uint8_t *buffer, size_t buflen)
|
||||
{
|
||||
FAR struct stm32_chan_s *chan;
|
||||
systime_t start;
|
||||
ssize_t xfrd;
|
||||
int ret;
|
||||
|
||||
@ -1840,6 +1841,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
chan->xfrd = 0;
|
||||
xfrd = 0;
|
||||
|
||||
start = clock_systimer();
|
||||
while (chan->xfrd < chan->buflen)
|
||||
{
|
||||
/* Set up for the wait BEFORE starting the transfer */
|
||||
@ -1864,11 +1866,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
|
||||
ret = stm32_chan_wait(priv, chan);
|
||||
|
||||
/* EAGAIN indicates that the device NAKed the transfer. In the case
|
||||
* of a NAK, we do not retry but rather assume that the transfer is
|
||||
* commplete and return the data that we have received. Retry could
|
||||
* be handled in class driver.
|
||||
*/
|
||||
/* EAGAIN indicates that the device NAKed the transfer. */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
@ -1888,21 +1886,43 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No... Break out and return the NAK */
|
||||
/* Get the elapsed time. Has the timeout elapsed?
|
||||
* if not then try again.
|
||||
*/
|
||||
|
||||
return (ssize_t)ret;
|
||||
systime_t elapsed = clock_systimer() - start;
|
||||
if (elapsed >= STM32_DATANAK_DELAY)
|
||||
{
|
||||
/* Timeout out... break out returning the NAK as
|
||||
* as a failure.
|
||||
*/
|
||||
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some unexpected, fatal error occurred. */
|
||||
|
||||
usbhost_trace1(OTG_TRACE1_TRNSFRFAILED, ret);
|
||||
usbhost_trace1(OTG_TRACE1_TRNSFRFAILED, ret);
|
||||
|
||||
/* Break out and return the error */
|
||||
/* Break out and return the error */
|
||||
|
||||
uerr("ERROR: stm32_chan_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
uerr("ERROR: stm32_chan_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Successfully received another chunk of data... add that to the
|
||||
* runing total. Then continue reading until we read 'buflen'
|
||||
* bytes of data or until the the devices NAKs (implying a short
|
||||
* packet).
|
||||
*/
|
||||
|
||||
xfrd += chan->xfrd;
|
||||
xfrd += chan->xfrd;
|
||||
}
|
||||
}
|
||||
|
||||
return xfrd;
|
||||
|
@ -1831,6 +1831,7 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv,
|
||||
size_t buflen)
|
||||
{
|
||||
FAR struct stm32l4_chan_s *chan;
|
||||
systime_t start;
|
||||
ssize_t xfrd;
|
||||
int ret;
|
||||
|
||||
@ -1845,6 +1846,7 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv,
|
||||
chan->xfrd = 0;
|
||||
xfrd = 0;
|
||||
|
||||
start = clock_systimer();
|
||||
while (chan->xfrd < chan->buflen)
|
||||
{
|
||||
/* Set up for the wait BEFORE starting the transfer */
|
||||
@ -1869,11 +1871,7 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv,
|
||||
|
||||
ret = stm32l4_chan_wait(priv, chan);
|
||||
|
||||
/* EAGAIN indicates that the device NAKed the transfer. In the case
|
||||
* of a NAK, we do not retry but rather assume that the transfer is
|
||||
* commplete and return the data that we have received. Retry could
|
||||
* be handled in class driver.
|
||||
*/
|
||||
/* EAGAIN indicates that the device NAKed the transfer. */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
@ -1893,21 +1891,43 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No... Break out and return the NAK */
|
||||
/* Get the elapsed time. Has the timeout elapsed?
|
||||
* if not then try again.
|
||||
*/
|
||||
|
||||
return (ssize_t)ret;
|
||||
systime_t elapsed = clock_systimer() - start;
|
||||
if (elapsed >= STM32L4_DATANAK_DELAY)
|
||||
{
|
||||
/* Timeout out... break out returning the NAK as
|
||||
* as a failure.
|
||||
*/
|
||||
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some unexpected, fatal error occurred. */
|
||||
|
||||
usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret);
|
||||
usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret);
|
||||
|
||||
/* Break out and return the error */
|
||||
/* Break out and return the error */
|
||||
|
||||
uerr("ERROR: stm32l4_chan_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
uerr("ERROR: stm32l4_chan_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Successfully received another chunk of data... add that to the
|
||||
* runing total. Then continue reading until we read 'buflen'
|
||||
* bytes of data or until the the devices NAKs (implying a short
|
||||
* packet).
|
||||
*/
|
||||
|
||||
xfrd += chan->xfrd;
|
||||
xfrd += chan->xfrd;
|
||||
}
|
||||
}
|
||||
|
||||
return xfrd;
|
||||
|
@ -339,7 +339,15 @@ must be is one of the following.
|
||||
above under "OTGFS Host".
|
||||
|
||||
STATUS: I have seen this work with some FLASH sticks but not with
|
||||
others. This probably needs a little TLC to get 100% reliable.
|
||||
others. I have not studied the failure case carefully. They seem
|
||||
to fail because the request is NAKed. That is not a failure, however,
|
||||
that is normal behavior when the FLASH is not ready.
|
||||
|
||||
There have been other cases like this with the STM32 host drivers:
|
||||
in the event of NAKs, other drivers retry and wait for the data. The
|
||||
STM32 does not but returns the NAK failure immediately. My guess is
|
||||
that there needs to be be some retry logic to the driver 100%
|
||||
reliable.
|
||||
|
||||
2. Kernel Modules / Shared Libraries
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user