drivers/can: optimize can driver reader side

Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
This commit is contained in:
Petro Karashchenko 2022-03-11 16:46:20 +01:00 committed by Xiang Xiao
parent e2114378b9
commit c3bae60c57
3 changed files with 62 additions and 46 deletions

View File

@ -184,7 +184,7 @@ static int can_bittiming(struct up_dev_s *priv);
static const struct can_ops_s g_canops =
{
.co_reset = can_reset,
.co_setup = can_setup,
.co_setup = can_setup,
.co_shutdown = can_shutdown,
.co_rxint = can_rxint,
.co_txint = can_txint,

View File

@ -392,7 +392,6 @@ static int can_open(FAR struct file *filep)
FAR struct inode *inode = filep->f_inode;
FAR struct can_dev_s *dev = inode->i_private;
irqstate_t flags;
int tmp;
int ret;
/* If the port is the middle of closing, wait until the close is finished */
@ -407,46 +406,48 @@ static int can_open(FAR struct file *filep)
* for this device, then perform hardware initialization.
*/
if (list_is_empty(&dev->cd_readers))
caninfo("ocount: %u\n", dev->cd_crefs);
if (dev->cd_crefs >= 255)
{
caninfo("ocount: %d\n", 0);
/* Limit to no more than 255 opens */
flags = enter_critical_section();
ret = dev_setup(dev);
if (ret >= 0)
{
/* Mark the FIFOs empty */
dev->cd_xmit.tx_head = 0;
dev->cd_xmit.tx_queue = 0;
dev->cd_xmit.tx_tail = 0;
/* Finally, Enable the CAN RX interrupt */
dev_rxint(dev, true);
}
list_add_head(&dev->cd_readers,
(FAR struct list_node *)init_can_reader(filep));
leave_critical_section(flags);
ret = -EMFILE;
goto errout;
}
else
{
tmp = list_length(&dev->cd_readers);
caninfo("ocount: %d\n", tmp);
flags = enter_critical_section();
if (tmp >= 255)
if (dev->cd_crefs == 0)
{
/* Limit to no more than 255 opens */
ret = dev_setup(dev);
if (ret == OK)
{
/* Mark the FIFOs empty */
ret = -EMFILE;
goto errout;
dev->cd_xmit.tx_head = 0;
dev->cd_xmit.tx_queue = 0;
dev->cd_xmit.tx_tail = 0;
/* Finally, Enable the CAN RX interrupt */
dev_rxint(dev, true);
}
}
flags = enter_critical_section();
list_add_head(&dev->cd_readers,
(FAR struct list_node *)init_can_reader(filep));
if (ret == OK)
{
dev->cd_crefs++;
/* Update the reader list only if driver was open for reading */
if ((filep->f_oflags & O_RDOK) != 0)
{
list_add_head(&dev->cd_readers,
(FAR struct list_node *)init_can_reader(filep));
}
}
leave_critical_section(flags);
}
@ -475,7 +476,7 @@ static int can_close(FAR struct file *filep)
int ret;
#ifdef CONFIG_DEBUG_CAN_INFO
caninfo("ocount: %d\n", list_length(&dev->cd_readers));
caninfo("ocount: %u\n", dev->cd_crefs);
#endif
ret = can_takesem(&dev->cd_closesem);
@ -496,10 +497,11 @@ static int can_close(FAR struct file *filep)
}
filep->f_priv = NULL;
dev->cd_crefs--;
/* Uninitialize the driver if there are no more readers */
/* De-initialize the driver if there are no more readers */
if (!list_is_empty(&dev->cd_readers))
if (dev->cd_crefs > 0)
{
goto errout;
}
@ -544,7 +546,7 @@ errout:
static ssize_t can_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
FAR struct can_reader_s *reader = NULL;
FAR struct can_reader_s *reader;
FAR struct can_rxfifo_s *fifo;
size_t nread;
irqstate_t flags;
@ -563,11 +565,25 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer,
if (buflen >= CAN_MSGLEN(0))
{
DEBUGASSERT(filep->f_priv != NULL);
reader = (FAR struct can_reader_s *)filep->f_priv;
fifo = &reader->fifo;
/* Interrupts must be disabled while accessing the cd_recv FIFO */
flags = enter_critical_section();
#ifdef CONFIG_CAN_ERRORS
/* Check for reader fifo overflow */
if (fifo->rx_overflow)
{
dev->cd_error |= CAN_ERROR5_RXOVERFLOW;
fifo->rx_overflow = false;
}
/* Check for internal errors */
if (dev->cd_error != 0)
@ -604,12 +620,7 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer,
}
#endif /* CONFIG_CAN_ERRORS */
DEBUGASSERT(filep->f_priv != NULL);
reader = (FAR struct can_reader_s *)filep->f_priv;
fifo = &reader->fifo;
if (filep->f_oflags & O_NONBLOCK)
if ((filep->f_oflags & O_NONBLOCK) != 0)
{
ret = nxsem_trywait(&fifo->rx_sem);
}
@ -1229,12 +1240,13 @@ int can_register(FAR const char *path, FAR struct can_dev_s *dev)
/* Initialize the CAN device structure */
list_initialize(&dev->cd_readers);
dev->cd_ntxwaiters = 0;
dev->cd_crefs = 0;
dev->cd_npendrtr = 0;
dev->cd_ntxwaiters = 0;
#ifdef CONFIG_CAN_ERRORS
dev->cd_error = 0;
#endif
list_initialize(&dev->cd_readers);
/* Initialize semaphores */
@ -1427,7 +1439,7 @@ int can_receive(FAR struct can_dev_s *dev, FAR struct can_hdr_s *hdr,
{
/* Report rx overflow error */
dev->cd_error |= CAN_ERROR5_RXOVERFLOW;
fifo->rx_overflow = true;
}
#endif
}

View File

@ -498,6 +498,9 @@ struct can_rxfifo_s
sem_t rx_sem;
#ifdef CONFIG_CAN_ERRORS
bool rx_overflow; /* Indicates the RX FIFO overflow event */
#endif
uint8_t rx_head; /* Index to the head [IN] in the circular buffer */
uint8_t rx_tail; /* Index to the tail [OUT] in the circular buffer */
/* Circular buffer of CAN messages */
@ -606,12 +609,13 @@ struct can_reader_s
struct can_dev_s
{
uint8_t cd_crefs; /* References counts on number of opens */
uint8_t cd_npendrtr; /* Number of pending RTR messages */
volatile uint8_t cd_ntxwaiters; /* Number of threads waiting to enqueue a message */
struct list_node cd_readers; /* List of readers */
#ifdef CONFIG_CAN_ERRORS
uint8_t cd_error; /* Flags to indicate internal device errors */
#endif
struct list_node cd_readers; /* List of readers */
sem_t cd_closesem; /* Locks out new opens while close is in progress */
sem_t cd_pollsem; /* Manages exclusive access to cd_fds[] */
struct can_txfifo_s cd_xmit; /* Describes transmit FIFO */