mirror of
https://github.com/apache/nuttx.git
synced 2026-05-23 14:58:13 +08:00
net/can: can protocol uses a separate buffer to cache can data
To avoid memory waste, can add support for using an independent iob buffer The IP protocol often configures CONFIG_IOB_BUFSIZE to be relatively large, such as 512, for higher throughput. However, the buffer required by CAN is fixed at a length of 16 or 64. If the system's IOB is directly used, a lot of memory will be wasted. Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
committed by
Alan C. Assis
parent
48e9b4fc7a
commit
3e025b5a03
@@ -44,6 +44,7 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/can.h>
|
||||
#include <nuttx/mm/iob.h>
|
||||
#include <nuttx/net/netconfig.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+5
-1
@@ -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
|
||||
|
||||
@@ -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 <nuttx/config.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/can.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/mm/iob.h>
|
||||
#include <nuttx/net/netstats.h>
|
||||
#include <nuttx/net/can.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <nuttx/net/can.h>
|
||||
#include <nuttx/net/ip.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user