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:
Tomasz Bursztyka 2017-03-08 09:30:03 +01:00 committed by Jukka Rissanen
commit e38a9e8b9c
6 changed files with 96 additions and 67 deletions

View file

@ -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),)
{ {

View file

@ -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 */

View file

@ -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",

View file

@ -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

View file

@ -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.
*/ */

View file

@ -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);