diff --git a/scripts/Makefile.package b/scripts/Makefile.package
index 5538deacb136..50b86b325d7a 100644
--- a/scripts/Makefile.package
+++ b/scripts/Makefile.package
@@ -50,10 +50,25 @@ quiet_cmd_tar = TAR     $@
 
 tar-rootdir := $(srctree)
 
+%.tar:
+	$(call cmd,tar)
+
 %.tar.gz: private tar-compress-opt := -I $(KGZIP)
 %.tar.gz:
 	$(call cmd,tar)
 
+%.tar.bz2: private tar-compress-opt := -I $(KBZIP2)
+%.tar.bz2:
+	$(call cmd,tar)
+
+%.tar.xz: private tar-compress-opt := -I $(XZ)
+%.tar.xz:
+	$(call cmd,tar)
+
+%.tar.zst: private tar-compress-opt := -I $(ZSTD)
+%.tar.zst:
+	$(call cmd,tar)
+
 # Linux source tarball
 # ---------------------------------------------------------------------------
 
@@ -138,36 +153,52 @@ $(tar-pkgs):
 	$(MAKE) -f $(srctree)/Makefile
 	+$(CONFIG_SHELL) $(srctree)/scripts/package/buildtar $@
 
-# perf-pkg - generate a source tarball with perf source
+# perf-tar*-src-pkg - generate a source tarball with perf source
 # ---------------------------------------------------------------------------
 
-perf-tar=perf-$(KERNELVERSION)
-
-quiet_cmd_perf_tar = TAR
-      cmd_perf_tar = \
-git --git-dir=$(srctree)/.git archive --prefix=$(perf-tar)/         \
-	HEAD^{tree} $$(cd $(srctree);                               \
-		       echo $$(cat tools/perf/MANIFEST)) \
-	-o $(perf-tar).tar;                                         \
-mkdir -p $(perf-tar);                                               \
-git --git-dir=$(srctree)/.git rev-parse HEAD > $(perf-tar)/HEAD;    \
-(cd $(srctree)/tools/perf;                                          \
-util/PERF-VERSION-GEN $(CURDIR)/$(perf-tar)/);              \
-tar rf $(perf-tar).tar $(perf-tar)/HEAD $(perf-tar)/PERF-VERSION-FILE; \
-rm -r $(perf-tar);                                                  \
-$(if $(findstring tar-src,$@),,                                     \
-$(if $(findstring bz2,$@),$(KBZIP2),                                 \
-$(if $(findstring gz,$@),$(KGZIP),                                  \
-$(if $(findstring xz,$@),$(XZ),                                     \
-$(if $(findstring zst,$@),$(ZSTD),                                  \
-$(error unknown target $@)))))                                      \
-	-f -9 $(perf-tar).tar)
-
-perf-tar-pkgs := perf-tar-src-pkg perf-targz-src-pkg perf-tarbz2-src-pkg \
-		 perf-tarxz-src-pkg perf-tarzst-src-pkg
-PHONY += $(perf-tar-pkgs)
-$(perf-tar-pkgs):
-	$(call cmd,perf_tar)
+perf-tar-src-pkg-tarball = perf-$(KERNELVERSION).$(1)
+perf-tar-src-pkg-phony   = perf-$(subst .,,$(1))-src-pkg
+
+quiet_cmd_stage_perf_src = STAGE   $@
+      cmd_stage_perf_src = \
+	rm -rf $@; \
+	mkdir -p $@; \
+	tar -c -f - --exclude-from=$<_exclude -C $(srctree) --files-from=$(srctree)/tools/perf/MANIFEST | \
+	tar -x -f - -C $@
+
+.tmp_perf: .tmp_filelist
+	$(call cmd,stage_perf_src)
+
+filechk_perf_head = \
+	if test -z "$(git -C $(srctree) rev-parse --show-cdup 2>/dev/null)" && \
+	       head=$$(git -C $(srctree) rev-parse --verify HEAD 2>/dev/null); then \
+		echo $$head; \
+	else \
+		echo "not a git tree"; \
+	fi
+
+.tmp_perf/HEAD: .tmp_perf FORCE
+	$(call filechk,perf_head)
+
+quiet_cmd_perf_version_file = GEN     $@
+      cmd_perf_version_file = cd $(srctree)/tools/perf; util/PERF-VERSION-GEN $(dir $(abspath $@))
+
+# PERF-VERSION-FILE and HEAD are independent, but this avoids updating the
+# timestamp of PERF-VERSION-FILE.
+# The best is to fix tools/perf/util/PERF-VERSION-GEN.
+.tmp_perf/PERF-VERSION-FILE: .tmp_perf/HEAD $(srctree)/tools/perf/util/PERF-VERSION-GEN
+	$(call cmd,perf_version_file)
+
+define perf-tar-src-pkg-rule
+PHONY += $(perf-tar-src-pkg-phony)
+$(perf-tar-src-pkg-phony): $(perf-tar-src-pkg-tarball)
+	@:
+
+$(perf-tar-src-pkg-tarball): private tar-rootdir := .tmp_perf
+$(perf-tar-src-pkg-tarball): .tmp_filelist .tmp_perf/HEAD .tmp_perf/PERF-VERSION-FILE
+endef
+
+$(foreach x, tar tar.gz tar.bz2 tar.xz tar.zst, $(eval $(call perf-tar-src-pkg-rule,$(x))))
 
 # Help text displayed when executing 'make help'
 # ---------------------------------------------------------------------------
@@ -186,11 +217,11 @@ help:
 	@echo '  tarbz2-pkg          - Build the kernel as a bzip2 compressed tarball'
 	@echo '  tarxz-pkg           - Build the kernel as a xz compressed tarball'
 	@echo '  tarzst-pkg          - Build the kernel as a zstd compressed tarball'
-	@echo '  perf-tar-src-pkg    - Build $(perf-tar).tar source tarball'
-	@echo '  perf-targz-src-pkg  - Build $(perf-tar).tar.gz source tarball'
-	@echo '  perf-tarbz2-src-pkg - Build $(perf-tar).tar.bz2 source tarball'
-	@echo '  perf-tarxz-src-pkg  - Build $(perf-tar).tar.xz source tarball'
-	@echo '  perf-tarzst-src-pkg - Build $(perf-tar).tar.zst source tarball'
+	@echo '  perf-tar-src-pkg    - Build the perf source tarball with no compression'
+	@echo '  perf-targz-src-pkg  - Build the perf source tarball with gzip compression'
+	@echo '  perf-tarbz2-src-pkg - Build the perf source tarball with bz2 compression'
+	@echo '  perf-tarxz-src-pkg  - Build the perf source tarball with xz compression'
+	@echo '  perf-tarzst-src-pkg - Build the perf source tarball with zst compression'
 
 PHONY += FORCE
 FORCE:
