stm32wl5: fix unbuffered mode and other possible bugs

This patch fixes unbuffered mode so it actually works.

Also, patch contains fixes for possible bugs that could result in
deadlock or system hang in certain situations.

Signed-off-by: Michał Łyszczek <michal.lyszczek@bofc.pl>
This commit is contained in:
Michał Łyszczek
2022-08-03 14:57:50 +02:00
committed by Xiang Xiao
parent 3e43128f07
commit 4e967c67b4
5 changed files with 101 additions and 33 deletions
+3
View File
@@ -132,6 +132,8 @@ int ipcc_poll(FAR struct file *filep, FAR struct pollfd *fds,
/* Should immediately notify on any of the requested events? */
eventset = 0;
#ifdef CONFIG_IPCC_BUFFERED
if (circbuf_used(&priv->ipcc->rxbuf) > 0)
{
eventset |= (fds->events & POLLIN);
@@ -141,6 +143,7 @@ int ipcc_poll(FAR struct file *filep, FAR struct pollfd *fds,
{
eventset |= (fds->events & POLLOUT);
}
#endif
if (eventset)
{
+30 -3
View File
@@ -122,6 +122,7 @@ ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
FAR struct ipcc_driver_s *priv;
ssize_t nread;
int ret;
int flags;
/* Get our private data structure */
@@ -141,11 +142,33 @@ ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
for (; ; )
{
/* Disable interrupts, or we might get in situation when we:
* - read 0 bytes from circbuf
* - interrupt comes in
* - it copies data to buffer and notifies blocked readers
* (in this case sem count is 0, so no sem_post() is called)
* - interrupt ends
* - since we are in blocking mode, and we read 0 from buffer
* we call sem_wait() and we hang in there cause rx interrupt
* will not be triggered again.
*/
flags = enter_critical_section();
#ifdef CONFIG_IPCC_BUFFERED
/* Data is buffered in interrupt handler, so we simply
* have to return buffers content to the user
*/
if (circbuf_used(&priv->ipcc->rxbuf))
{
/* There is some data on buffer, we are sure we won't block
* so immediately leave critical section to not block other
* more important drivers
*/
leave_critical_section(flags);
}
if ((nread = circbuf_read(&priv->ipcc->rxbuf, buffer, buflen)) > 0)
{
/* got some data */
@@ -176,18 +199,18 @@ ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
nxsem_post(&priv->exclsem);
return nread;
}
#else /* CONFIG_IPCC_BUFFERED */
/* Unbuffered read, read data directly from lower driver */
if ((nread = priv->ipcc->ops.read(&priv->ipcc, buffer, buflen)) != 0)
if ((nread = priv->ipcc->ops.read(priv->ipcc, buffer, buflen)) != 0)
{
/* Got some data, return number of bytes read to the caller
* --or--
* read() returned error in which case return errno value
*/
leave_critical_section(flags);
nxsem_post(&priv->exclsem);
return nread;
}
@@ -201,11 +224,15 @@ ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
* no data could be read
*/
leave_critical_section(flags);
nxsem_post(&priv->exclsem);
return -EAGAIN;
}
/* We are in blocking mode, so we have to wait for data to arrive */
/* We are in blocking mode, so we have to wait for data to arrive.
* nxsem_wait() will atomically leave critical section for us so
* we don't have to do it.
*/
nxsem_post(&priv->exclsem);
if ((ret = nxsem_wait(&priv->rxsem)))
+8 -1
View File
@@ -124,6 +124,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
FAR struct ipcc_driver_s *priv;
ssize_t nwritten;
int ret;
int flags;
/* Get our private data structure */
@@ -143,6 +144,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
for (nwritten = 0; ; )
{
flags = enter_critical_section();
#ifdef CONFIG_IPCC_BUFFERED
/* Buffered write, if buffer is empty try to write directly to
* IPCC memory, else buffer data in circbuf - it will be written
@@ -169,6 +171,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
*/
nxsem_post(&priv->exclsem);
leave_critical_section(flags);
return nwritten;
}
}
@@ -191,13 +194,15 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
/* All outstanding data has been copied to txbuffer, we're done */
nxsem_post(&priv->exclsem);
leave_critical_section(flags);
return nwritten;
}
#else /* CONFIG_IPCC_BUFFERED */
/* Unbuffered write, write data directly to lower driver */
nwritten += priv->ipcc->ops.write(&priv->ipcc, buffer, buflen);
nwritten += priv->ipcc->ops.write(priv->ipcc, buffer + nwritten,
buflen - nwritten);
if (nwritten == (ssize_t)buflen)
{
/* We've managed to write whole buffer to IPCC memory,
@@ -210,6 +215,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
*/
nxsem_post(&priv->exclsem);
leave_critical_section(flags);
return nwritten;
}
@@ -224,6 +230,7 @@ ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
*/
nxsem_post(&priv->exclsem);
leave_critical_section(flags);
return nwritten ? nwritten : -EAGAIN;
}