diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b8c855083a8..f7be17a327d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -20,6 +20,31 @@ menuconfig NETDEVICES if NETDEVICES +comment "Upper-half Network Device Driver Options" + +choice + prompt "Netdev poll worker" + +config NETDEV_LPWORK_THREAD + bool "Use low-priority worker thread to do netdev poll" + depends on SCHED_LPWORK + +config NETDEV_HPWORK_THREAD + bool "Use high-priority worker thread to do netdev poll" + depends on SCHED_HPWORK + +config NETDEV_WORK_THREAD + bool "Use a dedicated work thread to do netdev poll" + +endchoice # Netdev poll worker + +config NETDEV_WORK_THREAD_PRIORITY + int "Priority of work poll thread" + default 100 + depends on NETDEV_WORK_THREAD + ---help--- + The priority of work poll thread in netdev. + comment "General Ethernet MAC Driver Options" config NET_RPMSG_DRV diff --git a/drivers/net/netdev_upperhalf.c b/drivers/net/netdev_upperhalf.c index ebae685d653..08f065fd26d 100644 --- a/drivers/net/netdev_upperhalf.c +++ b/drivers/net/netdev_upperhalf.c @@ -27,13 +27,16 @@ #include #include #include +#include #include #include +#include #include #include #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -41,6 +44,14 @@ #define NETDEV_TX_CONTINUE 1 /* Return value for devif_poll */ +#define NETDEV_THREAD_NAME_FMT "netdev-%s" + +#ifdef CONFIG_NETDEV_HPWORK_THREAD +# define NETDEV_WORK HPWORK +#else +# define NETDEV_WORK LPWORK +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -51,7 +62,15 @@ struct netdev_upperhalf_s { FAR struct netdev_lowerhalf_s *lower; - struct work_s work; /* Deferring poll work to the work queue */ + /* Deferring poll work to work queue or thread */ + +#ifdef CONFIG_NETDEV_WORK_THREAD + pid_t tid; + sem_t sem; + sem_t sem_exit; +#else + struct work_s work; +#endif }; /**************************************************************************** @@ -394,9 +413,6 @@ static void netdev_upper_rxpoll_work(FAR struct netdev_upperhalf_s *upper) * Input Parameters: * arg - Reference to the upper half driver structure (cast to void *) * - * TODO: - * Support working in a dedicated thread. - * ****************************************************************************/ static void netdev_upper_work(FAR void *arg) @@ -411,6 +427,31 @@ static void netdev_upper_work(FAR void *arg) net_unlock(); } +/**************************************************************************** + * Name: netdev_upper_loop + * + * Description: + * The loop for dedicated thread. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_WORK_THREAD +static int netdev_upper_loop(int argc, FAR char *argv[]) +{ + FAR struct netdev_upperhalf_s *upper = + (FAR struct netdev_upperhalf_s *)((uintptr_t)strtoul(argv[1], NULL, 16)); + + while (nxsem_wait(&upper->sem) == OK && upper->tid != INVALID_PROCESS_ID) + { + netdev_upper_work(upper); + } + + nwarn("WARNING: Netdev work thread quitting."); + nxsem_post(&upper->sem_exit); + return 0; +} +#endif + /**************************************************************************** * Name: netdev_upper_queue_work * @@ -426,14 +467,20 @@ static inline void netdev_upper_queue_work(FAR struct net_driver_s *dev) { FAR struct netdev_upperhalf_s *upper = dev->d_private; - /* TODO: support trigger thread. */ - +#ifdef CONFIG_NETDEV_WORK_THREAD + int semcount; + if (nxsem_get_value(&upper->sem, &semcount) == OK && semcount <= 0) + { + nxsem_post(&upper->sem); + } +#else if (work_available(&upper->work)) { /* Schedule to serialize the poll on the worker thread. */ - work_queue(LPWORK, &upper->work, netdev_upper_work, upper, 0); + work_queue(NETDEV_WORK, &upper->work, netdev_upper_work, upper, 0); } +#endif } /**************************************************************************** @@ -465,7 +512,29 @@ static int netdev_upper_ifup(FAR struct net_driver_s *dev) { FAR struct netdev_upperhalf_s *upper = dev->d_private; - /* TODO: bring up a dedicated thread for work? */ +#ifdef CONFIG_NETDEV_WORK_THREAD + /* Try to bring up a dedicated thread for work. */ + + if (upper->tid <= 0) + { + FAR char *argv[2]; + char arg1[32]; + char name[32]; + + snprintf(arg1, sizeof(arg1), "%p", upper); + snprintf(name, sizeof(name), NETDEV_THREAD_NAME_FMT, dev->d_ifname); + argv[0] = arg1; + argv[1] = NULL; + + upper->tid = kthread_create(name, CONFIG_NETDEV_WORK_THREAD_PRIORITY, + CONFIG_DEFAULT_TASK_STACKSIZE, + netdev_upper_loop, argv); + if (upper->tid < 0) + { + return upper->tid; + } + } +#endif if (upper->lower->ops->ifup) { @@ -479,9 +548,9 @@ static int netdev_upper_ifdown(FAR struct net_driver_s *dev) { FAR struct netdev_upperhalf_s *upper = dev->d_private; - /* TODO: Support dedicated thread? */ - - work_cancel(LPWORK, &upper->work); +#ifndef CONFIG_NETDEV_WORK_THREAD + work_cancel(NETDEV_WORK, &upper->work); +#endif if (upper->lower->ops->ifdown) { @@ -593,6 +662,11 @@ int netdev_lower_register(FAR struct netdev_lowerhalf_s *dev, dev->netdev.d_private = NULL; } +#ifdef CONFIG_NETDEV_WORK_THREAD + nxsem_init(&upper->sem, 0, 0); + nxsem_init(&upper->sem_exit, 0, 0); +#endif + return ret; } @@ -627,6 +701,20 @@ int netdev_lower_unregister(FAR struct netdev_lowerhalf_s *dev) return ret; } +#ifdef CONFIG_NETDEV_WORK_THREAD + if (upper->tid > 0) + { + /* Try to tear down the dedicated thread for work. */ + + upper->tid = INVALID_PROCESS_ID; + nxsem_post(&upper->sem); + nxsem_wait(&upper->sem_exit); + } + + nxsem_destroy(&upper->sem); + nxsem_destroy(&upper->sem_exit); +#endif + kmm_free(upper); dev->netdev.d_private = NULL;