diff --git a/include/nuttx/net/can.h b/include/nuttx/net/can.h index 3d3856968b6..00c6db1ab76 100644 --- a/include/nuttx/net/can.h +++ b/include/nuttx/net/can.h @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -126,6 +127,48 @@ extern "C" struct net_driver_s; /* Forward reference */ int can_input(FAR struct net_driver_s *dev); +/**************************************************************************** + * Name: can_iob_timedalloc + * + * Description: + * Allocate an CAN I/O buffer from the CAN buffer pool. + * + ****************************************************************************/ + +#if CONFIG_NET_CAN_NBUFFERS > 0 +FAR struct iob_s *can_iob_timedalloc(unsigned int timeout); +#else +#define can_iob_timedalloc(t) net_iobtimedalloc(true, t) +#endif + +/**************************************************************************** + * Name: can_iob_clone + * + * Description: + * Clone an I/O buffer from the CAN buffer pool. + * + ****************************************************************************/ + +#if CONFIG_NET_CAN_NBUFFERS > 0 +FAR struct iob_s *can_iob_clone(FAR struct net_driver_s *dev); +#else +#define can_iob_clone(d) netdev_iob_clone(d, false) +#endif + +/**************************************************************************** + * Name: can_iob_navail + * + * Description: + * Return the number of available CAN I/O buffers. + * + ****************************************************************************/ + +#if CONFIG_NET_CAN_NBUFFERS > 0 +int can_iob_navail(void); +#else +#define can_iob_navail() iob_navail(false) +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/net/can/CMakeLists.txt b/net/can/CMakeLists.txt index 90f8d2fe23b..6c21d17195f 100644 --- a/net/can/CMakeLists.txt +++ b/net/can/CMakeLists.txt @@ -39,6 +39,10 @@ if(CONFIG_NET_CAN) list(APPEND SRCS can_setsockopt.c can_getsockopt.c) endif() + if(CONFIG_NET_CAN_NBUFFERS GREATER 0) + list(APPEND SRCS can_bufpool.c) + endif() + list(APPEND SRCS can_conn.c can_input.c can_callback.c can_poll.c) target_sources(net PRIVATE ${SRCS}) diff --git a/net/can/Kconfig b/net/can/Kconfig index c74c1ca2c7b..4c4e9d9b1c6 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig @@ -156,5 +156,14 @@ config NET_CAN_NOTIFIER purpose notifier, but was developed specifically to support poll() logic where the poll must wait for these events. +config NET_CAN_NBUFFERS + int "Number of CAN buffers" + depends on IOB_ALLOC + default 0 + ---help--- + Each CAN packet is represented by a CAN buffers. + This setting determines the number of preallocated CAN buffers + available for packet data. + endif # NET_CAN endmenu # CAN Socket Support diff --git a/net/can/Make.defs b/net/can/Make.defs index f6f3ae61901..b1ffd4d048f 100644 --- a/net/can/Make.defs +++ b/net/can/Make.defs @@ -43,6 +43,12 @@ ifeq ($(CONFIG_NET_CANPROTO_OPTIONS),y) SOCK_CSRCS += can_setsockopt.c can_getsockopt.c endif +ifdef CONFIG_NET_CAN_NBUFFERS +ifneq (${CONFIG_NET_CAN_NBUFFERS},0) +SOCK_CSRCS += can_bufpool.c +endif +endif + NET_CSRCS += can_conn.c NET_CSRCS += can_input.c NET_CSRCS += can_callback.c diff --git a/net/can/can.h b/net/can/can.h index a6a24860d9c..fa7bf105384 100644 --- a/net/can/can.h +++ b/net/can/can.h @@ -57,6 +57,10 @@ #define can_callback_free(dev,conn,cb) \ devif_conn_callback_free(dev, cb, &conn->sconn.list, &conn->sconn.list_tail) +#ifndef CONFIG_NET_CAN_NBUFFERS +# define CONFIG_NET_CAN_NBUFFERS 0 +#endif + /**************************************************************************** * Public Type Definitions ****************************************************************************/ @@ -90,7 +94,7 @@ struct can_conn_s struct iob_queue_s readahead; /* remove Read-ahead buffering */ #if CONFIG_NET_RECV_BUFSIZE > 0 - int32_t recv_buffnum; /* Recv buffer number */ + int32_t rcvbufs; /* Maximum amount of bytes queued in receive */ #endif #if CONFIG_NET_SEND_BUFSIZE > 0 diff --git a/net/can/can_bufpool.c b/net/can/can_bufpool.c new file mode 100644 index 00000000000..485b98d9b75 --- /dev/null +++ b/net/can/can_bufpool.c @@ -0,0 +1,145 @@ +/**************************************************************************** + * net/can/can_bufpool.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +#include "utils/utils.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_NET_TIMESTAMP +# define CAN_BUFFER_SIZE ALIGN_UP(sizeof(struct iob_s) + NET_CAN_PKTSIZE + \ + CONFIG_NET_LL_GUARDSIZE + IOB_ALIGNMENT - \ + 1, IOB_ALIGNMENT) +#else +# define CAN_BUFFER_SIZE ALIGN_UP(sizeof(struct iob_s) + NET_CAN_PKTSIZE + \ + IOB_ALIGNMENT - 1, IOB_ALIGNMENT) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The array containing all CAN buffers */ + +NET_BUFPOOL_DECLARE(g_can_buffer, CAN_BUFFER_SIZE, + CONFIG_NET_CAN_NBUFFERS, 0, 0); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: can_buf_free + * + * Description: + * Free the CAN buffer to the buffer pool + * + * Input Parameters: + * data - The CAN buffer to be freed + * + ****************************************************************************/ + +static void can_buf_free(FAR void *buf) +{ + NET_BUFPOOL_FREE(g_can_buffer, buf); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: can_iob_timedalloc + * + * Description: + * Allocate an CAN I/O buffer from the CAN buffer pool. + * + ****************************************************************************/ + +FAR struct iob_s *can_iob_timedalloc(unsigned int timeout) +{ + FAR void *buf = NET_BUFPOOL_TIMEDALLOC(g_can_buffer, timeout); + + if (buf == NULL) + { + nwarn("Failed to allocate CAN buffer\n"); + return NULL; + } + + return iob_init_with_data(buf, CAN_BUFFER_SIZE, can_buf_free); +} + +/**************************************************************************** + * Name: can_iob_clone + * + * Description: + * Clone an I/O buffer from the CAN buffer pool. + * + ****************************************************************************/ + +FAR struct iob_s *can_iob_clone(FAR struct net_driver_s *dev) +{ + FAR struct iob_s *iob; + + iob = can_iob_timedalloc(0); + if (iob == NULL) + { + return NULL; + } + +#ifdef CONFIG_NET_TIMESTAMP + iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE); +#endif + + /* CAN data length is fixed, So when we use iob_clone_partial to copy + * data, we don't have to worry about distributing other iob. + */ + + iob_clone_partial(dev->d_iob, dev->d_iob->io_pktlen, 0, iob, 0, + false, false); + + return iob; +} + +/**************************************************************************** + * Name: can_iob_navail + * + * Description: + * Return the number of available CAN I/O buffers. + * + ****************************************************************************/ + +int can_iob_navail(void) +{ + return NET_BUFPOOL_NAVAIL(g_can_buffer); +} diff --git a/net/can/can_callback.c b/net/can/can_callback.c index f28bc1008a8..62538865151 100644 --- a/net/can/can_callback.c +++ b/net/can/can_callback.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "devif/devif.h" #include "can/can.h" @@ -202,13 +203,18 @@ uint16_t can_datahandler(FAR struct net_driver_s *dev, int ret = 0; #if CONFIG_NET_RECV_BUFSIZE > 0 +# if CONFIG_NET_CAN_NBUFFERS > 0 + int bufnum = div_const_roundup(conn->rcvbufs, NET_CAN_PKTSIZE); +# else + int bufnum = div_const_roundup(conn->rcvbufs, CONFIG_IOB_BUFSIZE); +# endif /* Check the frame count pending on conn->readahead */ - if (iob_get_queue_entry_count(&conn->readahead) >= conn->recv_buffnum) + if (iob_get_queue_entry_count(&conn->readahead) >= bufnum) { nwarn("WARNING: There are no free receive buffer to retain the data. " "Receive buffer number:%"PRId32", received frames:%"PRIuPTR" \n", - conn->recv_buffnum, iob_get_queue_entry_count(&conn->readahead)); + bufnum, iob_get_queue_entry_count(&conn->readahead)); goto errout; } #endif diff --git a/net/can/can_getsockopt.c b/net/can/can_getsockopt.c index 6b2a1ae444b..bf6d75634c2 100644 --- a/net/can/can_getsockopt.c +++ b/net/can/can_getsockopt.c @@ -180,7 +180,7 @@ int can_getsockopt(FAR struct socket *psock, int level, int option, return -EINVAL; } - *(FAR int *)value = conn->recv_buffnum * CONFIG_IOB_BUFSIZE; + *(FAR int *)value = conn->rcvbufs; break; #endif diff --git a/net/can/can_input.c b/net/can/can_input.c index 679c69d85b6..ea4639aefa2 100644 --- a/net/can/can_input.c +++ b/net/can/can_input.c @@ -227,7 +227,7 @@ static int can_in(FAR struct net_driver_s *dev) * We need to clone the packet and deliver it to each listener. */ - FAR struct iob_s *iob = netdev_iob_clone(dev, false); + FAR struct iob_s *iob = can_iob_clone(dev); if (iob == NULL) { diff --git a/net/can/can_sendmsg_buffered.c b/net/can/can_sendmsg_buffered.c index 87d5c9ee2ef..eb9442d3824 100644 --- a/net/can/can_sendmsg_buffered.c +++ b/net/can/can_sendmsg_buffered.c @@ -39,6 +39,7 @@ #include +#include #include #include #include @@ -273,11 +274,11 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, if (nonblock) { - wb_iob = iob_tryalloc(false); + wb_iob = can_iob_timedalloc(0); } else { - wb_iob = net_iobtimedalloc(true, _SO_TIMEOUT(conn->sconn.s_sndtimeo)); + wb_iob = can_iob_timedalloc(_SO_TIMEOUT(conn->sconn.s_sndtimeo)); } if (wb_iob == NULL) @@ -446,7 +447,7 @@ int psock_can_cansend(FAR struct socket *psock) conn = psock->s_conn; #endif - if (iob_navail(false) <= 0 + if (can_iob_navail() <= 0 #if CONFIG_NET_SEND_BUFSIZE > 0 || iob_get_queue_size(&conn->write_q) >= conn->sndbufs #endif diff --git a/net/can/can_setsockopt.c b/net/can/can_setsockopt.c index ffd20340001..692df5ad0c6 100644 --- a/net/can/can_setsockopt.c +++ b/net/can/can_setsockopt.c @@ -199,9 +199,7 @@ int can_setsockopt(FAR struct socket *psock, int level, int option, #if CONFIG_NET_MAX_RECV_BUFSIZE > 0 buffersize = MIN(buffersize, CONFIG_NET_MAX_RECV_BUFSIZE); #endif - - conn->recv_buffnum = (buffersize + CONFIG_IOB_BUFSIZE - 1) - / CONFIG_IOB_BUFSIZE; + conn->rcvbufs = buffersize; break; } diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c index aebd83985ca..1a3e280cab3 100644 --- a/net/can/can_sockif.c +++ b/net/can/can_sockif.c @@ -228,8 +228,7 @@ static int can_setup(FAR struct socket *psock) */ #if CONFIG_NET_RECV_BUFSIZE > 0 - conn->recv_buffnum = (CONFIG_NET_RECV_BUFSIZE + CONFIG_IOB_BUFSIZE - 1) - / CONFIG_IOB_BUFSIZE; + conn->rcvbufs = CONFIG_NET_RECV_BUFSIZE; #endif #if CONFIG_NET_SEND_BUFSIZE > 0