CAN: Add a new CAN upper-half interface, can_txready(), that can be used to break deadlock conditions in certain CAN hardware that supports queuing of TX messages
This commit is contained in:
parent
da8950fe5b
commit
c6fc285277
10
ChangeLog
10
ChangeLog
@ -11060,3 +11060,13 @@
|
|||||||
board user LED interfaces (2015-11-01).
|
board user LED interfaces (2015-11-01).
|
||||||
* sched/clock: Fix error in clock_timespec_subtract(). Found by Lok
|
* sched/clock: Fix error in clock_timespec_subtract(). Found by Lok
|
||||||
(2015-11-03).
|
(2015-11-03).
|
||||||
|
* drivers/can.c and include/nuttx/can.h: Fix a problem in the CAN
|
||||||
|
upper-half driver that occurs only for CAN hardware that support a
|
||||||
|
H/W FIFO of outgoing CAN messages. In this case, there can be a
|
||||||
|
hang condition if both the H/W and S/W FIFOs are both full. In that
|
||||||
|
case, there may be no event to awaken the upper half driver. Add a
|
||||||
|
new (conditional) CAN upper half interface called can_txready() that
|
||||||
|
can be used by the lower half driver to avoid this hang condition
|
||||||
|
(2015-11-03).
|
||||||
|
* arch/arm/src/samv7: Add a call to can_txready() to the MCAN driver
|
||||||
|
(2015-11-03).
|
||||||
|
2
arch
2
arch
@ -1 +1 @@
|
|||||||
Subproject commit b763efbe64b84ff1cefdd428c7a3d7b7b69f1c9b
|
Subproject commit 309bd15763dfa0d7e803811216c3b17262255de6
|
@ -125,6 +125,54 @@ config CAN_NPENDINGRTR
|
|||||||
---help---
|
---help---
|
||||||
The size of the list of pending RTR requests. Default: 4
|
The size of the list of pending RTR requests. Default: 4
|
||||||
|
|
||||||
|
config CAN_TXREADY
|
||||||
|
bool "can_txready interface"
|
||||||
|
default n
|
||||||
|
---help---
|
||||||
|
This selection enables the can_txready() interface. This interface
|
||||||
|
is needed only for CAN hardware that supports queing of outgoing
|
||||||
|
messages in a H/W FIFO.
|
||||||
|
|
||||||
|
The CAN upper half driver also supports a queue of output messages
|
||||||
|
in a S/W FIFO. Messages are added to that queue when when
|
||||||
|
can_write() is called and removed from the queue in can_txdone()
|
||||||
|
when each TX message is complete.
|
||||||
|
|
||||||
|
After each message is added to the S/W FIFO, the CAN upper half
|
||||||
|
driver will attempt to send the message by calling into the lower
|
||||||
|
half driver. That send will not be performed if the lower half
|
||||||
|
driver is busy, i.e., if dev_txready() returns false. In that
|
||||||
|
case, the number of messages in the S/W FIFO can grow. If the
|
||||||
|
S/W FIFO becomes full, then can_write() will wait for space in
|
||||||
|
the S/W FIFO.
|
||||||
|
|
||||||
|
If the CAN hardware does not support a H/W FIFO then busy means
|
||||||
|
that the hardware is actively sending the message and is
|
||||||
|
guaranteed to become non busy (i.e, dev_txready()) when the
|
||||||
|
send transfer completes and can_txdone() is called. So the call
|
||||||
|
to can_txdone() means that the transfer has completed and also
|
||||||
|
that the hardware is ready to accept another transfer.
|
||||||
|
|
||||||
|
If the CAN hardware supports a H/W FIFO, can_txdone() is not
|
||||||
|
called when the tranfer is complete, but rather when the
|
||||||
|
transfer is queued in the H/W FIFO. When the H/W FIFO becomes
|
||||||
|
full, then dev_txready() will report false and the number of
|
||||||
|
queued messages in the S/W FIFO will grow.
|
||||||
|
|
||||||
|
There is no mechanism in this case to inform the upper half
|
||||||
|
driver when the hardware is again available, when there is
|
||||||
|
again space in the H/W FIFO. can_txdone() will not be called
|
||||||
|
again. If the S/W FIFO becomes full, then the upper half
|
||||||
|
driver will wait for space to become available, but there is
|
||||||
|
no event to awaken it and the driver will hang.
|
||||||
|
|
||||||
|
Enabling this feature adds support for the can_txready()
|
||||||
|
interface. This function is called from the lower half
|
||||||
|
driver's CAN interrupt handler each time a TX transfer
|
||||||
|
completes. This is a sure indication that the H/W FIFO is
|
||||||
|
no longer full. can_txready() will then awaken the
|
||||||
|
can_write() logic and the hang condition is avoided.
|
||||||
|
|
||||||
config CAN_LOOPBACK
|
config CAN_LOOPBACK
|
||||||
bool "CAN loopback mode"
|
bool "CAN loopback mode"
|
||||||
default n
|
default n
|
||||||
|
@ -554,7 +554,7 @@ static int can_xmit(FAR struct can_dev_s *dev)
|
|||||||
DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail);
|
DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail);
|
||||||
|
|
||||||
/* Increment the FIFO queue index before sending (because dev_send()
|
/* Increment the FIFO queue index before sending (because dev_send()
|
||||||
* might call can_txdone().
|
* might call can_txdone()).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tmpndx = dev->cd_xmit.tx_queue;
|
tmpndx = dev->cd_xmit.tx_queue;
|
||||||
@ -634,7 +634,7 @@ static ssize_t can_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
{
|
{
|
||||||
/* The transmit FIFO is full -- was non-blocking mode selected? */
|
/* The transmit FIFO is full -- was non-blocking mode selected? */
|
||||||
|
|
||||||
if (filep->f_oflags & O_NONBLOCK)
|
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||||
{
|
{
|
||||||
if (nsent == 0)
|
if (nsent == 0)
|
||||||
{
|
{
|
||||||
@ -1007,6 +1007,12 @@ int can_txdone(FAR struct can_dev_s *dev)
|
|||||||
|
|
||||||
if (dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail)
|
if (dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail)
|
||||||
{
|
{
|
||||||
|
/* The tx_queue index is incremented each time can_xmit() queues
|
||||||
|
* the transmission. When can_txdone() is called, the tx_queue
|
||||||
|
* index should always have been advanced beyond the current tx_head
|
||||||
|
* index.
|
||||||
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_queue);
|
DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_queue);
|
||||||
|
|
||||||
/* Remove the message at the head of the xmit FIFO */
|
/* Remove the message at the head of the xmit FIFO */
|
||||||
@ -1037,4 +1043,89 @@ int can_txdone(FAR struct can_dev_s *dev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: can_txready
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Called from the CAN interrupt handler at the completion of a send
|
||||||
|
* operation. This interface is needed only for CAN hardware that
|
||||||
|
* supports queing of outgoing messages in a H/W FIFO.
|
||||||
|
*
|
||||||
|
* The CAN upper half driver also supports a queue of output messages in a
|
||||||
|
* S/W FIFO. Messages are added to that queue when when can_write() is
|
||||||
|
* called and removed from the queue in can_txdone() when each TX message
|
||||||
|
* is complete.
|
||||||
|
*
|
||||||
|
* After each message is added to the S/W FIFO, the CAN upper half driver
|
||||||
|
* will attempt to send the message by calling into the lower half driver.
|
||||||
|
* That send will not be performed if the lower half driver is busy, i.e.,
|
||||||
|
* if dev_txready() returns false. In that case, the number of messages in
|
||||||
|
* the S/W FIFO can grow. If the S/W FIFO becomes full, then can_write()
|
||||||
|
* will wait for space in the S/W FIFO.
|
||||||
|
*
|
||||||
|
* If the CAN hardware does not support a H/W FIFO then busy means that
|
||||||
|
* the hardware is actively sending the message and is guaranteed to
|
||||||
|
* become non-busy (i.e, dev_txready()) when the send transfer completes
|
||||||
|
* and can_txdone() is called. So the call to can_txdone() means that the
|
||||||
|
* transfer has completed and also that the hardware is ready to accept
|
||||||
|
* another transfer.
|
||||||
|
*
|
||||||
|
* If the CAN hardware supports a H/W FIFO, can_txdone() is not called
|
||||||
|
* when the tranfer is complete, but rather when the transfer is queued in
|
||||||
|
* the H/W FIFO. When the H/W FIFO becomes full, then dev_txready() will
|
||||||
|
* report false and the number of queued messages in the S/W FIFO will grow.
|
||||||
|
*
|
||||||
|
* There is no mechanism in this case to inform the upper half driver when
|
||||||
|
* the hardware is again available, when there is again space in the H/W
|
||||||
|
* FIFO. can_txdone() will not be called again. If the S/W FIFO becomes
|
||||||
|
* full, then the upper half driver will wait for space to become
|
||||||
|
* available, but there is no event to awaken it and the driver will hang.
|
||||||
|
*
|
||||||
|
* Enabling this feature adds support for the can_txready() interface.
|
||||||
|
* This function is called from the lower half driver's CAN interrupt
|
||||||
|
* handler each time a TX transfer completes. This is a sure indication
|
||||||
|
* that the H/W FIFO is no longer full. can_txready() will then awaken
|
||||||
|
* the can_write() logic and the hang condition is avoided.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* dev - The specific CAN device
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* OK on success; a negated errno on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_CAN_TXREADY
|
||||||
|
int can_txready(FAR struct can_dev_s *dev)
|
||||||
|
{
|
||||||
|
int ret = -ENOENT;
|
||||||
|
|
||||||
|
canllvdbg("xmit head: %d queue: %d tail: %d waiters: %d\n",
|
||||||
|
dev->cd_xmit.tx_head, dev->cd_xmit.tx_queue, dev->cd_xmit.tx_tail,
|
||||||
|
dev->cd_ntxwaiters);
|
||||||
|
|
||||||
|
/* Are there any threads waiting for space in the xmit FIFO? */
|
||||||
|
|
||||||
|
if (dev->cd_ntxwaiters > 0)
|
||||||
|
{
|
||||||
|
/* Verify that the xmit FIFO is not empty.
|
||||||
|
* REVISIT: This probably should be an assertion since we should only
|
||||||
|
* be waiting for space in the xmit FIFO if the xmit FIFO is full.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail)
|
||||||
|
{
|
||||||
|
/* Send the next message in the FIFO, making space in the xmit FIFO */
|
||||||
|
|
||||||
|
(void)can_xmit(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inform one waiter that new xmit space is available */
|
||||||
|
|
||||||
|
ret = sem_post(&dev->cd_xmit.tx_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_CAN_TXREADY */
|
||||||
#endif /* CONFIG_CAN */
|
#endif /* CONFIG_CAN */
|
||||||
|
@ -524,6 +524,60 @@ int can_receive(FAR struct can_dev_s *dev, FAR struct can_hdr_s *hdr,
|
|||||||
|
|
||||||
int can_txdone(FAR struct can_dev_s *dev);
|
int can_txdone(FAR struct can_dev_s *dev);
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: can_txready
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Called from the CAN interrupt handler at the completion of a send operation.
|
||||||
|
* This interface is needed only for CAN hardware that supports queing of
|
||||||
|
* outgoing messages in a H/W FIFO.
|
||||||
|
*
|
||||||
|
* The CAN upper half driver also supports a queue of output messages in a S/W
|
||||||
|
* FIFO. Messages are added to that queue when when can_write() is called and
|
||||||
|
* removed from the queue in can_txdone() when each TX message is complete.
|
||||||
|
*
|
||||||
|
* After each message is added to the S/W FIFO, the CAN upper half driver will
|
||||||
|
* attempt to send the message by calling into the lower half driver. That send
|
||||||
|
* will not be performed if the lower half driver is busy, i.e., if dev_txready()
|
||||||
|
* returns false. In that case, the number of messages in the S/W FIFO can grow.
|
||||||
|
* If the S/W FIFO becomes full, then can_write() will wait for space in the
|
||||||
|
* S/W FIFO.
|
||||||
|
*
|
||||||
|
* If the CAN hardware does not support a H/W FIFO then busy means that the
|
||||||
|
* hardware is actively sending the message and is guaranteed to become non-
|
||||||
|
* busy (i.e, dev_txready()) when the send transfer completes and can_txdone()
|
||||||
|
* is called. So the call to can_txdone() means that the transfer has
|
||||||
|
* completed and also that the hardware is ready to accept another transfer.
|
||||||
|
*
|
||||||
|
* If the CAN hardware supports a H/W FIFO, can_txdone() is not called when
|
||||||
|
* the tranfer is complete, but rather when the transfer is queued in the
|
||||||
|
* H/W FIFO. When the H/W FIFO becomes full, then dev_txready() will report
|
||||||
|
* false and the number of queued messages in the S/W FIFO will grow.
|
||||||
|
*
|
||||||
|
* There is no mechanism in this case to inform the upper half driver when
|
||||||
|
* the hardware is again available, when there is again space in the H/W
|
||||||
|
* FIFO. can_txdone() will not be called again. If the S/W FIFO becomes
|
||||||
|
* full, then the upper half driver will wait for space to become available,
|
||||||
|
* but there is no event to awaken it and the driver will hang.
|
||||||
|
*
|
||||||
|
* Enabling this feature adds support for the can_txready() interface.
|
||||||
|
* This function is called from the lower half driver's CAN interrupt
|
||||||
|
* handler each time a TX transfer completes. This is a sure indication
|
||||||
|
* that the H/W FIFO is no longer full. can_txready() will then awaken
|
||||||
|
* the can_write() logic and the hang condition is avoided.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* dev - The specific CAN device
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* OK on success; a negated errno on failure.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_CAN_TXREADY
|
||||||
|
int can_txready(FAR struct can_dev_s *dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user