Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Mar 2017 13:51:14 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r314853 - head/sys/compat/linuxkpi/common/src
Message-ID:  <201703071351.v27DpEpT074899@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 {
 		/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703071351.v27DpEpT074899>