# This is rather strange Makefile to compile certain files under the kernel build
# system and to compile other in the normal way and it then links them

tso_test_mod-y = tx.o tx_common.o tx_tso.o tso_test_framework.o tso_pre_include.o tso_check_tx_queue.o tso_shared.o

ifdef KERNELRELEASE

# Define filechk if necessary
ifndef filechk
define filechk
	$(Q)set -e;                             \
	$(if Q,echo '  CHK     $@';)            \
	mkdir -p $(dir $@);                     \
	$(filechk_$(1)) < $< > $@.tmp;          \
	if [ -r $@ ] && cmp -s $@ $@.tmp; then  \
		rm -f $@.tmp;                   \
	else                                    \
		$(if Q,echo '  UPD     $@';)    \
		mv -f $@.tmp $@;                \
	fi
endef
endif

# tso_autocompat.h depends on the kernel compiled against.
# However, there is nothing stopping the user compiling on multiple
# machines in the same directory. The .kpath target provides a simple
# dependency check for this.
#
# Module(s).symvers also depends on the kernel compiled against, but
# can simply be deleted here.  However mmake does some more complicated
# management of Module.symvers and does not allow changing the kernel
# path, so don't touch it when invoked from an mmake tree.
$(obj)/.kpath: FORCE
	@if ! [ -f $@ ] || [ $$(cat $@) != $(objtree) ]; then           \
		echo $(objtree) >$@;                                    \
		$(if $(MMAKE_IN_KBUILD),,rm -f $(obj)/*.symvers;)       \
	fi

define filechk_tso_config.h
	printf "$(foreach name,SFC_TSO,#undef CONFIG_$(name)\n$(if $(filter y,$(CONFIG_$(name))),#define CONFIG_$(name) 1\n))"
endef

$(obj)/tso_config.h: $(src)/Makefile FORCE
	$(call filechk,tso_config.h)

$(addprefix $(obj)/,$(tso_test_mod-y)): \
	$(obj)/.kpath $(obj)/tso_config.h

obj-m += tso_test_mod.o

# Compiler flags - note the extra initial include
EXTRA_CFLAGS += -I$(src)/.. -I$(src)/..  -Wall
ifndef NOWERROR
EXTRA_CFLAGS += "-Werror"
endif

# Select the right warnings - complicated by working out which options work
ifndef try-run
try-run = $(shell set -e;		\
	TMP="$(obj)/.$$$$.tmp";		\
	TMPO="$(obj)/.$$$$.o";		\
	if ($(1)) >/dev/null 2>&1;	\
	then echo "$(2)";		\
	else echo "$(3)";		\
	fi;				\
	rm -f "$$TMP" "$$TMPO")
endif
ifndef cc-disable-warning
cc-disable-warning = $(call try-run,\
	$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1)))
endif
ifndef cc-option
cc-option = $(call try-run,\
        $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
endif
EXTRA_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)

EXTRA_CFLAGS += -DEFX_NOT_UPSTREAM=1 -DEFX_USE_KCOMPAT=1

# Turn on all debugging
EXTRA_CFLAGS += -DDEBUG

# Turn off stack protector because it messes up the calling conventions
EXTRA_CFLAGS += $(call cc-option, -fno-stack-protector,)

ifneq (,$(findstring indirect-branch, $(KBUILD_CFLAGS)))
	EXTRA_CFLAGS += -mindirect-branch=keep
endif

else # !KERNELRELEASE

# Get kernel version and source directory.  If neither is specified then we
# assume the current kernel version.
ifdef KPATH
ifndef KVER
KVER := $(shell sed -r 's/^\#define UTS_RELEASE "(.*)"/\1/; t; d' $(KPATH)/include/generated/utsrelease.h $(KPATH)/include/linux/utsrelease.h $(KPATH)/include/linux/version.h 2>/dev/null)
ifeq ($(KVER),)
$(error Failed to find kernel version for $(KPATH))
endif
endif
else
ifndef KVER
KVER := $(shell uname -r)
endif
KPATH := /lib/modules/$(KVER)/build
endif # KPATH

################################################################################

# Normally compiled userland utilities
test_o = tso_test.o
all_tests = tso_test

################################################################################

all : test-all

test-all : $(all_tests:=-test)

build : $(all_tests)

clean :
	rm -f *.o *.s *.ko *.mod.c *.symvers $(all_tests) tso_config.h .kpath
	$(MAKE) -C $(KPATH) M=$$(pwd) clean

################################################################################

tso_test_mod.o : FORCE
	$(MAKE) -C $(KPATH) M=$$(pwd) modules

# Normal .c to .o rule
$(test_o) : %.o : %.c tso_shared.h FORCE
	@echo [normal CC] $@
	@$(CC) -Wall -g -c -o $@ $<

KVERBASE := $(word 1,$(subst -, ,$(KVER)))

# if compiling against 2.6.32 then build properly, otherwise build dummy.
ifeq ($(KVERBASE),2.6.32)
# Normal final link rule
tso_test : tso_test.o tso_test_mod.o
	@set -e; if [ "`file -b tso_test.o`" == "`file -b tso_test_mod.o`" ]; then	\
		echo [HOSTLD] $@;	\
		$(CC) -o $@ $^;		\
	else				\
		echo [HOSTCC];	\
		$(CC) -o $@ dummy.c -DMSG="user and kernel binaries are incompatible";	\
	fi
else
# Dummy rule if kernel version not supported by this test.
tso_test : dummy.c
	@echo [normal CC] $@
	@$(CC) -o $@ $^ -DMSG="kernel $(KVER) not supported"
endif

# Note there is an implicit rule. Turn off using "make -r". No way to do this here

tso_test-test :: tso_test
	@set -e; for nic in 3 4; do echo $< $$nic; ./$< $$nic; done

.PHONY : test-all all clean $(all_tests:=-test) FORCE

endif # KERNELRELEASE
