diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index c2064a35688b..69bb25f7b3b8 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -10,15 +10,10 @@ TARGETS += core
 TARGETS += cpufreq
 TARGETS += cpu-hotplug
 TARGETS += damon
-TARGETS += drivers/dma-buf
-TARGETS += drivers/s390x/uvdevice
-TARGETS += drivers/net/bonding
+TARGETS += drivers
 TARGETS += efivarfs
 TARGETS += exec
 TARGETS += filesystems
-TARGETS += filesystems/binderfs
-TARGETS += filesystems/epoll
-TARGETS += filesystems/fat
 TARGETS += firmware
 TARGETS += fpu
 TARGETS += ftrace
@@ -44,9 +39,6 @@ TARGETS += move_mount_set_group
 TARGETS += mqueue
 TARGETS += nci
 TARGETS += net
-TARGETS += net/af_unix
-TARGETS += net/forwarding
-TARGETS += net/mptcp
 TARGETS += netfilter
 TARGETS += nsfs
 TARGETS += pidfd
@@ -93,16 +85,14 @@ TARGETS_HOTPLUG += memory-hotplug
 # BPF since it has cutting edge build time dependencies which require
 # more effort to install.
 SKIP_TARGETS ?= bpf
-ifneq ($(SKIP_TARGETS),)
-	TMP := $(filter-out $(SKIP_TARGETS), $(TARGETS))
-	override TARGETS := $(TMP)
-endif
+export SKIP_TARGETS
 
 # User can set FORCE_TARGETS to 1 to require all targets to be successfully
 # built; make will fail if any of the targets cannot be built. If
 # FORCE_TARGETS is not set (the default), make will succeed if at least one
 # of the targets gets built.
 FORCE_TARGETS ?=
+export FORCE_TARGETS
 
 # Clear LDFLAGS and MAKEFLAGS when implicit rules are missing.  This provides
 # implicit rules to sub-test Makefiles which avoids build failures in test
@@ -145,6 +135,7 @@ endif
 # Prepare for headers install
 include $(top_srcdir)/scripts/subarch.include
 ARCH           ?= $(SUBARCH)
+export abs_objtree
 export BUILD
 export KHDR_INCLUDES
 
@@ -152,23 +143,7 @@ export KHDR_INCLUDES
 # all isn't the first target in the file.
 .DEFAULT_GOAL := all
 
-all:
-	@ret=1;							\
-	for TARGET in $(TARGETS); do				\
-		BUILD_TARGET=$$BUILD/$$TARGET;			\
-		mkdir $$BUILD_TARGET  -p;			\
-		$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET	\
-				O=$(abs_objtree)		\
-				$(if $(FORCE_TARGETS),|| exit);	\
-		ret=$$((ret * $$?));				\
-	done; exit $$ret;
-
-run_tests: all
-	@for TARGET in $(TARGETS); do \
-		BUILD_TARGET=$$BUILD/$$TARGET;	\
-		$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests \
-				O=$(abs_objtree);		    \
-	done;
+OUTPUT := $(BUILD)
 
 hotplug:
 	@for TARGET in $(TARGETS_HOTPLUG); do \
@@ -204,8 +179,9 @@ KSFT_INSTALL_PATH := $(abspath $(KSFT_INSTALL_PATH))
 INSTALL_PATH := $(KSFT_INSTALL_PATH)
 ALL_SCRIPT := $(INSTALL_PATH)/run_kselftest.sh
 TEST_LIST := $(INSTALL_PATH)/kselftest-list.txt
+export TEST_LIST
 
-install: all
+main_install: all
 ifdef INSTALL_PATH
 	@# Ask all targets to install their files
 	mkdir -p $(INSTALL_PATH)/kselftest
@@ -214,31 +190,14 @@ ifdef INSTALL_PATH
 	install -m 744 kselftest/prefix.pl $(INSTALL_PATH)/kselftest/
 	install -m 744 run_kselftest.sh $(INSTALL_PATH)/
 	rm -f $(TEST_LIST)
-	@ret=1;	\
-	for TARGET in $(TARGETS); do \
-		BUILD_TARGET=$$BUILD/$$TARGET;	\
-		$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install \
-				O=$(abs_objtree)		\
-				$(if $(FORCE_TARGETS),|| exit);	\
-		ret=$$((ret * $$?));		\
-	done; exit $$ret;
-
-
-	@# Ask all targets to emit their test scripts
-	@# While building kselftest-list.text skip also non-existent TARGET dirs:
-	@# they could be the result of a build failure and should NOT be
-	@# included in the generated runlist.
-	for TARGET in $(TARGETS); do \
-		BUILD_TARGET=$$BUILD/$$TARGET;	\
-		[ ! -d $(INSTALL_PATH)/$$TARGET ] && echo "Skipping non-existent dir: $$TARGET" && continue; \
-		echo -ne "Emit Tests for $$TARGET\n"; \
-		$(MAKE) -s --no-print-directory OUTPUT=$$BUILD_TARGET COLLECTION=$$TARGET \
-			-C $$TARGET emit_tests >> $(TEST_LIST); \
-	done;
 else
 	$(error Error: set INSTALL_PATH to use install)
 endif
 
+include lib.mk
+
+install: main_install
+
 FORMAT ?= .gz
 TAR_PATH = $(abspath ${INSTALL_PATH}/kselftest-packages/kselftest.tar${FORMAT})
 gen_tar: install
@@ -246,10 +205,4 @@ gen_tar: install
 	@tar caf ${TAR_PATH} --exclude=kselftest-packages -C ${INSTALL_PATH} .
 	@echo "Created ${TAR_PATH}"
 
-clean:
-	@for TARGET in $(TARGETS); do \
-		BUILD_TARGET=$$BUILD/$$TARGET;	\
-		$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\
-	done;
-
-.PHONY: all run_tests hotplug run_hotplug clean_hotplug run_pstore_crash install clean gen_tar
+.PHONY: run_tests hotplug run_hotplug clean_hotplug run_pstore_crash gen_tar
diff --git a/tools/testing/selftests/drivers/Makefile b/tools/testing/selftests/drivers/Makefile
new file mode 100644
index 000000000000..4d4693c8efbc
--- /dev/null
+++ b/tools/testing/selftests/drivers/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+TARGETS += dma-buf
+TARGETS += s390x/uvdevice
+TARGETS += net/bonding
+
+include ../lib.mk
diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile
index 129880fb42d3..04fde0107d7a 100644
--- a/tools/testing/selftests/filesystems/Makefile
+++ b/tools/testing/selftests/filesystems/Makefile
@@ -4,4 +4,8 @@ CFLAGS += -I../../../../usr/include/
 TEST_GEN_PROGS := devpts_pts
 TEST_GEN_PROGS_EXTENDED := dnotify_test
 
+TARGETS += binderfs
+TARGETS += epoll
+TARGETS += fat
+
 include ../lib.mk
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index d44c72b3abe3..026a0c5b02e1 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -33,14 +33,17 @@ else
 CC := $(CROSS_COMPILE)gcc
 endif # LLVM
 
+pwd=$(shell pwd)
 ifeq (0,$(MAKELEVEL))
     ifeq ($(OUTPUT),)
-	OUTPUT := $(shell pwd)
+	OUTPUT := $(pwd)
 	DEFAULT_INSTALL_HDR_PATH := 1
     endif
 endif
 selfdir = $(realpath $(dir $(filter %/lib.mk,$(MAKEFILE_LIST))))
 top_srcdir = $(selfdir)/../../..
+testdir = $(pwd:$(selfdir)/%=%)
+export OUTPUT
 
 # The following are built by lib.mk common compile rules.
 # TEST_CUSTOM_PROGS should be used by tests that require
@@ -52,7 +55,24 @@ TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS))
 TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED))
 TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES))
 
+ifneq ($(SKIP_TARGETS),)
+        TARGETS_REL := $(patsubst %,$(testdir)/%,$(TARGETS))
+        TMP := $(filter-out $(SKIP_TARGETS),$(TARGETS_REL))
+        override TARGETS := $(TMP:$(testdir)/%=%)
+endif
+
 all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
+ifneq ($(TARGETS),)
+	@ret=1;							\
+	for TARGET in $(TARGETS); do				\
+		BUILD_TARGET=$$OUTPUT/$$TARGET;			\
+		mkdir $$BUILD_TARGET  -p;			\
+		$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET	\
+				O=$(abs_objtree)		\
+				$(if $(FORCE_TARGETS),|| exit);	\
+		ret=$$((ret * $$?));				\
+	done; exit $$ret;
+endif
 
 define RUN_TESTS
 	BASE_DIR="$(selfdir)";			\
@@ -77,6 +97,13 @@ ifdef building_out_of_srctree
 else
 	@$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS))
 endif
+ifneq ($(TARGETS),)
+	@for TARGET in $(TARGETS); do \
+		BUILD_TARGET=$$OUTPUT/$$TARGET;	\
+		$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests \
+				O=$(abs_objtree);		    \
+	done;
+endif
 
 define INSTALL_SINGLE_RULE
 	$(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH))
@@ -97,6 +124,29 @@ endef
 install: all
 ifdef INSTALL_PATH
 	$(INSTALL_RULE)
+ifneq ($(TARGETS),)
+	@ret=1;	\
+	for TARGET in $(TARGETS); do \
+		BUILD_TARGET=$$OUTPUT/$$TARGET;	\
+		$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install \
+				O=$(abs_objtree)		\
+				$(if $(FORCE_TARGETS),|| exit);	\
+		ret=$$((ret * $$?));		\
+	done; exit $$ret;
+
+
+	@# Ask all targets to emit their test scripts
+	@# While building kselftest-list.text skip also non-existent TARGET dirs:
+	@# they could be the result of a build failure and should NOT be
+	@# included in the generated runlist.
+	for TARGET in $(TARGETS); do \
+		BUILD_TARGET=$$OUTPUT/$$TARGET;	\
+		[ ! -d $(INSTALL_PATH)/$$TARGET ] && echo "Skipping non-existent dir: $$TARGET" && continue; \
+		echo -ne "Emit Tests for $$TARGET\n"; \
+		$(MAKE) -s --no-print-directory OUTPUT=$$BUILD_TARGET COLLECTION=$$TARGET \
+			-C $$TARGET emit_tests >> $(TEST_LIST); \
+	done;
+endif # ifneq ($(TARGETS),)
 else
 	$(error Error: set INSTALL_PATH to use install)
 endif
@@ -118,6 +168,13 @@ endef
 
 clean:
 	$(CLEAN)
+ifneq ($(TARGETS),)
+	@for TARGET in $(TARGETS); do \
+		BUILD_TARGET=$$OUTPUT/$$TARGET;	\
+		$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\
+	done;
+endif
+
 
 # When make O= with kselftest target from main level
 # the following aren't defined.
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index c0ee2955fe54..ef768c0992f5 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -66,6 +66,10 @@ TEST_GEN_FILES += io_uring_zerocopy_tx
 
 TEST_FILES := settings
 
+TARGETS += af_unix
+TARGETS += forwarding
+TARGETS += mptcp
+
 include ../lib.mk
 
 include bpf/Makefile
