Author: hselasky
Date: Tue Mar  7 13:51:14 2017
New Revision: 314853
URL: https://svnweb.freebsd.org/changeset/base/314853

Log:
  Use grouptaskqueue for tasklets in the LinuxKPI.
  
  This avoids creating own per-CPU threads and also ensures the tasklet
  execution happens on the same CPU core invoking the tasklet.
  
  MFC after:            1 week
  Sponsored by:         Mellanox Technologies

Modified:
  head/sys/compat/linuxkpi/common/src/linux_tasklet.c

Modified: head/sys/compat/linuxkpi/common/src/linux_tasklet.c
==============================================================================
--- head/sys/compat/linuxkpi/common/src/linux_tasklet.c Tue Mar  7 13:41:01 
2017        (r314852)
+++ head/sys/compat/linuxkpi/common/src/linux_tasklet.c Tue Mar  7 13:51:14 
2017        (r314853)
@@ -29,12 +29,11 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
-#include <sys/taskqueue.h>
+#include <sys/gtaskqueue.h>
 #include <sys/proc.h>
 #include <sys/sched.h>
 
 #include <linux/interrupt.h>
-#include <linux/bottom_half.h>
 #include <linux/compat.h>
 
 #define        TASKLET_ST_IDLE 0
@@ -54,17 +53,16 @@ __FBSDID("$FreeBSD$");
 struct tasklet_worker {
        struct mtx mtx;
        TAILQ_HEAD(, tasklet_struct) head;
-       struct taskqueue *taskqueue;
-       struct task task;
+       struct grouptask gtask;
 } __aligned(CACHE_LINE_SIZE);
 
 #define        TASKLET_WORKER_LOCK(tw) mtx_lock(&(tw)->mtx)
 #define        TASKLET_WORKER_UNLOCK(tw) mtx_unlock(&(tw)->mtx)
 
-static struct tasklet_worker tasklet_worker;
+static DPCPU_DEFINE(struct tasklet_worker, tasklet_worker);
 
 static void
-tasklet_handler(void *arg, int pending)
+tasklet_handler(void *arg)
 {
        struct tasklet_worker *tw = (struct tasklet_worker *)arg;
        struct tasklet_struct *ts;
@@ -72,7 +70,6 @@ tasklet_handler(void *arg, int pending)
        linux_set_current(curthread);
 
        TASKLET_WORKER_LOCK(tw);
-       local_bh_disable();     /* pin thread to CPU */
        while (1) {
                ts = TAILQ_FIRST(&tw->head);
                if (ts == NULL)
@@ -89,32 +86,47 @@ tasklet_handler(void *arg, int pending)
                } while (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC, 
TASKLET_ST_IDLE) == 0);
                TASKLET_WORKER_LOCK(tw);
        }
-       local_bh_enable();      /* unpin thread from CPU */
        TASKLET_WORKER_UNLOCK(tw);
 }
 
 static void
 tasklet_subsystem_init(void *arg __unused)
 {
-       struct tasklet_worker *tw = &tasklet_worker;
-
-       tw->taskqueue = taskqueue_create("tasklet", M_WAITOK,
-           taskqueue_thread_enqueue, &tw->taskqueue);
-       mtx_init(&tw->mtx, "linux_tasklet", NULL, MTX_DEF);
-       TAILQ_INIT(&tw->head);
-       TASK_INIT(&tw->task, 0, tasklet_handler, tw);
-       taskqueue_start_threads(&tw->taskqueue, 1, PI_NET, "tasklet");
+       struct tasklet_worker *tw;
+       char buf[32];
+       int i;
+
+       CPU_FOREACH(i) {
+               if (CPU_ABSENT(i))
+                       continue;
+
+               tw = DPCPU_ID_PTR(i, tasklet_worker);
+
+               mtx_init(&tw->mtx, "linux_tasklet", NULL, MTX_DEF);
+               TAILQ_INIT(&tw->head);
+               GROUPTASK_INIT(&tw->gtask, 0, tasklet_handler, tw);
+               snprintf(buf, sizeof(buf), "softirq%d", i);
+               taskqgroup_attach_cpu(qgroup_softirq, &tw->gtask,
+                   "tasklet", i, -1, buf);
+       }
 }
 SYSINIT(linux_tasklet, SI_SUB_INIT_IF, SI_ORDER_THIRD, tasklet_subsystem_init, 
NULL);
 
 static void
 tasklet_subsystem_uninit(void *arg __unused)
 {
-       struct tasklet_worker *tw = &tasklet_worker;
+       struct tasklet_worker *tw;
+       int i;
+
+       CPU_FOREACH(i) {
+               if (CPU_ABSENT(i))
+                       continue;
+
+               tw = DPCPU_ID_PTR(i, tasklet_worker);
 
-       taskqueue_free(tw->taskqueue);
-       tw->taskqueue = NULL;
-       mtx_destroy(&tw->mtx);
+               taskqgroup_detach(qgroup_softirq, &tw->gtask);
+               mtx_destroy(&tw->mtx);
+       }
 }
 SYSUNINIT(linux_tasklet, SI_SUB_INIT_IF, SI_ORDER_THIRD, 
tasklet_subsystem_uninit, NULL);
 
@@ -147,14 +159,16 @@ tasklet_schedule(struct tasklet_struct *
        if (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC, TASKLET_ST_LOOP)) {
                /* tasklet_handler() will loop */
        } else if (TASKLET_ST_CMPSET(ts, TASKLET_ST_IDLE, TASKLET_ST_BUSY)) {
-               struct tasklet_worker *tw = &tasklet_worker;
+               struct tasklet_worker *tw;
+
+               tw = &DPCPU_GET(tasklet_worker);
 
                /* tasklet_handler() was not queued */
                TASKLET_WORKER_LOCK(tw);
                /* enqueue tasklet */
                TAILQ_INSERT_TAIL(&tw->head, ts, entry);
                /* schedule worker */
-               taskqueue_enqueue(tw->taskqueue, &tw->task);
+               GROUPTASK_ENQUEUE(&tw->gtask);
                TASKLET_WORKER_UNLOCK(tw);
        } else {
                /*
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to