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.*")
|
||||
KEEP(*(SORT_BY_NAME(".net_if*")))
|
||||
KEEP(*(SORT_BY_NAME(".net_if.*")))
|
||||
__net_if_end = .;
|
||||
} 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)
|
||||
SECTION_DATA_PROLOGUE(net_stack, (OPTIONAL),)
|
||||
{
|
||||
|
|
|
@ -203,12 +203,6 @@ struct net_if {
|
|||
/** Queue for outgoing packets from apps */
|
||||
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)
|
||||
#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
|
||||
|
@ -1190,6 +1184,9 @@ struct net_if_api {
|
|||
#endif
|
||||
|
||||
#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) \
|
||||
((struct net_if *)&NET_IF_GET_NAME(dev_name, sfx))
|
||||
|
||||
|
@ -1202,12 +1199,9 @@ struct net_if_api {
|
|||
.mtu = _mtu, \
|
||||
NET_IF_DHCPV4_INIT \
|
||||
}; \
|
||||
NET_STACK_INFO_ADDR(TX, \
|
||||
dev_name, \
|
||||
CONFIG_NET_TX_STACK_SIZE, \
|
||||
CONFIG_NET_TX_STACK_SIZE, \
|
||||
NET_IF_GET(dev_name, sfx)->tx_stack, \
|
||||
sfx)
|
||||
static struct k_poll_event \
|
||||
(NET_IF_EVENT_GET_NAME(dev_name, sfx)) __used \
|
||||
__attribute__((__section__(".net_if_event.data"))) = {}
|
||||
|
||||
|
||||
/* Network device initialization macros */
|
||||
|
|
|
@ -470,7 +470,7 @@ class SizeCalculator:
|
|||
"_k_sem_area", "_k_mutex_area", "_k_alert_area",
|
||||
"_k_fifo_area", "_k_lifo_area", "_k_stack_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"]
|
||||
# These get copied into RAM only on non-XIP
|
||||
ro_sections = ["text", "ctors", "init_array", "reset",
|
||||
|
|
|
@ -61,6 +61,7 @@ config NET_BUF_POOL_USAGE
|
|||
config NETWORKING
|
||||
bool "Link layer and IP networking support"
|
||||
select NET_BUF
|
||||
select POLL
|
||||
select RANDOM_GENERATOR
|
||||
default n
|
||||
help
|
||||
|
|
|
@ -33,12 +33,18 @@
|
|||
extern struct net_if __net_if_start[];
|
||||
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];
|
||||
|
||||
/* We keep track of the link callbacks in this list.
|
||||
*/
|
||||
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)
|
||||
#define debug_check_packet(buf) \
|
||||
{ \
|
||||
|
@ -67,17 +73,23 @@ static inline void net_context_send_cb(struct net_context *context,
|
|||
#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;
|
||||
struct net_linkaddr *dst;
|
||||
struct net_context *context;
|
||||
struct net_buf *buf;
|
||||
void *context_token;
|
||||
int status;
|
||||
#if defined(CONFIG_NET_STATISTICS)
|
||||
size_t pkt_len;
|
||||
#endif
|
||||
|
||||
buf = net_buf_get(&iface->tx_queue, K_NO_WAIT);
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
debug_check_packet(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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
while (1) {
|
||||
struct net_buf *buf;
|
||||
|
||||
buf = net_buf_get(&iface->tx_queue, K_NO_WAIT);
|
||||
if (!buf) {
|
||||
if (!net_if_tx(iface)) {
|
||||
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",
|
||||
sizeof(iface->tx_stack), api, &iface->tx_queue);
|
||||
break;
|
||||
}
|
||||
case K_POLL_STATE_NOT_READY:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
api->init(iface);
|
||||
/* Attempt to bring the interface up */
|
||||
net_if_up(iface);
|
||||
static int net_if_prepare_events(void)
|
||||
{
|
||||
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) {
|
||||
struct net_buf *buf;
|
||||
int ev_count;
|
||||
|
||||
/* Get next packet from application - wait if necessary */
|
||||
buf = net_buf_get(&iface->tx_queue, K_FOREVER);
|
||||
ev_count = net_if_prepare_events();
|
||||
|
||||
iface_send_data(iface, buf);
|
||||
k_poll(__net_if_event_start, ev_count, K_FOREVER);
|
||||
|
||||
net_analyze_stack("TX thread", iface->tx_stack,
|
||||
sizeof(iface->tx_stack));
|
||||
net_nbuf_print();
|
||||
net_if_process_events(__net_if_event_start, ev_count);
|
||||
|
||||
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);
|
||||
|
||||
k_fifo_init(&iface->tx_queue);
|
||||
|
||||
k_thread_spawn(iface->tx_stack, sizeof(iface->tx_stack),
|
||||
(k_thread_entry_t)net_if_tx_thread,
|
||||
iface, NULL, NULL, K_PRIO_COOP(7),
|
||||
K_ESSENTIAL, K_NO_WAIT);
|
||||
api->init(iface);
|
||||
|
||||
/* Attempt to bring the interface up */
|
||||
net_if_up(iface);
|
||||
}
|
||||
|
||||
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("");
|
||||
|
||||
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
||||
init_tx_queue(iface);
|
||||
init_iface(iface);
|
||||
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
iface->ttl = CONFIG_NET_INITIAL_TTL;
|
||||
|
@ -1575,6 +1621,11 @@ void net_if_init(void)
|
|||
#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
|
||||
* 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>";
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#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("====================\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,
|
||||
iface->link_addr.len));
|
||||
printk("MTU : %d\n", iface->mtu);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue