net: Switch from per-iface tx thread to a unique k_poll triggered one
Now that k_poll landed in the kernel, it's worth using it to save memory and reduce the number of threads at runtime. Such switch has been first done in bluetooth (see hci_core.c and conn.c in subsys/bluetooth/host). Since network interfaces kind of follows the same design for sending data, it was then easy to copy the same change as in bluetooth. Change-Id: I7f9734b88ac818284bbabaedc946b4765b905ebb Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
parent
0453629078
commit
e38a9e8b9c
6 changed files with 96 additions and 67 deletions
|
@ -134,10 +134,18 @@
|
||||||
{
|
{
|
||||||
__net_if_start = .;
|
__net_if_start = .;
|
||||||
*(".net_if.*")
|
*(".net_if.*")
|
||||||
KEEP(*(SORT_BY_NAME(".net_if*")))
|
KEEP(*(SORT_BY_NAME(".net_if.*")))
|
||||||
__net_if_end = .;
|
__net_if_end = .;
|
||||||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||||
|
|
||||||
|
SECTION_DATA_PROLOGUE(net_if_event, (OPTIONAL),)
|
||||||
|
{
|
||||||
|
__net_if_event_start = .;
|
||||||
|
*(".net_if_event.*")
|
||||||
|
KEEP(*(SORT_BY_NAME(".net_if_event.*")))
|
||||||
|
__net_if_event_end = .;
|
||||||
|
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||||
|
|
||||||
#if defined(CONFIG_NET_SHELL)
|
#if defined(CONFIG_NET_SHELL)
|
||||||
SECTION_DATA_PROLOGUE(net_stack, (OPTIONAL),)
|
SECTION_DATA_PROLOGUE(net_stack, (OPTIONAL),)
|
||||||
{
|
{
|
||||||
|
|
|
@ -203,12 +203,6 @@ struct net_if {
|
||||||
/** Queue for outgoing packets from apps */
|
/** Queue for outgoing packets from apps */
|
||||||
struct k_fifo tx_queue;
|
struct k_fifo tx_queue;
|
||||||
|
|
||||||
/** Stack for the TX thread tied to this interface */
|
|
||||||
#ifndef CONFIG_NET_TX_STACK_SIZE
|
|
||||||
#define CONFIG_NET_TX_STACK_SIZE 1024
|
|
||||||
#endif
|
|
||||||
NET_STACK_DEFINE_EMBEDDED(tx_stack, CONFIG_NET_TX_STACK_SIZE);
|
|
||||||
|
|
||||||
#if defined(CONFIG_NET_IPV6)
|
#if defined(CONFIG_NET_IPV6)
|
||||||
#define NET_IF_MAX_IPV6_ADDR CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT
|
#define NET_IF_MAX_IPV6_ADDR CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT
|
||||||
#define NET_IF_MAX_IPV6_MADDR CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT
|
#define NET_IF_MAX_IPV6_MADDR CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT
|
||||||
|
@ -1190,6 +1184,9 @@ struct net_if_api {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NET_IF_GET_NAME(dev_name, sfx) (__net_if_##dev_name##_##sfx)
|
#define NET_IF_GET_NAME(dev_name, sfx) (__net_if_##dev_name##_##sfx)
|
||||||
|
#define NET_IF_EVENT_GET_NAME(dev_name, sfx) \
|
||||||
|
(__net_if_event_##dev_name##_##sfx)
|
||||||
|
|
||||||
#define NET_IF_GET(dev_name, sfx) \
|
#define NET_IF_GET(dev_name, sfx) \
|
||||||
((struct net_if *)&NET_IF_GET_NAME(dev_name, sfx))
|
((struct net_if *)&NET_IF_GET_NAME(dev_name, sfx))
|
||||||
|
|
||||||
|
@ -1202,12 +1199,9 @@ struct net_if_api {
|
||||||
.mtu = _mtu, \
|
.mtu = _mtu, \
|
||||||
NET_IF_DHCPV4_INIT \
|
NET_IF_DHCPV4_INIT \
|
||||||
}; \
|
}; \
|
||||||
NET_STACK_INFO_ADDR(TX, \
|
static struct k_poll_event \
|
||||||
dev_name, \
|
(NET_IF_EVENT_GET_NAME(dev_name, sfx)) __used \
|
||||||
CONFIG_NET_TX_STACK_SIZE, \
|
__attribute__((__section__(".net_if_event.data"))) = {}
|
||||||
CONFIG_NET_TX_STACK_SIZE, \
|
|
||||||
NET_IF_GET(dev_name, sfx)->tx_stack, \
|
|
||||||
sfx)
|
|
||||||
|
|
||||||
|
|
||||||
/* Network device initialization macros */
|
/* Network device initialization macros */
|
||||||
|
|
|
@ -470,7 +470,7 @@ class SizeCalculator:
|
||||||
"_k_sem_area", "_k_mutex_area", "_k_alert_area",
|
"_k_sem_area", "_k_mutex_area", "_k_alert_area",
|
||||||
"_k_fifo_area", "_k_lifo_area", "_k_stack_area",
|
"_k_fifo_area", "_k_lifo_area", "_k_stack_area",
|
||||||
"_k_msgq_area", "_k_mbox_area", "_k_pipe_area",
|
"_k_msgq_area", "_k_mbox_area", "_k_pipe_area",
|
||||||
"net_if", "net_stack", "net_l2_data",
|
"net_if", "net_if_event", "net_stack", "net_l2_data",
|
||||||
"_k_queue_area"]
|
"_k_queue_area"]
|
||||||
# These get copied into RAM only on non-XIP
|
# These get copied into RAM only on non-XIP
|
||||||
ro_sections = ["text", "ctors", "init_array", "reset",
|
ro_sections = ["text", "ctors", "init_array", "reset",
|
||||||
|
|
|
@ -61,6 +61,7 @@ config NET_BUF_POOL_USAGE
|
||||||
config NETWORKING
|
config NETWORKING
|
||||||
bool "Link layer and IP networking support"
|
bool "Link layer and IP networking support"
|
||||||
select NET_BUF
|
select NET_BUF
|
||||||
|
select POLL
|
||||||
select RANDOM_GENERATOR
|
select RANDOM_GENERATOR
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
|
|
|
@ -33,12 +33,18 @@
|
||||||
extern struct net_if __net_if_start[];
|
extern struct net_if __net_if_start[];
|
||||||
extern struct net_if __net_if_end[];
|
extern struct net_if __net_if_end[];
|
||||||
|
|
||||||
|
extern struct k_poll_event __net_if_event_start[];
|
||||||
|
extern struct k_poll_event __net_if_event_stop[];
|
||||||
|
|
||||||
static struct net_if_router routers[CONFIG_NET_MAX_ROUTERS];
|
static struct net_if_router routers[CONFIG_NET_MAX_ROUTERS];
|
||||||
|
|
||||||
/* We keep track of the link callbacks in this list.
|
/* We keep track of the link callbacks in this list.
|
||||||
*/
|
*/
|
||||||
static sys_slist_t link_callbacks;
|
static sys_slist_t link_callbacks;
|
||||||
|
|
||||||
|
NET_STACK_DEFINE(TX, tx_stack, CONFIG_NET_TX_STACK_SIZE,
|
||||||
|
CONFIG_NET_TX_STACK_SIZE);
|
||||||
|
|
||||||
#if defined(CONFIG_NET_DEBUG_IF)
|
#if defined(CONFIG_NET_DEBUG_IF)
|
||||||
#define debug_check_packet(buf) \
|
#define debug_check_packet(buf) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -67,17 +73,23 @@ static inline void net_context_send_cb(struct net_context *context,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iface_send_data(struct net_if *iface, struct net_buf *buf)
|
static bool net_if_tx(struct net_if *iface)
|
||||||
{
|
{
|
||||||
const struct net_if_api *api = iface->dev->driver_api;
|
const struct net_if_api *api = iface->dev->driver_api;
|
||||||
struct net_linkaddr *dst;
|
struct net_linkaddr *dst;
|
||||||
struct net_context *context;
|
struct net_context *context;
|
||||||
|
struct net_buf *buf;
|
||||||
void *context_token;
|
void *context_token;
|
||||||
int status;
|
int status;
|
||||||
#if defined(CONFIG_NET_STATISTICS)
|
#if defined(CONFIG_NET_STATISTICS)
|
||||||
size_t pkt_len;
|
size_t pkt_len;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
buf = net_buf_get(&iface->tx_queue, K_NO_WAIT);
|
||||||
|
if (!buf) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
debug_check_packet(buf);
|
debug_check_packet(buf);
|
||||||
|
|
||||||
dst = net_nbuf_ll_dst(buf);
|
dst = net_nbuf_ll_dst(buf);
|
||||||
|
@ -109,6 +121,8 @@ static void iface_send_data(struct net_if *iface, struct net_buf *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
net_if_call_link_cb(iface, dst, status);
|
net_if_call_link_cb(iface, dst, status);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void net_if_flush_tx(struct net_if *iface)
|
static void net_if_flush_tx(struct net_if *iface)
|
||||||
|
@ -126,56 +140,88 @@ static void net_if_flush_tx(struct net_if *iface)
|
||||||
k_yield();
|
k_yield();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct net_buf *buf;
|
if (!net_if_tx(iface)) {
|
||||||
|
|
||||||
buf = net_buf_get(&iface->tx_queue, K_NO_WAIT);
|
|
||||||
if (!buf) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
iface_send_data(iface, buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void net_if_tx_thread(struct net_if *iface)
|
static void net_if_process_events(struct k_poll_event *event, int ev_count)
|
||||||
{
|
{
|
||||||
const struct net_if_api *api = iface->dev->driver_api;
|
for (; ev_count; event++, ev_count--) {
|
||||||
|
switch (event->state) {
|
||||||
|
case K_POLL_STATE_SIGNALED:
|
||||||
|
break;
|
||||||
|
case K_POLL_STATE_FIFO_DATA_AVAILABLE:
|
||||||
|
{
|
||||||
|
struct net_if *iface;
|
||||||
|
|
||||||
NET_ASSERT(api && api->init && api->send);
|
iface = CONTAINER_OF(event->fifo, struct net_if,
|
||||||
|
tx_queue);
|
||||||
|
net_if_tx(iface);
|
||||||
|
|
||||||
NET_DBG("Starting TX thread (stack %zu bytes) for driver %p queue %p",
|
break;
|
||||||
sizeof(iface->tx_stack), api, &iface->tx_queue);
|
}
|
||||||
|
case K_POLL_STATE_NOT_READY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
api->init(iface);
|
static int net_if_prepare_events(void)
|
||||||
/* Attempt to bring the interface up */
|
{
|
||||||
net_if_up(iface);
|
struct net_if *iface;
|
||||||
|
int ev_count = 0;
|
||||||
|
|
||||||
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
||||||
|
if (!atomic_test_bit(iface->flags, NET_IF_UP)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_poll_event_init(&__net_if_event_start[ev_count],
|
||||||
|
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
||||||
|
K_POLL_MODE_NOTIFY_ONLY,
|
||||||
|
&iface->tx_queue);
|
||||||
|
ev_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ev_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void net_if_tx_thread(void)
|
||||||
|
{
|
||||||
|
NET_DBG("Starting TX thread (stack %zu bytes)",
|
||||||
|
CONFIG_NET_TX_STACK_SIZE);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct net_buf *buf;
|
int ev_count;
|
||||||
|
|
||||||
/* Get next packet from application - wait if necessary */
|
ev_count = net_if_prepare_events();
|
||||||
buf = net_buf_get(&iface->tx_queue, K_FOREVER);
|
|
||||||
|
|
||||||
iface_send_data(iface, buf);
|
k_poll(__net_if_event_start, ev_count, K_FOREVER);
|
||||||
|
|
||||||
net_analyze_stack("TX thread", iface->tx_stack,
|
net_if_process_events(__net_if_event_start, ev_count);
|
||||||
sizeof(iface->tx_stack));
|
|
||||||
net_nbuf_print();
|
|
||||||
|
|
||||||
k_yield();
|
k_yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void init_tx_queue(struct net_if *iface)
|
static inline void init_iface(struct net_if *iface)
|
||||||
{
|
{
|
||||||
|
const struct net_if_api *api = iface->dev->driver_api;
|
||||||
|
|
||||||
|
NET_ASSERT(api && api->init && api->send);
|
||||||
|
|
||||||
NET_DBG("On iface %p", iface);
|
NET_DBG("On iface %p", iface);
|
||||||
|
|
||||||
k_fifo_init(&iface->tx_queue);
|
k_fifo_init(&iface->tx_queue);
|
||||||
|
|
||||||
k_thread_spawn(iface->tx_stack, sizeof(iface->tx_stack),
|
api->init(iface);
|
||||||
(k_thread_entry_t)net_if_tx_thread,
|
|
||||||
iface, NULL, NULL, K_PRIO_COOP(7),
|
/* Attempt to bring the interface up */
|
||||||
K_ESSENTIAL, K_NO_WAIT);
|
net_if_up(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum net_verdict net_if_send_data(struct net_if *iface, struct net_buf *buf)
|
enum net_verdict net_if_send_data(struct net_if *iface, struct net_buf *buf)
|
||||||
|
@ -1561,7 +1607,7 @@ void net_if_init(void)
|
||||||
NET_DBG("");
|
NET_DBG("");
|
||||||
|
|
||||||
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
||||||
init_tx_queue(iface);
|
init_iface(iface);
|
||||||
|
|
||||||
#if defined(CONFIG_NET_IPV4)
|
#if defined(CONFIG_NET_IPV4)
|
||||||
iface->ttl = CONFIG_NET_INITIAL_TTL;
|
iface->ttl = CONFIG_NET_INITIAL_TTL;
|
||||||
|
@ -1575,6 +1621,11 @@ void net_if_init(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
k_thread_spawn(tx_stack, sizeof(tx_stack),
|
||||||
|
(k_thread_entry_t)net_if_tx_thread,
|
||||||
|
NULL, NULL, NULL, K_PRIO_COOP(7),
|
||||||
|
K_ESSENTIAL, K_NO_WAIT);
|
||||||
|
|
||||||
/* RPL init must be done after the network interface is up
|
/* RPL init must be done after the network interface is up
|
||||||
* as the RPL code wants to add multicast address to interface.
|
* as the RPL code wants to add multicast address to interface.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -76,29 +76,6 @@ static inline const char *addrstate2str(enum net_addr_state addr_state)
|
||||||
return "<invalid state>";
|
return "<invalid state>";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tx_stack(struct net_if *iface, unsigned char *stack,
|
|
||||||
size_t stack_size)
|
|
||||||
{
|
|
||||||
ARG_UNUSED(iface);
|
|
||||||
|
|
||||||
#if defined(CONFIG_INIT_STACKS)
|
|
||||||
unsigned int stack_offset, pcnt, unused;
|
|
||||||
|
|
||||||
net_analyze_stack_get_values(stack, stack_size,
|
|
||||||
&stack_offset, &pcnt, &unused);
|
|
||||||
|
|
||||||
printk("TX stack size %zu/%zu bytes unused %u usage %zu/%zu (%u %%)\n",
|
|
||||||
stack_size,
|
|
||||||
stack_size + stack_offset, unused,
|
|
||||||
stack_size - unused, stack_size, pcnt);
|
|
||||||
#else
|
|
||||||
ARG_UNUSED(stack_size);
|
|
||||||
ARG_UNUSED(stack);
|
|
||||||
|
|
||||||
printk("TX stack usage not available.\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iface_cb(struct net_if *iface, void *user_data)
|
static void iface_cb(struct net_if *iface, void *user_data)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_NET_IPV6)
|
#if defined(CONFIG_NET_IPV6)
|
||||||
|
@ -114,8 +91,6 @@ static void iface_cb(struct net_if *iface, void *user_data)
|
||||||
printk("Interface %p\n", iface);
|
printk("Interface %p\n", iface);
|
||||||
printk("====================\n");
|
printk("====================\n");
|
||||||
|
|
||||||
tx_stack(iface, iface->tx_stack, CONFIG_NET_TX_STACK_SIZE);
|
|
||||||
|
|
||||||
printk("Link addr : %s\n", net_sprint_ll_addr(iface->link_addr.addr,
|
printk("Link addr : %s\n", net_sprint_ll_addr(iface->link_addr.addr,
|
||||||
iface->link_addr.len));
|
iface->link_addr.len));
|
||||||
printk("MTU : %d\n", iface->mtu);
|
printk("MTU : %d\n", iface->mtu);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue