summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile14
-rw-r--r--tools/bpf/bpftool/prog.c31
-rw-r--r--tools/include/uapi/asm-generic/mman-common.h1
-rw-r--r--tools/include/uapi/linux/bpf.h8
-rw-r--r--tools/lib/traceevent/parse-filter.c6
-rw-r--r--tools/perf/Makefile.config6
-rw-r--r--tools/perf/arch/s390/include/dwarf-regs-table.h71
-rw-r--r--tools/perf/arch/s390/include/perf_regs.h95
-rw-r--r--tools/perf/arch/s390/util/Build3
-rw-r--r--tools/perf/arch/s390/util/auxtrace.c118
-rw-r--r--tools/perf/arch/s390/util/dwarf-regs.c11
-rw-r--r--tools/perf/arch/s390/util/unwind-libdw.c63
-rw-r--r--tools/testing/nvdimm/Kbuild1
-rw-r--r--tools/testing/nvdimm/test/nfit.c319
-rw-r--r--tools/testing/nvdimm/test/nfit_test.h52
-rw-r--r--tools/testing/selftests/Makefile3
-rw-r--r--tools/testing/selftests/android/Makefile46
-rw-r--r--tools/testing/selftests/android/ion/.gitignore2
-rw-r--r--tools/testing/selftests/android/ion/Makefile16
-rw-r--r--tools/testing/selftests/android/ion/README101
-rw-r--r--tools/testing/selftests/android/ion/config4
-rw-r--r--tools/testing/selftests/android/ion/ion.h143
-rwxr-xr-xtools/testing/selftests/android/ion/ion_test.sh55
-rw-r--r--tools/testing/selftests/android/ion/ionapp_export.c135
-rw-r--r--tools/testing/selftests/android/ion/ionapp_import.c88
-rw-r--r--tools/testing/selftests/android/ion/ionutils.c259
-rw-r--r--tools/testing/selftests/android/ion/ionutils.h55
-rw-r--r--tools/testing/selftests/android/ion/ipcsocket.c227
-rw-r--r--tools/testing/selftests/android/ion/ipcsocket.h35
-rwxr-xr-xtools/testing/selftests/android/run.sh3
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c152
-rw-r--r--tools/testing/selftests/breakpoints/breakpoint_test_arm64.c1
-rw-r--r--tools/testing/selftests/cpu-hotplug/config1
-rw-r--r--tools/testing/selftests/exec/execveat.c27
-rwxr-xr-xtools/testing/selftests/firmware/fw_fallback.sh38
-rwxr-xr-xtools/testing/selftests/firmware/fw_filesystem.sh34
-rw-r--r--tools/testing/selftests/ftrace/config4
-rwxr-xr-xtools/testing/selftests/ftrace/ftracetest7
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic4.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/event-enable.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/event-pid.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc5
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc4
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/instances/instance-event.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/instances/instance.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/template1
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc2
-rw-r--r--tools/testing/selftests/memfd/memfd_test.c4
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile4
-rw-r--r--tools/testing/selftests/seccomp/.gitignore1
-rw-r--r--tools/testing/selftests/timers/.gitignore2
-rw-r--r--tools/testing/selftests/vDSO/vdso_test.c19
-rw-r--r--tools/testing/selftests/vm/.gitignore2
-rw-r--r--tools/testing/selftests/vm/Makefile1
-rw-r--r--tools/testing/selftests/vm/gup_benchmark.c91
-rw-r--r--tools/thermal/tmon/Makefile18
-rw-r--r--tools/wmi/Makefile18
-rw-r--r--tools/wmi/dell-smbios-example.c210
76 files changed, 2464 insertions, 199 deletions
diff --git a/tools/Makefile b/tools/Makefile
index c03b4f69d5b7..be02c8b904db 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -30,6 +30,7 @@ help:
@echo ' usb - USB testing tools'
@echo ' virtio - vhost test module'
@echo ' vm - misc vm tools'
+ @echo ' wmi - WMI interface examples'
@echo ' x86_energy_perf_policy - Intel energy policy tool'
@echo ''
@echo 'You can do:'
@@ -58,7 +59,7 @@ acpi: FORCE
cpupower: FORCE
$(call descend,power/$@)
-cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds: FORCE
+cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE
$(call descend,$@)
liblockdep: FORCE
@@ -93,7 +94,7 @@ kvm_stat: FORCE
all: acpi cgroup cpupower gpio hv firewire liblockdep \
perf selftests spi turbostat usb \
virtio vm bpf x86_energy_perf_policy \
- tmon freefall iio objtool kvm_stat
+ tmon freefall iio objtool kvm_stat wmi
acpi_install:
$(call descend,power/$(@:_install=),install)
@@ -101,7 +102,7 @@ acpi_install:
cpupower_install:
$(call descend,power/$(@:_install=),install)
-cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install:
+cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install:
$(call descend,$(@:_install=),install)
liblockdep_install:
@@ -126,7 +127,8 @@ install: acpi_install cgroup_install cpupower_install gpio_install \
hv_install firewire_install iio_install liblockdep_install \
perf_install selftests_install turbostat_install usb_install \
virtio_install vm_install bpf_install x86_energy_perf_policy_install \
- tmon_install freefall_install objtool_install kvm_stat_install
+ tmon_install freefall_install objtool_install kvm_stat_install \
+ wmi_install
acpi_clean:
$(call descend,power/acpi,clean)
@@ -134,7 +136,7 @@ acpi_clean:
cpupower_clean:
$(call descend,power/cpupower,clean)
-cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean:
+cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean:
$(call descend,$(@:_clean=),clean)
liblockdep_clean:
@@ -172,6 +174,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
- gpio_clean objtool_clean leds_clean
+ gpio_clean objtool_clean leds_clean wmi_clean
.PHONY: FORCE
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index f45c44ef9bec..ad619b96c276 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -41,7 +41,6 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
-#include <net/if.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -230,21 +229,6 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
info->tag[0], info->tag[1], info->tag[2], info->tag[3],
info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
- if (info->status & BPF_PROG_STATUS_DEV_BOUND) {
- jsonw_name(json_wtr, "dev");
- if (info->ifindex) {
- char name[IF_NAMESIZE];
-
- if (!if_indextoname(info->ifindex, name))
- jsonw_printf(json_wtr, "\"ifindex:%d\"",
- info->ifindex);
- else
- jsonw_printf(json_wtr, "\"%s\"", name);
- } else {
- jsonw_printf(json_wtr, "\"unknown\"");
- }
- }
-
if (info->load_time) {
char buf[32];
@@ -302,21 +286,6 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
printf("tag ");
fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
- printf(" ");
-
- if (info->status & BPF_PROG_STATUS_DEV_BOUND) {
- printf("dev ");
- if (info->ifindex) {
- char name[IF_NAMESIZE];
-
- if (!if_indextoname(info->ifindex, name))
- printf("ifindex:%d ", info->ifindex);
- else
- printf("%s ", name);
- } else {
- printf("unknown ");
- }
- }
printf("\n");
if (info->load_time) {
diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h
index 6d319c46fd90..f8b134f5608f 100644
--- a/tools/include/uapi/asm-generic/mman-common.h
+++ b/tools/include/uapi/asm-generic/mman-common.h
@@ -17,6 +17,7 @@
#define MAP_SHARED 0x01 /* Share changes */
#define MAP_PRIVATE 0x02 /* Changes are private */
+#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */
#define MAP_TYPE 0x0f /* Mask for type of mapping */
#define MAP_FIXED 0x10 /* Interpret addr exactly */
#define MAP_ANONYMOUS 0x20 /* don't use a file */
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index e880ae6434ee..4c223ab30293 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -262,7 +262,7 @@ union bpf_attr {
__u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags;
char prog_name[BPF_OBJ_NAME_LEN];
- __u32 prog_target_ifindex; /* ifindex of netdev to prep for */
+ __u32 prog_ifindex; /* ifindex of netdev to prep for */
};
struct { /* anonymous struct used by BPF_OBJ_* commands */
@@ -897,10 +897,6 @@ enum sk_action {
#define BPF_TAG_SIZE 8
-enum bpf_prog_status {
- BPF_PROG_STATUS_DEV_BOUND = (1 << 0),
-};
-
struct bpf_prog_info {
__u32 type;
__u32 id;
@@ -914,8 +910,6 @@ struct bpf_prog_info {
__u32 nr_map_ids;
__aligned_u64 map_ids;
char name[BPF_OBJ_NAME_LEN];
- __u32 ifindex;
- __u32 status;
} __attribute__((aligned(8)));
struct bpf_map_info {
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index 7c214ceb9386..315df0a70265 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -436,13 +436,13 @@ create_arg_exp(enum filter_exp_type etype)
return NULL;
arg->type = FILTER_ARG_EXP;
- arg->op.type = etype;
+ arg->exp.type = etype;
return arg;
}
static struct filter_arg *
-create_arg_cmp(enum filter_exp_type etype)
+create_arg_cmp(enum filter_cmp_type ctype)
{
struct filter_arg *arg;
@@ -452,7 +452,7 @@ create_arg_cmp(enum filter_exp_type etype)
/* Use NUM and change if necessary */
arg->type = FILTER_ARG_NUM;
- arg->op.type = etype;
+ arg->num.type = ctype;
return arg;
}
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 63f534a0902f..ed65e82f034e 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -53,6 +53,10 @@ ifeq ($(SRCARCH),arm64)
LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
endif
+ifeq ($(ARCH),s390)
+ NO_PERF_REGS := 0
+endif
+
ifeq ($(NO_PERF_REGS),0)
$(call detected,CONFIG_PERF_REGS)
endif
@@ -61,7 +65,7 @@ endif
# Disable it on all other architectures in case libdw unwind
# support is detected in system. Add supported architectures
# to the check.
-ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc))
+ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390))
NO_LIBDW_DWARF_UNWIND := 1
endif
diff --git a/tools/perf/arch/s390/include/dwarf-regs-table.h b/tools/perf/arch/s390/include/dwarf-regs-table.h
index 792d4c277225..671553525f41 100644
--- a/tools/perf/arch/s390/include/dwarf-regs-table.h
+++ b/tools/perf/arch/s390/include/dwarf-regs-table.h
@@ -1,9 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#ifdef DEFINE_DWARF_REGSTR_TABLE
-/* This is included in perf/util/dwarf-regs.c */
+#ifndef S390_DWARF_REGS_TABLE_H
+#define S390_DWARF_REGS_TABLE_H
-static const char * const s390_regstr_tbl[] = {
+#define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg
+
+/*
+ * For reference, see DWARF register mapping:
+ * http://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_s390/x1542.html
+ */
+static const char * const s390_dwarf_regs[] = {
"%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+ REG_DWARFNUM_NAME(f0, 16),
+ REG_DWARFNUM_NAME(f1, 20),
+ REG_DWARFNUM_NAME(f2, 17),
+ REG_DWARFNUM_NAME(f3, 21),
+ REG_DWARFNUM_NAME(f4, 18),
+ REG_DWARFNUM_NAME(f5, 22),
+ REG_DWARFNUM_NAME(f6, 19),
+ REG_DWARFNUM_NAME(f7, 23),
+ REG_DWARFNUM_NAME(f8, 24),
+ REG_DWARFNUM_NAME(f9, 28),
+ REG_DWARFNUM_NAME(f10, 25),
+ REG_DWARFNUM_NAME(f11, 29),
+ REG_DWARFNUM_NAME(f12, 26),
+ REG_DWARFNUM_NAME(f13, 30),
+ REG_DWARFNUM_NAME(f14, 27),
+ REG_DWARFNUM_NAME(f15, 31),
+ REG_DWARFNUM_NAME(c0, 32),
+ REG_DWARFNUM_NAME(c1, 33),
+ REG_DWARFNUM_NAME(c2, 34),
+ REG_DWARFNUM_NAME(c3, 35),
+ REG_DWARFNUM_NAME(c4, 36),
+ REG_DWARFNUM_NAME(c5, 37),
+ REG_DWARFNUM_NAME(c6, 38),
+ REG_DWARFNUM_NAME(c7, 39),
+ REG_DWARFNUM_NAME(c8, 40),
+ REG_DWARFNUM_NAME(c9, 41),
+ REG_DWARFNUM_NAME(c10, 42),
+ REG_DWARFNUM_NAME(c11, 43),
+ REG_DWARFNUM_NAME(c12, 44),
+ REG_DWARFNUM_NAME(c13, 45),
+ REG_DWARFNUM_NAME(c14, 46),
+ REG_DWARFNUM_NAME(c15, 47),
+ REG_DWARFNUM_NAME(a0, 48),
+ REG_DWARFNUM_NAME(a1, 49),
+ REG_DWARFNUM_NAME(a2, 50),
+ REG_DWARFNUM_NAME(a3, 51),
+ REG_DWARFNUM_NAME(a4, 52),
+ REG_DWARFNUM_NAME(a5, 53),
+ REG_DWARFNUM_NAME(a6, 54),
+ REG_DWARFNUM_NAME(a7, 55),
+ REG_DWARFNUM_NAME(a8, 56),
+ REG_DWARFNUM_NAME(a9, 57),
+ REG_DWARFNUM_NAME(a10, 58),
+ REG_DWARFNUM_NAME(a11, 59),
+ REG_DWARFNUM_NAME(a12, 60),
+ REG_DWARFNUM_NAME(a13, 61),
+ REG_DWARFNUM_NAME(a14, 62),
+ REG_DWARFNUM_NAME(a15, 63),
+ REG_DWARFNUM_NAME(pswm, 64),
+ REG_DWARFNUM_NAME(pswa, 65),
};
-#endif
+
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+#define s390_regstr_tbl s390_dwarf_regs
+
+#endif /* DEFINE_DWARF_REGSTR_TABLE */
+#endif /* S390_DWARF_REGS_TABLE_H */
diff --git a/tools/perf/arch/s390/include/perf_regs.h b/tools/perf/arch/s390/include/perf_regs.h
new file mode 100644
index 000000000000..d2df54a6bc5a
--- /dev/null
+++ b/tools/perf/arch/s390/include/perf_regs.h
@@ -0,0 +1,95 @@
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include <linux/types.h>
+#include <../../../../arch/s390/include/uapi/asm/perf_regs.h>
+
+void perf_regs_load(u64 *regs);
+
+#define PERF_REGS_MASK ((1ULL << PERF_REG_S390_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_S390_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
+
+#define PERF_REG_IP PERF_REG_S390_PC
+#define PERF_REG_SP PERF_REG_S390_R15
+
+static inline const char *perf_reg_name(int id)
+{
+ switch (id) {
+ case PERF_REG_S390_R0:
+ return "R0";
+ case PERF_REG_S390_R1:
+ return "R1";
+ case PERF_REG_S390_R2:
+ return "R2";
+ case PERF_REG_S390_R3:
+ return "R3";
+ case PERF_REG_S390_R4:
+ return "R4";
+ case PERF_REG_S390_R5:
+ return "R5";
+ case PERF_REG_S390_R6:
+ return "R6";
+ case PERF_REG_S390_R7:
+ return "R7";
+ case PERF_REG_S390_R8:
+ return "R8";
+ case PERF_REG_S390_R9:
+ return "R9";
+ case PERF_REG_S390_R10:
+ return "R10";
+ case PERF_REG_S390_R11:
+ return "R11";
+ case PERF_REG_S390_R12:
+ return "R12";
+ case PERF_REG_S390_R13:
+ return "R13";
+ case PERF_REG_S390_R14:
+ return "R14";
+ case PERF_REG_S390_R15:
+ return "R15";
+ case PERF_REG_S390_FP0:
+ return "FP0";
+ case PERF_REG_S390_FP1:
+ return "FP1";
+ case PERF_REG_S390_FP2:
+ return "FP2";
+ case PERF_REG_S390_FP3:
+ return "FP3";
+ case PERF_REG_S390_FP4:
+ return "FP4";
+ case PERF_REG_S390_FP5:
+ return "FP5";
+ case PERF_REG_S390_FP6:
+ return "FP6";
+ case PERF_REG_S390_FP7:
+ return "FP7";
+ case PERF_REG_S390_FP8:
+ return "FP8";
+ case PERF_REG_S390_FP9:
+ return "FP9";
+ case PERF_REG_S390_FP10:
+ return "FP10";
+ case PERF_REG_S390_FP11:
+ return "FP11";
+ case PERF_REG_S390_FP12:
+ return "FP12";
+ case PERF_REG_S390_FP13:
+ return "FP13";
+ case PERF_REG_S390_FP14:
+ return "FP14";
+ case PERF_REG_S390_FP15:
+ return "FP15";
+ case PERF_REG_S390_MASK:
+ return "MASK";
+ case PERF_REG_S390_PC:
+ return "PC";
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
index 5bd7b9260cc0..4a233683c684 100644
--- a/tools/perf/arch/s390/util/Build
+++ b/tools/perf/arch/s390/util/Build
@@ -2,5 +2,8 @@ libperf-y += header.o
libperf-y += kvm-stat.o
libperf-$(CONFIG_DWARF) += dwarf-regs.o
+libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
libperf-y += machine.o
+
+libperf-$(CONFIG_AUXTRACE) += auxtrace.o
diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c
new file mode 100644
index 000000000000..6cb48e4cffd9
--- /dev/null
+++ b/tools/perf/arch/s390/util/auxtrace.c
@@ -0,0 +1,118 @@
+#include <stdbool.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+
+#include "../../util/evlist.h"
+#include "../../util/auxtrace.h"
+#include "../../util/evsel.h"
+
+#define PERF_EVENT_CPUM_SF 0xB0000 /* Event: Basic-sampling */
+#define PERF_EVENT_CPUM_SF_DIAG 0xBD000 /* Event: Combined-sampling */
+#define DEFAULT_AUX_PAGES 128
+#define DEFAULT_FREQ 4000
+
+static void cpumsf_free(struct auxtrace_record *itr)
+{
+ free(itr);
+}
+
+static size_t cpumsf_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+ struct perf_evlist *evlist __maybe_unused)
+{
+ return 0;
+}
+
+static int
+cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused,
+ struct perf_session *session __maybe_unused,
+ struct auxtrace_info_event *auxtrace_info __maybe_unused,
+ size_t priv_size __maybe_unused)
+{
+ return 0;
+}
+
+static unsigned long
+cpumsf_reference(struct auxtrace_record *itr __maybe_unused)
+{
+ return 0;
+}
+
+static int
+cpumsf_recording_options(struct auxtrace_record *ar __maybe_unused,
+ struct perf_evlist *evlist __maybe_unused,
+ struct record_opts *opts)
+{
+ unsigned int factor = 1;
+ unsigned int pages;
+
+ opts->full_auxtrace = true;
+
+ /*
+ * The AUX buffer size should be set properly to avoid
+ * overflow of samples if it is not set explicitly.
+ * DEFAULT_AUX_PAGES is an proper size when sampling frequency
+ * is DEFAULT_FREQ. It is expected to hold about 1/2 second
+ * of sampling data. The size used for AUX buffer will scale
+ * according to the specified frequency and DEFAULT_FREQ.
+ */
+ if (!opts->auxtrace_mmap_pages) {
+ if (opts->user_freq != UINT_MAX)
+ factor = (opts->user_freq + DEFAULT_FREQ
+ - 1) / DEFAULT_FREQ;
+ pages = DEFAULT_AUX_PAGES * factor;
+ opts->auxtrace_mmap_pages = roundup_pow_of_two(pages);
+ }
+
+ return 0;
+}
+
+static int
+cpumsf_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused,
+ struct record_opts *opts __maybe_unused,
+ const char *str __maybe_unused)
+{
+ return 0;
+}
+
+/*
+ * auxtrace_record__init is called when perf record
+ * check if the event really need auxtrace
+ */
+struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist,
+ int *err)
+{
+ struct auxtrace_record *aux;
+ struct perf_evsel *pos;
+ int diagnose = 0;
+
+ if (evlist->nr_entries == 0)
+ return NULL;
+
+ evlist__for_each_entry(evlist, pos) {
+ if (pos->attr.config == PERF_EVENT_CPUM_SF_DIAG) {
+ diagnose = 1;
+ break;
+ }
+ }
+
+ if (!diagnose)
+ return NULL;
+
+ /* sampling in diagnose mode. alloc aux buffer */
+ aux = zalloc(sizeof(*aux));
+ if (aux == NULL) {
+ *err = -ENOMEM;
+ return NULL;
+ }
+
+ aux->parse_snapshot_options = cpumsf_parse_snapshot_options;
+ aux->recording_options = cpumsf_recording_options;
+ aux->info_priv_size = cpumsf_info_priv_size;
+ aux->info_fill = cpumsf_info_fill;
+ aux->free = cpumsf_free;
+ aux->reference = cpumsf_reference;
+
+ return aux;
+}
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c
index 0dff5b2ed1e5..f47576ce13ea 100644
--- a/tools/perf/arch/s390/util/dwarf-regs.c
+++ b/tools/perf/arch/s390/util/dwarf-regs.c
@@ -9,15 +9,10 @@
#include <stddef.h>
#include <dwarf-regs.h>
-
-#define NUM_GPRS 16
-
-static const char *gpr_names[NUM_GPRS] = {
- "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
- "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
-};
+#include <linux/kernel.h>
+#include "dwarf-regs-table.h"
const char *get_arch_regstr(unsigned int n)
{
- return (n >= NUM_GPRS) ? NULL : gpr_names[n];
+ return (n >= ARRAY_SIZE(s390_dwarf_regs)) ? NULL : s390_dwarf_regs[n];
}
diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/arch/s390/util/unwind-libdw.c
new file mode 100644
index 000000000000..387c698cdd1b
--- /dev/null
+++ b/tools/perf/arch/s390/util/unwind-libdw.c
@@ -0,0 +1,63 @@
+#include <linux/kernel.h>
+#include <elfutils/libdwfl.h>
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"
+#include "../../util/event.h"
+#include "dwarf-regs-table.h"
+
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+{
+ struct unwind_info *ui = arg;
+ struct regs_dump *user_regs = &ui->sample->user_regs;
+ Dwarf_Word dwarf_regs[ARRAY_SIZE(s390_dwarf_regs)];
+
+#define REG(r) ({ \
+ Dwarf_Word val = 0; \
+ perf_reg_value(&val, user_regs, PERF_REG_S390_##r); \
+ val; \
+})
+ /*
+ * For DWARF register mapping details,
+ * see also perf/arch/s390/include/dwarf-regs-table.h
+ */
+ dwarf_regs[0] = REG(R0);
+ dwarf_regs[1] = REG(R1);
+ dwarf_regs[2] = REG(R2);
+ dwarf_regs[3] = REG(R3);
+ dwarf_regs[4] = REG(R4);
+ dwarf_regs[5] = REG(R5);
+ dwarf_regs[6] = REG(R6);
+ dwarf_regs[7] = REG(R7);
+ dwarf_regs[8] = REG(R8);
+ dwarf_regs[9] = REG(R9);
+ dwarf_regs[10] = REG(R10);
+ dwarf_regs[11] = REG(R11);
+ dwarf_regs[12] = REG(R12);
+ dwarf_regs[13] = REG(R13);
+ dwarf_regs[14] = REG(R14);
+ dwarf_regs[15] = REG(R15);
+
+ dwarf_regs[16] = REG(FP0);
+ dwarf_regs[17] = REG(FP2);
+ dwarf_regs[18] = REG(FP4);
+ dwarf_regs[19] = REG(FP6);
+ dwarf_regs[20] = REG(FP1);
+ dwarf_regs[21] = REG(FP3);
+ dwarf_regs[22] = REG(FP5);
+ dwarf_regs[23] = REG(FP7);
+ dwarf_regs[24] = REG(FP8);
+ dwarf_regs[25] = REG(FP10);
+ dwarf_regs[26] = REG(FP12);
+ dwarf_regs[27] = REG(FP14);
+ dwarf_regs[28] = REG(FP9);
+ dwarf_regs[29] = REG(FP11);
+ dwarf_regs[30] = REG(FP13);
+ dwarf_regs[31] = REG(FP15);
+
+ dwarf_regs[64] = REG(MASK);
+ dwarf_regs[65] = REG(PC);
+
+ dwfl_thread_state_register_pc(thread, dwarf_regs[65]);
+ return dwfl_thread_state_registers(thread, 0, 32, dwarf_regs);
+}
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index 65368d9027f5..db33b28c5ef3 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -70,6 +70,7 @@ libnvdimm-y += $(NVDIMM_SRC)/region_devs.o
libnvdimm-y += $(NVDIMM_SRC)/region.o
libnvdimm-y += $(NVDIMM_SRC)/namespace_devs.o
libnvdimm-y += $(NVDIMM_SRC)/label.o
+libnvdimm-y += $(NVDIMM_SRC)/badrange.o
libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o
libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o
libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index bef419d4266d..7217b2b953b5 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -168,8 +168,12 @@ struct nfit_test {
spinlock_t lock;
} ars_state;
struct device *dimm_dev[NUM_DCR];
+ struct badrange badrange;
+ struct work_struct work;
};
+static struct workqueue_struct *nfit_wq;
+
static struct nfit_test *to_nfit_test(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -234,48 +238,68 @@ static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd,
return rc;
}
-#define NFIT_TEST_ARS_RECORDS 4
#define NFIT_TEST_CLEAR_ERR_UNIT 256
static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd,
unsigned int buf_len)
{
+ int ars_recs;
+
if (buf_len < sizeof(*nd_cmd))
return -EINVAL;
+ /* for testing, only store up to n records that fit within 4k */
+ ars_recs = SZ_4K / sizeof(struct nd_ars_record);
+
nd_cmd->max_ars_out = sizeof(struct nd_cmd_ars_status)
- + NFIT_TEST_ARS_RECORDS * sizeof(struct nd_ars_record);
+ + ars_recs * sizeof(struct nd_ars_record);
nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16;
nd_cmd->clear_err_unit = NFIT_TEST_CLEAR_ERR_UNIT;
return 0;
}
-/*
- * Initialize the ars_state to return an ars_result 1 second in the future with
- * a 4K error range in the middle of the requested address range.
- */
-static void post_ars_status(struct ars_state *ars_state, u64 addr, u64 len)
+static void post_ars_status(struct ars_state *ars_state,
+ struct badrange *badrange, u64 addr, u64 len)
{
struct nd_cmd_ars_status *ars_status;
struct nd_ars_record *ars_record;
+ struct badrange_entry *be;
+ u64 end = addr + len - 1;
+ int i = 0;
ars_state->deadline = jiffies + 1*HZ;
ars_status = ars_state->ars_status;
ars_status->status = 0;
- ars_status->out_length = sizeof(struct nd_cmd_ars_status)
- + sizeof(struct nd_ars_record);
ars_status->address = addr;
ars_status->length = len;
ars_status->type = ND_ARS_PERSISTENT;
- ars_status->num_records = 1;
- ars_record = &ars_status->records[0];
- ars_record->handle = 0;
- ars_record->err_address = addr + len / 2;
- ars_record->length = SZ_4K;
+
+ spin_lock(&badrange->lock);
+ list_for_each_entry(be, &badrange->list, list) {
+ u64 be_end = be->start + be->length - 1;
+ u64 rstart, rend;
+
+ /* skip entries outside the range */
+ if (be_end < addr || be->start > end)
+ continue;
+
+ rstart = (be->start < addr) ? addr : be->start;
+ rend = (be_end < end) ? be_end : end;
+ ars_record = &ars_status->records[i];
+ ars_record->handle = 0;
+ ars_record->err_address = rstart;
+ ars_record->length = rend - rstart + 1;
+ i++;
+ }
+ spin_unlock(&badrange->lock);
+ ars_status->num_records = i;
+ ars_status->out_length = sizeof(struct nd_cmd_ars_status)
+ + i * sizeof(struct nd_ars_record);
}
-static int nfit_test_cmd_ars_start(struct ars_state *ars_state,
+static int nfit_test_cmd_ars_start(struct nfit_test *t,
+ struct ars_state *ars_state,
struct nd_cmd_ars_start *ars_start, unsigned int buf_len,
int *cmd_rc)
{
@@ -289,7 +313,7 @@ static int nfit_test_cmd_ars_start(struct ars_state *ars_state,
} else {
ars_start->status = 0;
ars_start->scrub_time = 1;
- post_ars_status(ars_state, ars_start->address,
+ post_ars_status(ars_state, &t->badrange, ars_start->address,
ars_start->length);
*cmd_rc = 0;
}
@@ -320,7 +344,8 @@ static int nfit_test_cmd_ars_status(struct ars_state *ars_state,
return 0;
}
-static int nfit_test_cmd_clear_error(struct nd_cmd_clear_error *clear_err,
+static int nfit_test_cmd_clear_error(struct nfit_test *t,
+ struct nd_cmd_clear_error *clear_err,
unsigned int buf_len, int *cmd_rc)
{
const u64 mask = NFIT_TEST_CLEAR_ERR_UNIT - 1;
@@ -330,18 +355,91 @@ static int nfit_test_cmd_clear_error(struct nd_cmd_clear_error *clear_err,
if ((clear_err->address & mask) || (clear_err->length & mask))
return -EINVAL;
- /*
- * Report 'all clear' success for all commands even though a new
- * scrub will find errors again. This is enough to have the
- * error removed from the 'badblocks' tracking in the pmem
- * driver.
- */
+ badrange_forget(&t->badrange, clear_err->address, clear_err->length);
clear_err->status = 0;
clear_err->cleared = clear_err->length;
*cmd_rc = 0;
return 0;
}
+struct region_search_spa {
+ u64 addr;
+ struct nd_region *region;
+};
+
+static int is_region_device(struct device *dev)
+{
+ return !strncmp(dev->kobj.name, "region", 6);
+}
+
+static int nfit_test_search_region_spa(struct device *dev, void *data)
+{
+ struct region_search_spa *ctx = data;
+ struct nd_region *nd_region;
+ resource_size_t ndr_end;
+
+ if (!is_region_device(dev))
+ return 0;
+
+ nd_region = to_nd_region(dev);
+ ndr_end = nd_region->ndr_start + nd_region->ndr_size;
+
+ if (ctx->addr >= nd_region->ndr_start && ctx->addr < ndr_end) {
+ ctx->region = nd_region;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int nfit_test_search_spa(struct nvdimm_bus *bus,
+ struct nd_cmd_translate_spa *spa)
+{
+ int ret;
+ struct nd_region *nd_region = NULL;
+ struct nvdimm *nvdimm = NULL;
+ struct nd_mapping *nd_mapping = NULL;
+ struct region_search_spa ctx = {
+ .addr = spa->spa,
+ .region = NULL,
+ };
+ u64 dpa;
+
+ ret = device_for_each_child(&bus->dev, &ctx,
+ nfit_test_search_region_spa);
+
+ if (!ret)
+ return -ENODEV;
+
+ nd_region = ctx.region;
+
+ dpa = ctx.addr - nd_region->ndr_start;
+
+ /*
+ * last dimm is selected for test
+ */
+ nd_mapping = &nd_region->mapping[nd_region->ndr_mappings - 1];
+ nvdimm = nd_mapping->nvdimm;
+
+ spa->devices[0].nfit_device_handle = handle[nvdimm->id];
+ spa->num_nvdimms = 1;
+ spa->devices[0].dpa = dpa;
+
+ return 0;
+}
+
+static int nfit_test_cmd_translate_spa(struct nvdimm_bus *bus,
+ struct nd_cmd_translate_spa *spa, unsigned int buf_len)
+{
+ if (buf_len < spa->translate_length)
+ return -EINVAL;
+
+ if (nfit_test_search_spa(bus, spa) < 0 || !spa->num_nvdimms)
+ spa->status = 2;
+
+ return 0;
+}
+
static int nfit_test_cmd_smart(struct nd_cmd_smart *smart, unsigned int buf_len)
{
static const struct nd_smart_payload smart_data = {
@@ -378,6 +476,93 @@ static int nfit_test_cmd_smart_threshold(struct nd_cmd_smart_threshold *smart_t,
return 0;
}
+static void uc_error_notify(struct work_struct *work)
+{
+ struct nfit_test *t = container_of(work, typeof(*t), work);
+
+ __acpi_nfit_notify(&t->pdev.dev, t, NFIT_NOTIFY_UC_MEMORY_ERROR);
+}
+
+static int nfit_test_cmd_ars_error_inject(struct nfit_test *t,
+ struct nd_cmd_ars_err_inj *err_inj, unsigned int buf_len)
+{
+ int rc;
+
+ if (buf_len != sizeof(*err_inj)) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if (err_inj->err_inj_spa_range_length <= 0) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = badrange_add(&t->badrange, err_inj->err_inj_spa_range_base,
+ err_inj->err_inj_spa_range_length);
+ if (rc < 0)
+ goto err;
+
+ if (err_inj->err_inj_options & (1 << ND_ARS_ERR_INJ_OPT_NOTIFY))
+ queue_work(nfit_wq, &t->work);
+
+ err_inj->status = 0;
+ return 0;
+
+err:
+ err_inj->status = NFIT_ARS_INJECT_INVALID;
+ return rc;
+}
+
+static int nfit_test_cmd_ars_inject_clear(struct nfit_test *t,
+ struct nd_cmd_ars_err_inj_clr *err_clr, unsigned int buf_len)
+{
+ int rc;
+
+ if (buf_len != sizeof(*err_clr)) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if (err_clr->err_inj_clr_spa_range_length <= 0) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ badrange_forget(&t->badrange, err_clr->err_inj_clr_spa_range_base,
+ err_clr->err_inj_clr_spa_range_length);
+
+ err_clr->status = 0;
+ return 0;
+
+err:
+ err_clr->status = NFIT_ARS_INJECT_INVALID;
+ return rc;
+}
+
+static int nfit_test_cmd_ars_inject_status(struct nfit_test *t,
+ struct nd_cmd_ars_err_inj_stat *err_stat,
+ unsigned int buf_len)
+{
+ struct badrange_entry *be;
+ int max = SZ_4K / sizeof(struct nd_error_stat_query_record);
+ int i = 0;
+
+ err_stat->status = 0;
+ spin_lock(&t->badrange.lock);
+ list_for_each_entry(be, &t->badrange.list, list) {
+ err_stat->record[i].err_inj_stat_spa_range_base = be->start;
+ err_stat->record[i].err_inj_stat_spa_range_length = be->length;
+ i++;
+ if (i > max)
+ break;
+ }
+ spin_unlock(&t->badrange.lock);
+ err_stat->inj_err_rec_count = i;
+
+ return 0;
+}
+
static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
unsigned int buf_len, int *cmd_rc)
@@ -449,6 +634,38 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
}
} else {
struct ars_state *ars_state = &t->ars_state;
+ struct nd_cmd_pkg *call_pkg = buf;
+
+ if (!nd_desc)
+ return -ENOTTY;
+
+ if (cmd == ND_CMD_CALL) {
+ func = call_pkg->nd_command;
+
+ buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out;
+ buf = (void *) call_pkg->nd_payload;
+
+ switch (func) {
+ case NFIT_CMD_TRANSLATE_SPA:
+ rc = nfit_test_cmd_translate_spa(
+ acpi_desc->nvdimm_bus, buf, buf_len);
+ return rc;
+ case NFIT_CMD_ARS_INJECT_SET:
+ rc = nfit_test_cmd_ars_error_inject(t, buf,
+ buf_len);
+ return rc;
+ case NFIT_CMD_ARS_INJECT_CLEAR:
+ rc = nfit_test_cmd_ars_inject_clear(t, buf,
+ buf_len);
+ return rc;
+ case NFIT_CMD_ARS_INJECT_GET:
+ rc = nfit_test_cmd_ars_inject_status(t, buf,
+ buf_len);
+ return rc;
+ default:
+ return -ENOTTY;
+ }
+ }
if (!nd_desc || !test_bit(cmd, &nd_desc->cmd_mask))
return -ENOTTY;
@@ -458,15 +675,15 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
rc = nfit_test_cmd_ars_cap(buf, buf_len);
break;
case ND_CMD_ARS_START:
- rc = nfit_test_cmd_ars_start(ars_state, buf, buf_len,
- cmd_rc);
+ rc = nfit_test_cmd_ars_start(t, ars_state, buf,
+ buf_len, cmd_rc);
break;
case ND_CMD_ARS_STATUS:
rc = nfit_test_cmd_ars_status(ars_state, buf, buf_len,
cmd_rc);
break;
case ND_CMD_CLEAR_ERROR:
- rc = nfit_test_cmd_clear_error(buf, buf_len, cmd_rc);
+ rc = nfit_test_cmd_clear_error(t, buf, buf_len, cmd_rc);
break;
default:
return -ENOTTY;
@@ -566,10 +783,9 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
static int ars_state_init(struct device *dev, struct ars_state *ars_state)
{
+ /* for testing, only store up to n records that fit within 4k */
ars_state->ars_status = devm_kzalloc(dev,
- sizeof(struct nd_cmd_ars_status)
- + sizeof(struct nd_ars_record) * NFIT_TEST_ARS_RECORDS,
- GFP_KERNEL);
+ sizeof(struct nd_cmd_ars_status) + SZ_4K, GFP_KERNEL);
if (!ars_state->ars_status)
return -ENOMEM;
spin_lock_init(&ars_state->lock);
@@ -1419,7 +1635,8 @@ static void nfit_test0_setup(struct nfit_test *t)
+ i * sizeof(u64);
}
- post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE);
+ post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0],
+ SPA0_SIZE);
acpi_desc = &t->acpi_desc;
set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en);
@@ -1430,7 +1647,12 @@ static void nfit_test0_setup(struct nfit_test *t)
set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en);
set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en);
set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en);
+ set_bit(ND_CMD_CALL, &acpi_desc->bus_cmd_force_en);
set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NFIT_CMD_TRANSLATE_SPA, &acpi_desc->bus_nfit_cmd_force_en);
+ set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_nfit_cmd_force_en);
+ set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_nfit_cmd_force_en);
+ set_bit(NFIT_CMD_ARS_INJECT_GET, &acpi_desc->bus_nfit_cmd_force_en);
}
static void nfit_test1_setup(struct nfit_test *t)
@@ -1520,7 +1742,8 @@ static void nfit_test1_setup(struct nfit_test *t)
dcr->code = NFIT_FIC_BYTE;
dcr->windows = 0;
- post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE);
+ post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0],
+ SPA2_SIZE);
acpi_desc = &t->acpi_desc;
set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en);
@@ -1589,6 +1812,7 @@ static int nfit_ctl_test(struct device *dev)
unsigned long mask, cmd_size, offset;
union {
struct nd_cmd_get_config_size cfg_size;
+ struct nd_cmd_clear_error clear_err;
struct nd_cmd_ars_status ars_stat;
struct nd_cmd_ars_cap ars_cap;
char buf[sizeof(struct nd_cmd_ars_status)
@@ -1613,10 +1837,15 @@ static int nfit_ctl_test(struct device *dev)
.cmd_mask = 1UL << ND_CMD_ARS_CAP
| 1UL << ND_CMD_ARS_START
| 1UL << ND_CMD_ARS_STATUS
- | 1UL << ND_CMD_CLEAR_ERROR,
+ | 1UL << ND_CMD_CLEAR_ERROR
+ | 1UL << ND_CMD_CALL,
.module = THIS_MODULE,
.provider_name = "ACPI.NFIT",
.ndctl = acpi_nfit_ctl,
+ .bus_dsm_mask = 1UL << NFIT_CMD_TRANSLATE_SPA
+ | 1UL << NFIT_CMD_ARS_INJECT_SET
+ | 1UL << NFIT_CMD_ARS_INJECT_CLEAR
+ | 1UL << NFIT_CMD_ARS_INJECT_GET,
},
.dev = &adev->dev,
};
@@ -1767,6 +1996,23 @@ static int nfit_ctl_test(struct device *dev)
return -EIO;
}
+ /* test clear error */
+ cmd_size = sizeof(cmds.clear_err);
+ cmds.clear_err = (struct nd_cmd_clear_error) {
+ .length = 512,
+ .cleared = 512,
+ };
+ rc = setup_result(cmds.buf, cmd_size);
+ if (rc)
+ return rc;
+ rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_CLEAR_ERROR,
+ cmds.buf, cmd_size, &cmd_rc);
+ if (rc < 0 || cmd_rc) {
+ dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n",
+ __func__, __LINE__, rc, cmd_rc);
+ return -EIO;
+ }
+
return 0;
}
@@ -1915,6 +2161,10 @@ static __init int nfit_test_init(void)
nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm);
+ nfit_wq = create_singlethread_workqueue("nfit");
+ if (!nfit_wq)
+ return -ENOMEM;
+
nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm");
if (IS_ERR(nfit_test_dimm)) {
rc = PTR_ERR(nfit_test_dimm);
@@ -1931,6 +2181,7 @@ static __init int nfit_test_init(void)
goto err_register;
}
INIT_LIST_HEAD(&nfit_test->resources);
+ badrange_init(&nfit_test->badrange);
switch (i) {
case 0:
nfit_test->num_pm = NUM_PM;
@@ -1966,6 +2217,7 @@ static __init int nfit_test_init(void)
goto err_register;
instances[i] = nfit_test;
+ INIT_WORK(&nfit_test->work, uc_error_notify);
}
rc = platform_driver_register(&nfit_test_driver);
@@ -1974,6 +2226,7 @@ static __init int nfit_test_init(void)
return 0;
err_register:
+ destroy_workqueue(nfit_wq);
for (i = 0; i < NUM_NFITS; i++)
if (instances[i])
platform_device_unregister(&instances[i]->pdev);
@@ -1989,6 +2242,8 @@ static __exit void nfit_test_exit(void)
{
int i;
+ flush_workqueue(nfit_wq);
+ destroy_workqueue(nfit_wq);
for (i = 0; i < NUM_NFITS; i++)
platform_device_unregister(&instances[i]->pdev);
platform_driver_unregister(&nfit_test_driver);
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h
index d3d63dd5ed38..113b44675a71 100644
--- a/tools/testing/nvdimm/test/nfit_test.h
+++ b/tools/testing/nvdimm/test/nfit_test.h
@@ -32,6 +32,58 @@ struct nfit_test_resource {
void *buf;
};
+#define ND_TRANSLATE_SPA_STATUS_INVALID_SPA 2
+#define NFIT_ARS_INJECT_INVALID 2
+
+enum err_inj_options {
+ ND_ARS_ERR_INJ_OPT_NOTIFY = 0,
+};
+
+/* nfit commands */
+enum nfit_cmd_num {
+ NFIT_CMD_TRANSLATE_SPA = 5,
+ NFIT_CMD_ARS_INJECT_SET = 7,
+ NFIT_CMD_ARS_INJECT_CLEAR = 8,
+ NFIT_CMD_ARS_INJECT_GET = 9,
+};
+
+struct nd_cmd_translate_spa {
+ __u64 spa;
+ __u32 status;
+ __u8 flags;
+ __u8 _reserved[3];
+ __u64 translate_length;
+ __u32 num_nvdimms;
+ struct nd_nvdimm_device {
+ __u32 nfit_device_handle;
+ __u32 _reserved;
+ __u64 dpa;
+ } __packed devices[0];
+
+} __packed;
+
+struct nd_cmd_ars_err_inj {
+ __u64 err_inj_spa_range_base;
+ __u64 err_inj_spa_range_length;
+ __u8 err_inj_options;
+ __u32 status;
+} __packed;
+
+struct nd_cmd_ars_err_inj_clr {
+ __u64 err_inj_clr_spa_range_base;
+ __u64 err_inj_clr_spa_range_length;
+ __u32 status;
+} __packed;
+
+struct nd_cmd_ars_err_inj_stat {
+ __u32 status;
+ __u32 inj_err_rec_count;
+ struct nd_error_stat_query_record {
+ __u64 err_inj_stat_spa_range_base;
+ __u64 err_inj_stat_spa_range_length;
+ } __packed record[0];
+} __packed;
+
union acpi_object;
typedef void *acpi_handle;
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 3c9c0bbe7dbb..eaf599dc2137 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-TARGETS = bpf
+TARGETS = android
+TARGETS += bpf
TARGETS += breakpoints
TARGETS += capabilities
TARGETS += cpufreq
diff --git a/tools/testing/selftests/android/Makefile b/tools/testing/selftests/android/Makefile
new file mode 100644
index 000000000000..1a7492268993
--- /dev/null
+++ b/tools/testing/selftests/android/Makefile
@@ -0,0 +1,46 @@
+SUBDIRS := ion
+
+TEST_PROGS := run.sh
+
+.PHONY: all clean
+
+include ../lib.mk
+
+all:
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ mkdir $$BUILD_TARGET -p; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
+ #SUBDIR test prog name should be in the form: SUBDIR_test.sh
+ TEST=$$DIR"_test.sh"; \
+ if [ -e $$DIR/$$TEST ]; then
+ rsync -a $$DIR/$$TEST $$BUILD_TARGET/;
+ fi
+ done
+
+override define RUN_TESTS
+ @cd $(OUTPUT); ./run.sh
+endef
+
+override define INSTALL_RULE
+ mkdir -p $(INSTALL_PATH)
+ install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)
+
+ @for SUBDIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$SUBDIR; \
+ mkdir $$BUILD_TARGET -p; \
+ $(MAKE) OUTPUT=$$BUILD_TARGET -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \
+ done;
+endef
+
+override define EMIT_TESTS
+ echo "./run.sh"
+endef
+
+override define CLEAN
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ mkdir $$BUILD_TARGET -p; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
+ done
+endef
diff --git a/tools/testing/selftests/android/ion/.gitignore b/tools/testing/selftests/android/ion/.gitignore
new file mode 100644
index 000000000000..67e6f391b2a9
--- /dev/null
+++ b/tools/testing/selftests/android/ion/.gitignore
@@ -0,0 +1,2 @@
+ionapp_export
+ionapp_import
diff --git a/tools/testing/selftests/android/ion/Makefile b/tools/testing/selftests/android/ion/Makefile
new file mode 100644
index 000000000000..96e0c448b39d
--- /dev/null
+++ b/tools/testing/selftests/android/ion/Makefile
@@ -0,0 +1,16 @@
+
+INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/
+CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g
+
+TEST_GEN_FILES := ionapp_export ionapp_import
+
+all: $(TEST_GEN_FILES)
+
+$(TEST_GEN_FILES): ipcsocket.c ionutils.c
+
+TEST_PROGS := ion_test.sh
+
+include ../../lib.mk
+
+$(OUTPUT)/ionapp_export: ionapp_export.c ipcsocket.c ionutils.c
+$(OUTPUT)/ionapp_import: ionapp_import.c ipcsocket.c ionutils.c
diff --git a/tools/testing/selftests/android/ion/README b/tools/testing/selftests/android/ion/README
new file mode 100644
index 000000000000..21783e9c451e
--- /dev/null
+++ b/tools/testing/selftests/android/ion/README
@@ -0,0 +1,101 @@
+ION BUFFER SHARING UTILITY
+==========================
+File: ion_test.sh : Utility to test ION driver buffer sharing mechanism.
+Author: Pintu Kumar <pintu.ping@gmail.com>
+
+Introduction:
+-------------
+This is a test utility to verify ION buffer sharing in user space
+between 2 independent processes.
+It uses unix domain socket (with SCM_RIGHTS) as IPC to transfer an FD to
+another process to share the same buffer.
+This utility demonstrates how ION buffer sharing can be implemented between
+two user space processes, using various heap types.
+The following heap types are supported by ION driver.
+ION_HEAP_TYPE_SYSTEM (0)
+ION_HEAP_TYPE_SYSTEM_CONTIG (1)
+ION_HEAP_TYPE_CARVEOUT (2)
+ION_HEAP_TYPE_CHUNK (3)
+ION_HEAP_TYPE_DMA (4)
+
+By default only the SYSTEM and SYSTEM_CONTIG heaps are supported.
+Each heap is associated with the respective heap id.
+This utility is designed in the form of client/server program.
+The server part (ionapp_export) is the exporter of the buffer.
+It is responsible for creating an ION client, allocating the buffer based on
+the heap id, writing some data to this buffer and then exporting the FD
+(associated with this buffer) to another process using socket IPC.
+This FD is called as buffer FD (which is different than the ION client FD).
+
+The client part (ionapp_import) is the importer of the buffer.
+It retrives the FD from the socket data and installs into its address space.
+This new FD internally points to the same kernel buffer.
+So first it reads the data that is stored in this buffer and prints it.
+Then it writes the different size of data (it could be different data) to the
+same buffer.
+Finally the buffer FD must be closed by both the exporter and importer.
+Thus the same kernel buffer is shared among two user space processes using
+ION driver and only one time allocation.
+
+Prerequisite:
+-------------
+This utility works only if /dev/ion interface is present.
+The following configs needs to be enabled in kernel to include ion driver.
+CONFIG_ANDROID=y
+CONFIG_STAGING=y
+CONFIG_ION=y
+CONFIG_ION_SYSTEM_HEAP=y
+
+This utility requires to be run as root user.
+
+
+Compile and test:
+-----------------
+This utility is made to be run as part of kselftest framework in kernel.
+To compile and run using kselftest you can simply do the following from the
+kernel top directory.
+linux$ make TARGETS=android kselftest
+Or you can also use:
+linux$ make -C tools/testing/selftests TARGETS=android run_tests
+Using the selftest it can directly execute the ion_test.sh script to test the
+buffer sharing using ion system heap.
+Currently the heap size is hard coded as just 10 bytes inside this script.
+You need to be a root user to run under selftest.
+
+You can also compile and test manually using the following steps:
+ion$ make
+These will generate 2 executable: ionapp_export, ionapp_import
+Now you can run the export and import manually by specifying the heap type
+and the heap size.
+You can also directly execute the shell script to run the test automatically.
+Simply use the following command to run the test.
+ion$ sudo ./ion_test.sh
+
+Test Results:
+-------------
+The utility is verified on Ubuntu-32 bit system with Linux Kernel 4.14.
+Here is the snapshot of the test result using kselftest.
+
+linux# make TARGETS=android kselftest
+heap_type: 0, heap_size: 10
+--------------------------------------
+heap type: 0
+ heap id: 1
+heap name: ion_system_heap
+--------------------------------------
+Fill buffer content:
+0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd
+Sharing fd: 6, Client fd: 5
+<ion_close_buffer_fd>: buffer release successfully....
+Received buffer fd: 4
+Read buffer content:
+0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0x0 0x0 0x0 0x0 0x0 0x0
+0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
+Fill buffer content:
+0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd
+0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd
+0xfd 0xfd
+<ion_close_buffer_fd>: buffer release successfully....
+ion_test.sh: heap_type: 0 - [PASS]
+
+ion_test.sh: done
diff --git a/tools/testing/selftests/android/ion/config b/tools/testing/selftests/android/ion/config
new file mode 100644
index 000000000000..19db6ca9aa2b
--- /dev/null
+++ b/tools/testing/selftests/android/ion/config
@@ -0,0 +1,4 @@
+CONFIG_ANDROID=y
+CONFIG_STAGING=y
+CONFIG_ION=y
+CONFIG_ION_SYSTEM_HEAP=y
diff --git a/tools/testing/selftests/android/ion/ion.h b/tools/testing/selftests/android/ion/ion.h
new file mode 100644
index 000000000000..f7021ac51335
--- /dev/null
+++ b/tools/testing/selftests/android/ion/ion.h
@@ -0,0 +1,143 @@
+/*
+ * ion.h
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* This file is copied from drivers/staging/android/uapi/ion.h
+ * This local copy is required for the selftest to pass, when build
+ * outside the kernel source tree.
+ * Please keep this file in sync with its original file until the
+ * ion driver is moved outside the staging tree.
+ */
+
+#ifndef _UAPI_LINUX_ION_H
+#define _UAPI_LINUX_ION_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * enum ion_heap_types - list of all possible types of heaps
+ * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
+ * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
+ * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
+ * carveout heap, allocations are physically
+ * contiguous
+ * @ION_HEAP_TYPE_DMA: memory allocated via DMA API
+ * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask
+ * is used to identify the heaps, so only 32
+ * total heap types are supported
+ */
+enum ion_heap_type {
+ ION_HEAP_TYPE_SYSTEM,
+ ION_HEAP_TYPE_SYSTEM_CONTIG,
+ ION_HEAP_TYPE_CARVEOUT,
+ ION_HEAP_TYPE_CHUNK,
+ ION_HEAP_TYPE_DMA,
+ ION_HEAP_TYPE_CUSTOM, /*
+ * must be last so device specific heaps always
+ * are at the end of this enum
+ */
+};
+
+#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
+
+/**
+ * allocation flags - the lower 16 bits are used by core ion, the upper 16
+ * bits are reserved for use by the heaps themselves.
+ */
+
+/*
+ * mappings of this buffer should be cached, ion will do cache maintenance
+ * when the buffer is mapped for dma
+ */
+#define ION_FLAG_CACHED 1
+
+/**
+ * DOC: Ion Userspace API
+ *
+ * create a client by opening /dev/ion
+ * most operations handled via following ioctls
+ *
+ */
+
+/**
+ * struct ion_allocation_data - metadata passed from userspace for allocations
+ * @len: size of the allocation
+ * @heap_id_mask: mask of heap ids to allocate from
+ * @flags: flags passed to heap
+ * @handle: pointer that will be populated with a cookie to use to
+ * refer to this allocation
+ *
+ * Provided by userspace as an argument to the ioctl
+ */
+struct ion_allocation_data {
+ __u64 len;
+ __u32 heap_id_mask;
+ __u32 flags;
+ __u32 fd;
+ __u32 unused;
+};
+
+#define MAX_HEAP_NAME 32
+
+/**
+ * struct ion_heap_data - data about a heap
+ * @name - first 32 characters of the heap name
+ * @type - heap type
+ * @heap_id - heap id for the heap
+ */
+struct ion_heap_data {
+ char name[MAX_HEAP_NAME];
+ __u32 type;
+ __u32 heap_id;
+ __u32 reserved0;
+ __u32 reserved1;
+ __u32 reserved2;
+};
+
+/**
+ * struct ion_heap_query - collection of data about all heaps
+ * @cnt - total number of heaps to be copied
+ * @heaps - buffer to copy heap data
+ */
+struct ion_heap_query {
+ __u32 cnt; /* Total number of heaps to be copied */
+ __u32 reserved0; /* align to 64bits */
+ __u64 heaps; /* buffer to be populated */
+ __u32 reserved1;
+ __u32 reserved2;
+};
+
+#define ION_IOC_MAGIC 'I'
+
+/**
+ * DOC: ION_IOC_ALLOC - allocate memory
+ *
+ * Takes an ion_allocation_data struct and returns it with the handle field
+ * populated with the opaque handle for the allocation.
+ */
+#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
+ struct ion_allocation_data)
+
+/**
+ * DOC: ION_IOC_HEAP_QUERY - information about available heaps
+ *
+ * Takes an ion_heap_query structure and populates information about
+ * available Ion heaps.
+ */
+#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, \
+ struct ion_heap_query)
+
+#endif /* _UAPI_LINUX_ION_H */
diff --git a/tools/testing/selftests/android/ion/ion_test.sh b/tools/testing/selftests/android/ion/ion_test.sh
new file mode 100755
index 000000000000..a1aff506f5e6
--- /dev/null
+++ b/tools/testing/selftests/android/ion/ion_test.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+heapsize=4096
+TCID="ion_test.sh"
+errcode=0
+
+run_test()
+{
+ heaptype=$1
+ ./ionapp_export -i $heaptype -s $heapsize &
+ sleep 1
+ ./ionapp_import
+ if [ $? -ne 0 ]; then
+ echo "$TCID: heap_type: $heaptype - [FAIL]"
+ errcode=1
+ else
+ echo "$TCID: heap_type: $heaptype - [PASS]"
+ fi
+ sleep 1
+ echo ""
+}
+
+check_root()
+{
+ uid=$(id -u)
+ if [ $uid -ne 0 ]; then
+ echo $TCID: must be run as root >&2
+ exit 0
+ fi
+}
+
+check_device()
+{
+ DEVICE=/dev/ion
+ if [ ! -e $DEVICE ]; then
+ echo $TCID: No $DEVICE device found >&2
+ echo $TCID: May be CONFIG_ION is not set >&2
+ exit 0
+ fi
+}
+
+main_function()
+{
+ check_device
+ check_root
+
+ # ION_SYSTEM_HEAP TEST
+ run_test 0
+ # ION_SYSTEM_CONTIG_HEAP TEST
+ run_test 1
+}
+
+main_function
+echo "$TCID: done"
+exit $errcode
diff --git a/tools/testing/selftests/android/ion/ionapp_export.c b/tools/testing/selftests/android/ion/ionapp_export.c
new file mode 100644
index 000000000000..a944e72621a9
--- /dev/null
+++ b/tools/testing/selftests/android/ion/ionapp_export.c
@@ -0,0 +1,135 @@
+/*
+ * ionapp_export.c
+ *
+ * It is a user space utility to create and export android
+ * ion memory buffer fd to another process using unix domain socket as IPC.
+ * This acts like a server for ionapp_import(client).
+ * So, this server has to be started first before the client.
+ *
+ * Copyright (C) 2017 Pintu Kumar <pintu.ping@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include "ionutils.h"
+#include "ipcsocket.h"
+
+
+void print_usage(int argc, char *argv[])
+{
+ printf("Usage: %s [-h <help>] [-i <heap id>] [-s <size in bytes>]\n",
+ argv[0]);
+}
+
+int main(int argc, char *argv[])
+{
+ int opt, ret, status, heapid;
+ int sockfd, client_fd, shared_fd;
+ unsigned char *map_buf;
+ unsigned long map_len, heap_type, heap_size, flags;
+ struct ion_buffer_info info;
+ struct socket_info skinfo;
+
+ if (argc < 2) {
+ print_usage(argc, argv);
+ return -1;
+ }
+
+ heap_size = 0;
+ flags = 0;
+
+ while ((opt = getopt(argc, argv, "hi:s:")) != -1) {
+ switch (opt) {
+ case 'h':
+ print_usage(argc, argv);
+ exit(0);
+ break;
+ case 'i':
+ heapid = atoi(optarg);
+ switch (heapid) {
+ case 0:
+ heap_type = ION_HEAP_TYPE_SYSTEM;
+ break;
+ case 1:
+ heap_type = ION_HEAP_TYPE_SYSTEM_CONTIG;
+ break;
+ default:
+ printf("ERROR: heap type not supported\n");
+ exit(1);
+ }
+ break;
+ case 's':
+ heap_size = atoi(optarg);
+ break;
+ default:
+ print_usage(argc, argv);
+ exit(1);
+ break;
+ }
+ }
+
+ if (heap_size <= 0) {
+ printf("heap_size cannot be 0\n");
+ print_usage(argc, argv);
+ exit(1);
+ }
+
+ printf("heap_type: %ld, heap_size: %ld\n", heap_type, heap_size);
+ info.heap_type = heap_type;
+ info.heap_size = heap_size;
+ info.flag_type = flags;
+
+ /* This is server: open the socket connection first */
+ /* Here; 1 indicates server or exporter */
+ status = opensocket(&sockfd, SOCKET_NAME, 1);
+ if (status < 0) {
+ fprintf(stderr, "<%s>: Failed opensocket.\n", __func__);
+ goto err_socket;
+ }
+ skinfo.sockfd = sockfd;
+
+ ret = ion_export_buffer_fd(&info);
+ if (ret < 0) {
+ fprintf(stderr, "FAILED: ion_get_buffer_fd\n");
+ goto err_export;
+ }
+ client_fd = info.ionfd;
+ shared_fd = info.buffd;
+ map_buf = info.buffer;
+ map_len = info.buflen;
+ write_buffer(map_buf, map_len);
+
+ /* share ion buf fd with other user process */
+ printf("Sharing fd: %d, Client fd: %d\n", shared_fd, client_fd);
+ skinfo.datafd = shared_fd;
+ skinfo.buflen = map_len;
+
+ ret = socket_send_fd(&skinfo);
+ if (ret < 0) {
+ fprintf(stderr, "FAILED: socket_send_fd\n");
+ goto err_send;
+ }
+
+err_send:
+err_export:
+ ion_close_buffer_fd(&info);
+
+err_socket:
+ closesocket(sockfd, SOCKET_NAME);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/android/ion/ionapp_import.c b/tools/testing/selftests/android/ion/ionapp_import.c
new file mode 100644
index 000000000000..ae2d704cfa46
--- /dev/null
+++ b/tools/testing/selftests/android/ion/ionapp_import.c
@@ -0,0 +1,88 @@
+/*
+ * ionapp_import.c
+ *
+ * It is a user space utility to receive android ion memory buffer fd
+ * over unix domain socket IPC that can be exported by ionapp_export.
+ * This acts like a client for ionapp_export.
+ *
+ * Copyright (C) 2017 Pintu Kumar <pintu.ping@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "ionutils.h"
+#include "ipcsocket.h"
+
+
+int main(void)
+{
+ int ret, status;
+ int sockfd, shared_fd;
+ unsigned char *map_buf;
+ unsigned long map_len;
+ struct ion_buffer_info info;
+ struct socket_info skinfo;
+
+ /* This is the client part. Here 0 means client or importer */
+ status = opensocket(&sockfd, SOCKET_NAME, 0);
+ if (status < 0) {
+ fprintf(stderr, "No exporter exists...\n");
+ ret = status;
+ goto err_socket;
+ }
+
+ skinfo.sockfd = sockfd;
+
+ ret = socket_receive_fd(&skinfo);
+ if (ret < 0) {
+ fprintf(stderr, "Failed: socket_receive_fd\n");
+ goto err_recv;
+ }
+
+ shared_fd = skinfo.datafd;
+ printf("Received buffer fd: %d\n", shared_fd);
+ if (shared_fd <= 0) {
+ fprintf(stderr, "ERROR: improper buf fd\n");
+ ret = -1;
+ goto err_fd;
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.buffd = shared_fd;
+ info.buflen = ION_BUFFER_LEN;
+
+ ret = ion_import_buffer_fd(&info);
+ if (ret < 0) {
+ fprintf(stderr, "Failed: ion_use_buffer_fd\n");
+ goto err_import;
+ }
+
+ map_buf = info.buffer;
+ map_len = info.buflen;
+ read_buffer(map_buf, map_len);
+
+ /* Write probably new data to the same buffer again */
+ map_len = ION_BUFFER_LEN;
+ write_buffer(map_buf, map_len);
+
+err_import:
+ ion_close_buffer_fd(&info);
+err_fd:
+err_recv:
+err_socket:
+ closesocket(sockfd, SOCKET_NAME);
+
+ return ret;
+}
diff --git a/tools/testing/selftests/android/ion/ionutils.c b/tools/testing/selftests/android/ion/ionutils.c
new file mode 100644
index 000000000000..ce69c14f51fa
--- /dev/null
+++ b/tools/testing/selftests/android/ion/ionutils.c
@@ -0,0 +1,259 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+//#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "ionutils.h"
+#include "ipcsocket.h"
+
+
+void write_buffer(void *buffer, unsigned long len)
+{
+ int i;
+ unsigned char *ptr = (unsigned char *)buffer;
+
+ if (!ptr) {
+ fprintf(stderr, "<%s>: Invalid buffer...\n", __func__);
+ return;
+ }
+
+ printf("Fill buffer content:\n");
+ memset(ptr, 0xfd, len);
+ for (i = 0; i < len; i++)
+ printf("0x%x ", ptr[i]);
+ printf("\n");
+}
+
+void read_buffer(void *buffer, unsigned long len)
+{
+ int i;
+ unsigned char *ptr = (unsigned char *)buffer;
+
+ if (!ptr) {
+ fprintf(stderr, "<%s>: Invalid buffer...\n", __func__);
+ return;
+ }
+
+ printf("Read buffer content:\n");
+ for (i = 0; i < len; i++)
+ printf("0x%x ", ptr[i]);
+ printf("\n");
+}
+
+int ion_export_buffer_fd(struct ion_buffer_info *ion_info)
+{
+ int i, ret, ionfd, buffer_fd;
+ unsigned int heap_id;
+ unsigned long maplen;
+ unsigned char *map_buffer;
+ struct ion_allocation_data alloc_data;
+ struct ion_heap_query query;
+ struct ion_heap_data heap_data[MAX_HEAP_COUNT];
+
+ if (!ion_info) {
+ fprintf(stderr, "<%s>: Invalid ion info\n", __func__);
+ return -1;
+ }
+
+ /* Create an ION client */
+ ionfd = open(ION_DEVICE, O_RDWR);
+ if (ionfd < 0) {
+ fprintf(stderr, "<%s>: Failed to open ion client: %s\n",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ memset(&query, 0, sizeof(query));
+ query.cnt = MAX_HEAP_COUNT;
+ query.heaps = (unsigned long int)&heap_data[0];
+ /* Query ION heap_id_mask from ION heap */
+ ret = ioctl(ionfd, ION_IOC_HEAP_QUERY, &query);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed: ION_IOC_HEAP_QUERY: %s\n",
+ __func__, strerror(errno));
+ goto err_query;
+ }
+
+ heap_id = MAX_HEAP_COUNT + 1;
+ for (i = 0; i < query.cnt; i++) {
+ if (heap_data[i].type == ion_info->heap_type) {
+ printf("--------------------------------------\n");
+ printf("heap type: %d\n", heap_data[i].type);
+ printf(" heap id: %d\n", heap_data[i].heap_id);
+ printf("heap name: %s\n", heap_data[i].name);
+ printf("--------------------------------------\n");
+ heap_id = heap_data[i].heap_id;
+ break;
+ }
+ }
+
+ if (heap_id > MAX_HEAP_COUNT) {
+ fprintf(stderr, "<%s>: ERROR: heap type does not exists\n",
+ __func__);
+ goto err_heap;
+ }
+
+ alloc_data.len = ion_info->heap_size;
+ alloc_data.heap_id_mask = 1 << heap_id;
+ alloc_data.flags = ion_info->flag_type;
+
+ /* Allocate memory for this ION client as per heap_type */
+ ret = ioctl(ionfd, ION_IOC_ALLOC, &alloc_data);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed: ION_IOC_ALLOC: %s\n",
+ __func__, strerror(errno));
+ goto err_alloc;
+ }
+
+ /* This will return a valid buffer fd */
+ buffer_fd = alloc_data.fd;
+ maplen = alloc_data.len;
+
+ if (buffer_fd < 0 || maplen <= 0) {
+ fprintf(stderr, "<%s>: Invalid map data, fd: %d, len: %ld\n",
+ __func__, buffer_fd, maplen);
+ goto err_fd_data;
+ }
+
+ /* Create memory mapped buffer for the buffer fd */
+ map_buffer = (unsigned char *)mmap(NULL, maplen, PROT_READ|PROT_WRITE,
+ MAP_SHARED, buffer_fd, 0);
+ if (map_buffer == MAP_FAILED) {
+ fprintf(stderr, "<%s>: Failed: mmap: %s\n",
+ __func__, strerror(errno));
+ goto err_mmap;
+ }
+
+ ion_info->ionfd = ionfd;
+ ion_info->buffd = buffer_fd;
+ ion_info->buffer = map_buffer;
+ ion_info->buflen = maplen;
+
+ return 0;
+
+ munmap(map_buffer, maplen);
+
+err_fd_data:
+err_mmap:
+ /* in case of error: close the buffer fd */
+ if (buffer_fd)
+ close(buffer_fd);
+
+err_query:
+err_heap:
+err_alloc:
+ /* In case of error: close the ion client fd */
+ if (ionfd)
+ close(ionfd);
+
+ return -1;
+}
+
+int ion_import_buffer_fd(struct ion_buffer_info *ion_info)
+{
+ int buffd;
+ unsigned char *map_buf;
+ unsigned long map_len;
+
+ if (!ion_info) {
+ fprintf(stderr, "<%s>: Invalid ion info\n", __func__);
+ return -1;
+ }
+
+ map_len = ion_info->buflen;
+ buffd = ion_info->buffd;
+
+ if (buffd < 0 || map_len <= 0) {
+ fprintf(stderr, "<%s>: Invalid map data, fd: %d, len: %ld\n",
+ __func__, buffd, map_len);
+ goto err_buffd;
+ }
+
+ map_buf = (unsigned char *)mmap(NULL, map_len, PROT_READ|PROT_WRITE,
+ MAP_SHARED, buffd, 0);
+ if (map_buf == MAP_FAILED) {
+ printf("<%s>: Failed - mmap: %s\n",
+ __func__, strerror(errno));
+ goto err_mmap;
+ }
+
+ ion_info->buffer = map_buf;
+ ion_info->buflen = map_len;
+
+ return 0;
+
+err_mmap:
+ if (buffd)
+ close(buffd);
+
+err_buffd:
+ return -1;
+}
+
+void ion_close_buffer_fd(struct ion_buffer_info *ion_info)
+{
+ if (ion_info) {
+ /* unmap the buffer properly in the end */
+ munmap(ion_info->buffer, ion_info->buflen);
+ /* close the buffer fd */
+ if (ion_info->buffd > 0)
+ close(ion_info->buffd);
+ /* Finally, close the client fd */
+ if (ion_info->ionfd > 0)
+ close(ion_info->ionfd);
+ printf("<%s>: buffer release successfully....\n", __func__);
+ }
+}
+
+int socket_send_fd(struct socket_info *info)
+{
+ int status;
+ int fd, sockfd;
+ struct socketdata skdata;
+
+ if (!info) {
+ fprintf(stderr, "<%s>: Invalid socket info\n", __func__);
+ return -1;
+ }
+
+ sockfd = info->sockfd;
+ fd = info->datafd;
+ memset(&skdata, 0, sizeof(skdata));
+ skdata.data = fd;
+ skdata.len = sizeof(skdata.data);
+ status = sendtosocket(sockfd, &skdata);
+ if (status < 0) {
+ fprintf(stderr, "<%s>: Failed: sendtosocket\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int socket_receive_fd(struct socket_info *info)
+{
+ int status;
+ int fd, sockfd;
+ struct socketdata skdata;
+
+ if (!info) {
+ fprintf(stderr, "<%s>: Invalid socket info\n", __func__);
+ return -1;
+ }
+
+ sockfd = info->sockfd;
+ memset(&skdata, 0, sizeof(skdata));
+ status = receivefromsocket(sockfd, &skdata);
+ if (status < 0) {
+ fprintf(stderr, "<%s>: Failed: receivefromsocket\n", __func__);
+ return -1;
+ }
+
+ fd = (int)skdata.data;
+ info->datafd = fd;
+
+ return status;
+}
diff --git a/tools/testing/selftests/android/ion/ionutils.h b/tools/testing/selftests/android/ion/ionutils.h
new file mode 100644
index 000000000000..9941eb858576
--- /dev/null
+++ b/tools/testing/selftests/android/ion/ionutils.h
@@ -0,0 +1,55 @@
+#ifndef __ION_UTILS_H
+#define __ION_UTILS_H
+
+#include "ion.h"
+
+#define SOCKET_NAME "ion_socket"
+#define ION_DEVICE "/dev/ion"
+
+#define ION_BUFFER_LEN 4096
+#define MAX_HEAP_COUNT ION_HEAP_TYPE_CUSTOM
+
+struct socket_info {
+ int sockfd;
+ int datafd;
+ unsigned long buflen;
+};
+
+struct ion_buffer_info {
+ int ionfd;
+ int buffd;
+ unsigned int heap_type;
+ unsigned int flag_type;
+ unsigned long heap_size;
+ unsigned long buflen;
+ unsigned char *buffer;
+};
+
+
+/* This is used to fill the data into the mapped buffer */
+void write_buffer(void *buffer, unsigned long len);
+
+/* This is used to read the data from the exported buffer */
+void read_buffer(void *buffer, unsigned long len);
+
+/* This is used to create an ION buffer FD for the kernel buffer
+ * So you can export this same buffer to others in the form of FD
+ */
+int ion_export_buffer_fd(struct ion_buffer_info *ion_info);
+
+/* This is used to import or map an exported FD.
+ * So we point to same buffer without making a copy. Hence zero-copy.
+ */
+int ion_import_buffer_fd(struct ion_buffer_info *ion_info);
+
+/* This is used to close all references for the ION client */
+void ion_close_buffer_fd(struct ion_buffer_info *ion_info);
+
+/* This is used to send FD to another process using socket IPC */
+int socket_send_fd(struct socket_info *skinfo);
+
+/* This is used to receive FD from another process using socket IPC */
+int socket_receive_fd(struct socket_info *skinfo);
+
+
+#endif
diff --git a/tools/testing/selftests/android/ion/ipcsocket.c b/tools/testing/selftests/android/ion/ipcsocket.c
new file mode 100644
index 000000000000..7dc521002095
--- /dev/null
+++ b/tools/testing/selftests/android/ion/ipcsocket.c
@@ -0,0 +1,227 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <errno.h>
+
+#include "ipcsocket.h"
+
+
+int opensocket(int *sockfd, const char *name, int connecttype)
+{
+ int ret, temp = 1;
+
+ if (!name || strlen(name) > MAX_SOCK_NAME_LEN) {
+ fprintf(stderr, "<%s>: Invalid socket name.\n", __func__);
+ return -1;
+ }
+
+ ret = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed socket: <%s>\n",
+ __func__, strerror(errno));
+ return ret;
+ }
+
+ *sockfd = ret;
+ if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&temp, sizeof(int)) < 0) {
+ fprintf(stderr, "<%s>: Failed setsockopt: <%s>\n",
+ __func__, strerror(errno));
+ goto err;
+ }
+
+ sprintf(sock_name, "/tmp/%s", name);
+
+ if (connecttype == 1) {
+ /* This is for Server connection */
+ struct sockaddr_un skaddr;
+ int clientfd;
+ socklen_t sklen;
+
+ unlink(sock_name);
+ memset(&skaddr, 0, sizeof(skaddr));
+ skaddr.sun_family = AF_LOCAL;
+ strcpy(skaddr.sun_path, sock_name);
+
+ ret = bind(*sockfd, (struct sockaddr *)&skaddr,
+ SUN_LEN(&skaddr));
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed bind: <%s>\n",
+ __func__, strerror(errno));
+ goto err;
+ }
+
+ ret = listen(*sockfd, 5);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed listen: <%s>\n",
+ __func__, strerror(errno));
+ goto err;
+ }
+
+ memset(&skaddr, 0, sizeof(skaddr));
+ sklen = sizeof(skaddr);
+
+ ret = accept(*sockfd, (struct sockaddr *)&skaddr,
+ (socklen_t *)&sklen);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed accept: <%s>\n",
+ __func__, strerror(errno));
+ goto err;
+ }
+
+ clientfd = ret;
+ *sockfd = clientfd;
+ } else {
+ /* This is for client connection */
+ struct sockaddr_un skaddr;
+
+ memset(&skaddr, 0, sizeof(skaddr));
+ skaddr.sun_family = AF_LOCAL;
+ strcpy(skaddr.sun_path, sock_name);
+
+ ret = connect(*sockfd, (struct sockaddr *)&skaddr,
+ SUN_LEN(&skaddr));
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed connect: <%s>\n",
+ __func__, strerror(errno));
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ if (*sockfd)
+ close(*sockfd);
+
+ return ret;
+}
+
+int sendtosocket(int sockfd, struct socketdata *skdata)
+{
+ int ret, buffd;
+ unsigned int len;
+ char cmsg_b[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cmsg;
+ struct msghdr msgh;
+ struct iovec iov;
+ struct timeval timeout;
+ fd_set selFDs;
+
+ if (!skdata) {
+ fprintf(stderr, "<%s>: socketdata is NULL\n", __func__);
+ return -1;
+ }
+
+ FD_ZERO(&selFDs);
+ FD_SET(0, &selFDs);
+ FD_SET(sockfd, &selFDs);
+ timeout.tv_sec = 20;
+ timeout.tv_usec = 0;
+
+ ret = select(sockfd+1, NULL, &selFDs, NULL, &timeout);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed select: <%s>\n",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ if (FD_ISSET(sockfd, &selFDs)) {
+ buffd = skdata->data;
+ len = skdata->len;
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_control = &cmsg_b;
+ msgh.msg_controllen = CMSG_LEN(len);
+ iov.iov_base = "OK";
+ iov.iov_len = 2;
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(len);
+ memcpy(CMSG_DATA(cmsg), &buffd, len);
+
+ ret = sendmsg(sockfd, &msgh, MSG_DONTWAIT);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed sendmsg: <%s>\n",
+ __func__, strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int receivefromsocket(int sockfd, struct socketdata *skdata)
+{
+ int ret, buffd;
+ unsigned int len = 0;
+ char cmsg_b[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cmsg;
+ struct msghdr msgh;
+ struct iovec iov;
+ fd_set recvFDs;
+ char data[32];
+
+ if (!skdata) {
+ fprintf(stderr, "<%s>: socketdata is NULL\n", __func__);
+ return -1;
+ }
+
+ FD_ZERO(&recvFDs);
+ FD_SET(0, &recvFDs);
+ FD_SET(sockfd, &recvFDs);
+
+ ret = select(sockfd+1, &recvFDs, NULL, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed select: <%s>\n",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ if (FD_ISSET(sockfd, &recvFDs)) {
+ len = sizeof(buffd);
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_control = &cmsg_b;
+ msgh.msg_controllen = CMSG_LEN(len);
+ iov.iov_base = data;
+ iov.iov_len = sizeof(data)-1;
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(len);
+
+ ret = recvmsg(sockfd, &msgh, MSG_DONTWAIT);
+ if (ret < 0) {
+ fprintf(stderr, "<%s>: Failed recvmsg: <%s>\n",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ memcpy(&buffd, CMSG_DATA(cmsg), len);
+ skdata->data = buffd;
+ skdata->len = len;
+ }
+ return 0;
+}
+
+int closesocket(int sockfd, char *name)
+{
+ char sockname[MAX_SOCK_NAME_LEN];
+
+ if (sockfd)
+ close(sockfd);
+ sprintf(sockname, "/tmp/%s", name);
+ unlink(sockname);
+ shutdown(sockfd, 2);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/android/ion/ipcsocket.h b/tools/testing/selftests/android/ion/ipcsocket.h
new file mode 100644
index 000000000000..b3e84498a8a1
--- /dev/null
+++ b/tools/testing/selftests/android/ion/ipcsocket.h
@@ -0,0 +1,35 @@
+
+#ifndef _IPCSOCKET_H
+#define _IPCSOCKET_H
+
+
+#define MAX_SOCK_NAME_LEN 64
+
+char sock_name[MAX_SOCK_NAME_LEN];
+
+/* This structure is responsible for holding the IPC data
+ * data: hold the buffer fd
+ * len: just the length of 32-bit integer fd
+ */
+struct socketdata {
+ int data;
+ unsigned int len;
+};
+
+/* This API is used to open the IPC socket connection
+ * name: implies a unique socket name in the system
+ * connecttype: implies server(0) or client(1)
+ */
+int opensocket(int *sockfd, const char *name, int connecttype);
+
+/* This is the API to send socket data over IPC socket */
+int sendtosocket(int sockfd, struct socketdata *data);
+
+/* This is the API to receive socket data over IPC socket */
+int receivefromsocket(int sockfd, struct socketdata *data);
+
+/* This is the API to close the socket connection */
+int closesocket(int sockfd, char *name);
+
+
+#endif
diff --git a/tools/testing/selftests/android/run.sh b/tools/testing/selftests/android/run.sh
new file mode 100755
index 000000000000..dd8edf291454
--- /dev/null
+++ b/tools/testing/selftests/android/run.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+(cd ion; ./ion_test.sh)
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index bf092b83e453..3c64f30cf63c 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -4377,11 +4377,10 @@ static struct bpf_test tests[] = {
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_LD_MAP_FD(BPF_REG_1, 0),
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
- BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
- BPF_MOV64_IMM(BPF_REG_1, 0),
- BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
- BPF_MOV64_IMM(BPF_REG_3, 0),
- BPF_EMIT_CALL(BPF_FUNC_probe_write_user),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+ BPF_MOV64_IMM(BPF_REG_2, 0),
+ BPF_EMIT_CALL(BPF_FUNC_trace_printk),
BPF_EXIT_INSN(),
},
.fixup_map2 = { 3 },
@@ -4481,14 +4480,12 @@ static struct bpf_test tests[] = {
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_LD_MAP_FD(BPF_REG_1, 0),
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
- BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1,
offsetof(struct test_val, foo)),
- BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
- BPF_MOV64_IMM(BPF_REG_1, 0),
- BPF_MOV64_IMM(BPF_REG_3, 0),
- BPF_EMIT_CALL(BPF_FUNC_probe_write_user),
+ BPF_MOV64_IMM(BPF_REG_2, 0),
+ BPF_EMIT_CALL(BPF_FUNC_trace_printk),
BPF_EXIT_INSN(),
},
.fixup_map2 = { 3 },
@@ -4618,18 +4615,16 @@ static struct bpf_test tests[] = {
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_LD_MAP_FD(BPF_REG_1, 0),
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
- BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
BPF_MOV64_IMM(BPF_REG_3, 0),
BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3),
- BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
- BPF_MOV64_IMM(BPF_REG_1, 0),
- BPF_MOV64_IMM(BPF_REG_3, 0),
- BPF_EMIT_CALL(BPF_FUNC_probe_write_user),
+ BPF_MOV64_IMM(BPF_REG_2, 0),
+ BPF_EMIT_CALL(BPF_FUNC_trace_printk),
BPF_EXIT_INSN(),
},
.fixup_map2 = { 3 },
- .errstr = "R2 min value is outside of the array range",
+ .errstr = "R1 min value is outside of the array range",
.result = REJECT,
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
},
@@ -4760,20 +4755,18 @@ static struct bpf_test tests[] = {
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
BPF_LD_MAP_FD(BPF_REG_1, 0),
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
- BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
BPF_JMP_IMM(BPF_JGT, BPF_REG_3,
- offsetof(struct test_val, foo), 4),
+ offsetof(struct test_val, foo), 3),
BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3),
- BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
- BPF_MOV64_IMM(BPF_REG_1, 0),
- BPF_MOV64_IMM(BPF_REG_3, 0),
- BPF_EMIT_CALL(BPF_FUNC_probe_write_user),
+ BPF_MOV64_IMM(BPF_REG_2, 0),
+ BPF_EMIT_CALL(BPF_FUNC_trace_printk),
BPF_EXIT_INSN(),
},
.fixup_map2 = { 3 },
- .errstr = "R2 min value is outside of the array range",
+ .errstr = "R1 min value is outside of the array range",
.result = REJECT,
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
},
@@ -5638,7 +5631,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
},
{
- "helper access to variable memory: size = 0 allowed on NULL",
+ "helper access to variable memory: size = 0 allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)",
.insns = {
BPF_MOV64_IMM(BPF_REG_1, 0),
BPF_MOV64_IMM(BPF_REG_2, 0),
@@ -5652,7 +5645,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
},
{
- "helper access to variable memory: size > 0 not allowed on NULL",
+ "helper access to variable memory: size > 0 not allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)",
.insns = {
BPF_MOV64_IMM(BPF_REG_1, 0),
BPF_MOV64_IMM(BPF_REG_2, 0),
@@ -5670,7 +5663,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
},
{
- "helper access to variable memory: size = 0 allowed on != NULL stack pointer",
+ "helper access to variable memory: size = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)",
.insns = {
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
@@ -5687,7 +5680,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
},
{
- "helper access to variable memory: size = 0 allowed on != NULL map pointer",
+ "helper access to variable memory: size = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)",
.insns = {
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -5709,7 +5702,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
},
{
- "helper access to variable memory: size possible = 0 allowed on != NULL stack pointer",
+ "helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)",
.insns = {
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -5734,7 +5727,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
},
{
- "helper access to variable memory: size possible = 0 allowed on != NULL map pointer",
+ "helper access to variable memory: size possible = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)",
.insns = {
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -5757,7 +5750,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
},
{
- "helper access to variable memory: size possible = 0 allowed on != NULL packet pointer",
+ "helper access to variable memory: size possible = 0 allowed on != NULL packet pointer (ARG_PTR_TO_MEM_OR_NULL)",
.insns = {
BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
offsetof(struct __sk_buff, data)),
@@ -5779,6 +5772,105 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
},
{
+ "helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)",
+ .insns = {
+ BPF_MOV64_IMM(BPF_REG_1, 0),
+ BPF_MOV64_IMM(BPF_REG_2, 0),
+ BPF_MOV64_IMM(BPF_REG_3, 0),
+ BPF_EMIT_CALL(BPF_FUNC_probe_read),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "R1 type=inv expected=fp",
+ .result = REJECT,
+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+ },
+ {
+ "helper access to variable memory: size > 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)",
+ .insns = {
+ BPF_MOV64_IMM(BPF_REG_1, 0),
+ BPF_MOV64_IMM(BPF_REG_2, 1),
+ BPF_MOV64_IMM(BPF_REG_3, 0),
+ BPF_EMIT_CALL(BPF_FUNC_probe_read),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "R1 type=inv expected=fp",
+ .result = REJECT,
+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+ },
+ {
+ "helper access to variable memory: size = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)",
+ .insns = {
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
+ BPF_MOV64_IMM(BPF_REG_2, 0),
+ BPF_MOV64_IMM(BPF_REG_3, 0),
+ BPF_EMIT_CALL(BPF_FUNC_probe_read),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+ },
+ {
+ "helper access to variable memory: size = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)",
+ .insns = {
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+ BPF_MOV64_IMM(BPF_REG_2, 0),
+ BPF_MOV64_IMM(BPF_REG_3, 0),
+ BPF_EMIT_CALL(BPF_FUNC_probe_read),
+ BPF_EXIT_INSN(),
+ },
+ .fixup_map1 = { 3 },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+ },
+ {
+ "helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)",
+ .insns = {
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
+ BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0),
+ BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 4),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
+ BPF_MOV64_IMM(BPF_REG_3, 0),
+ BPF_EMIT_CALL(BPF_FUNC_probe_read),
+ BPF_EXIT_INSN(),
+ },
+ .fixup_map1 = { 3 },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+ },
+ {
+ "helper access to variable memory: size possible = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)",
+ .insns = {
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+ BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0),
+ BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 2),
+ BPF_MOV64_IMM(BPF_REG_3, 0),
+ BPF_EMIT_CALL(BPF_FUNC_probe_read),
+ BPF_EXIT_INSN(),
+ },
+ .fixup_map1 = { 3 },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+ },
+ {
"helper access to variable memory: 8 bytes leak",
.insns = {
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
diff --git a/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c b/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c
index 960d02100c26..2d95e5adde72 100644
--- a/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c
+++ b/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c
@@ -19,6 +19,7 @@
#define _GNU_SOURCE
+#include <asm/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
diff --git a/tools/testing/selftests/cpu-hotplug/config b/tools/testing/selftests/cpu-hotplug/config
index e6ab090cfbf3..d4aca2ad5069 100644
--- a/tools/testing/selftests/cpu-hotplug/config
+++ b/tools/testing/selftests/cpu-hotplug/config
@@ -1,2 +1 @@
CONFIG_NOTIFIER_ERROR_INJECTION=y
-CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
diff --git a/tools/testing/selftests/exec/execveat.c b/tools/testing/selftests/exec/execveat.c
index 8d5d1d2ee7c1..67cd4597db2b 100644
--- a/tools/testing/selftests/exec/execveat.c
+++ b/tools/testing/selftests/exec/execveat.c
@@ -147,7 +147,7 @@ static void exe_cp(const char *src, const char *dest)
}
#define XX_DIR_LEN 200
-static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script)
+static int check_execveat_pathmax(int root_dfd, const char *src, int is_script)
{
int fail = 0;
int ii, count, len;
@@ -156,20 +156,30 @@ static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script)
if (*longpath == '\0') {
/* Create a filename close to PATH_MAX in length */
+ char *cwd = getcwd(NULL, 0);
+
+ if (!cwd) {
+ printf("Failed to getcwd(), errno=%d (%s)\n",
+ errno, strerror(errno));
+ return 2;
+ }
+ strcpy(longpath, cwd);
+ strcat(longpath, "/");
memset(longname, 'x', XX_DIR_LEN - 1);
longname[XX_DIR_LEN - 1] = '/';
longname[XX_DIR_LEN] = '\0';
- count = (PATH_MAX - 3) / XX_DIR_LEN;
+ count = (PATH_MAX - 3 - strlen(cwd)) / XX_DIR_LEN;
for (ii = 0; ii < count; ii++) {
strcat(longpath, longname);
mkdir(longpath, 0755);
}
- len = (PATH_MAX - 3) - (count * XX_DIR_LEN);
+ len = (PATH_MAX - 3 - strlen(cwd)) - (count * XX_DIR_LEN);
if (len <= 0)
len = 1;
memset(longname, 'y', len);
longname[len] = '\0';
strcat(longpath, longname);
+ free(cwd);
}
exe_cp(src, longpath);
@@ -190,7 +200,7 @@ static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script)
}
/*
- * Execute as a long pathname relative to ".". If this is a script,
+ * Execute as a long pathname relative to "/". If this is a script,
* the interpreter will launch but fail to open the script because its
* name ("/dev/fd/5/xxx....") is bigger than PATH_MAX.
*
@@ -200,10 +210,10 @@ static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script)
* the exit status shall be 126."), so allow either.
*/
if (is_script)
- fail += check_execveat_invoked_rc(dot_dfd, longpath, 0,
+ fail += check_execveat_invoked_rc(root_dfd, longpath + 1, 0,
127, 126);
else
- fail += check_execveat(dot_dfd, longpath, 0);
+ fail += check_execveat(root_dfd, longpath + 1, 0);
return fail;
}
@@ -218,6 +228,7 @@ static int run_tests(void)
int subdir_dfd_ephemeral = open_or_die("subdir.ephemeral",
O_DIRECTORY|O_RDONLY);
int dot_dfd = open_or_die(".", O_DIRECTORY|O_RDONLY);
+ int root_dfd = open_or_die("/", O_DIRECTORY|O_RDONLY);
int dot_dfd_path = open_or_die(".", O_DIRECTORY|O_RDONLY|O_PATH);
int dot_dfd_cloexec = open_or_die(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC);
int fd = open_or_die("execveat", O_RDONLY);
@@ -353,8 +364,8 @@ static int run_tests(void)
/* Attempt to execute relative to non-directory => ENOTDIR */
fail += check_execveat_fail(fd, "execveat", 0, ENOTDIR);
- fail += check_execveat_pathmax(dot_dfd, "execveat", 0);
- fail += check_execveat_pathmax(dot_dfd, "script", 1);
+ fail += check_execveat_pathmax(root_dfd, "execveat", 0);
+ fail += check_execveat_pathmax(root_dfd, "script", 1);
return fail;
}
diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh
index a52a3bab532b..34a42c68ebfb 100755
--- a/tools/testing/selftests/firmware/fw_fallback.sh
+++ b/tools/testing/selftests/firmware/fw_fallback.sh
@@ -86,6 +86,11 @@ load_fw_cancel()
load_fw_custom()
{
+ if [ ! -e "$DIR"/trigger_custom_fallback ]; then
+ echo "$0: custom fallback trigger not present, ignoring test" >&2
+ return 1
+ fi
+
local name="$1"
local file="$2"
@@ -108,11 +113,17 @@ load_fw_custom()
# Wait for request to finish.
wait
+ return 0
}
load_fw_custom_cancel()
{
+ if [ ! -e "$DIR"/trigger_custom_fallback ]; then
+ echo "$0: canceling custom fallback trigger not present, ignoring test" >&2
+ return 1
+ fi
+
local name="$1"
local file="$2"
@@ -133,6 +144,7 @@ load_fw_custom_cancel()
# Wait for request to finish.
wait
+ return 0
}
load_fw_fallback_with_child()
@@ -227,20 +239,22 @@ else
echo "$0: cancelling fallback mechanism works"
fi
-load_fw_custom "$NAME" "$FW"
-if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
- echo "$0: firmware was not loaded" >&2
- exit 1
-else
- echo "$0: custom fallback loading mechanism works"
+if load_fw_custom "$NAME" "$FW" ; then
+ if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not loaded" >&2
+ exit 1
+ else
+ echo "$0: custom fallback loading mechanism works"
+ fi
fi
-load_fw_custom_cancel "nope-$NAME" "$FW"
-if diff -q "$FW" /dev/test_firmware >/dev/null ; then
- echo "$0: firmware was expected to be cancelled" >&2
- exit 1
-else
- echo "$0: cancelling custom fallback mechanism works"
+if load_fw_custom_cancel "nope-$NAME" "$FW" ; then
+ if diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was expected to be cancelled" >&2
+ exit 1
+ else
+ echo "$0: cancelling custom fallback mechanism works"
+ fi
fi
set +e
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh
index 62f2d6f54929..b1f20fef36c7 100755
--- a/tools/testing/selftests/firmware/fw_filesystem.sh
+++ b/tools/testing/selftests/firmware/fw_filesystem.sh
@@ -70,9 +70,13 @@ if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then
exit 1
fi
-if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then
- echo "$0: empty filename should not succeed (async)" >&2
- exit 1
+if [ ! -e "$DIR"/trigger_async_request ]; then
+ echo "$0: empty filename: async trigger not present, ignoring test" >&2
+else
+ if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then
+ echo "$0: empty filename should not succeed (async)" >&2
+ exit 1
+ fi
fi
# Request a firmware that doesn't exist, it should fail.
@@ -105,17 +109,21 @@ else
fi
# Try the asynchronous version too
-if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then
- echo "$0: could not trigger async request" >&2
- exit 1
-fi
-
-# Verify the contents are what we expect.
-if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
- echo "$0: firmware was not loaded (async)" >&2
- exit 1
+if [ ! -e "$DIR"/trigger_async_request ]; then
+ echo "$0: firmware loading: async trigger not present, ignoring test" >&2
else
- echo "$0: async filesystem loading works"
+ if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then
+ echo "$0: could not trigger async request" >&2
+ exit 1
+ fi
+
+ # Verify the contents are what we expect.
+ if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not loaded (async)" >&2
+ exit 1
+ else
+ echo "$0: async filesystem loading works"
+ fi
fi
### Batched requests tests
diff --git a/tools/testing/selftests/ftrace/config b/tools/testing/selftests/ftrace/config
index 8a1c9f949fe0..b01924c71c09 100644
--- a/tools/testing/selftests/ftrace/config
+++ b/tools/testing/selftests/ftrace/config
@@ -1,2 +1,6 @@
CONFIG_KPROBES=y
CONFIG_FTRACE=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_TRACER_SNAPSHOT=y
+CONFIG_STACK_TRACER=y
+CONFIG_HIST_TRIGGERS=y
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
index abc706cf7702..f9a9d424c980 100755
--- a/tools/testing/selftests/ftrace/ftracetest
+++ b/tools/testing/selftests/ftrace/ftracetest
@@ -222,7 +222,14 @@ SIG_RESULT=
SIG_BASE=36 # Use realtime signals
SIG_PID=$$
+exit_pass () {
+ exit 0
+}
+
SIG_FAIL=$((SIG_BASE + FAIL))
+exit_fail () {
+ exit 1
+}
trap 'SIG_RESULT=$FAIL' $SIG_FAIL
SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED))
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc
index aa51f6c17359..0696098d6408 100644
--- a/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc
@@ -2,4 +2,4 @@
# description: Basic event tracing check
test -f available_events -a -f set_event -a -d events
# check scheduler events are available
-grep -q sched available_events && exit 0 || exit $FAIL
+grep -q sched available_events && exit_pass || exit_fail
diff --git a/tools/testing/selftests/ftrace/test.d/event/event-enable.tc b/tools/testing/selftests/ftrace/test.d/event/event-enable.tc
index 6ff851a75884..9daf034186f5 100644
--- a/tools/testing/selftests/ftrace/test.d/event/event-enable.tc
+++ b/tools/testing/selftests/ftrace/test.d/event/event-enable.tc
@@ -11,7 +11,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
yield() {
diff --git a/tools/testing/selftests/ftrace/test.d/event/event-pid.tc b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc
index cc14feec6e1f..132478b305c2 100644
--- a/tools/testing/selftests/ftrace/test.d/event/event-pid.tc
+++ b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc
@@ -13,7 +13,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
yield() {
diff --git a/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc b/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc
index 85094904aa79..6a37a8642ee6 100644
--- a/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc
+++ b/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc
@@ -11,7 +11,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
yield() {
diff --git a/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc b/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc
index cc1cf4d30ef5..4e9b6e2c0219 100644
--- a/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc
+++ b/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc
@@ -10,7 +10,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
yield() {
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc
index 45df747887e0..1aec99d108eb 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc
@@ -28,7 +28,7 @@ do_reset() {
fail() { # msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
disable_tracing
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc
index 0387e22e7577..9f8d27ca39cf 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc
@@ -18,7 +18,7 @@ do_reset() {
fail() { # msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
disable_tracing
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc
index 78524fcc25ae..524ce24b3c22 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc
@@ -51,7 +51,7 @@ do_reset() {
fail() { # msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
yield() {
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
index 9d4afcca1e36..6fed4cf2db81 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
@@ -27,7 +27,7 @@ do_reset() {
fail() { # mesg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
SLEEP_TIME=".1"
@@ -48,8 +48,7 @@ test_event_enabled() {
e=`cat $EVENT_ENABLE`
if [ "$e" != $val ]; then
- echo "Expected $val but found $e"
- exit 1
+ fail "Expected $val but found $e"
fi
}
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc
index fe0dc5a7ea26..b2d5a8febfe8 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc
@@ -32,7 +32,7 @@ fail() { # mesg
reset_tracer
echo > set_ftrace_filter
echo $1
- exit $FAIL
+ exit_fail
}
echo "Testing function tracer with profiler:"
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
index 5ad723724adb..0f3f92622e33 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
@@ -26,14 +26,14 @@ do_reset() {
fail() { # mesg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
do_reset
FILTER=set_ftrace_filter
FUNC1="schedule"
-FUNC2="do_IRQ"
+FUNC2="do_softirq"
ALL_FUNCS="#### all functions enabled ####"
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
index cdc92a371cd7..f6d9ac73268a 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
@@ -27,7 +27,7 @@ do_reset() {
fail() { # mesg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
SLEEP_TIME=".1"
diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc
index d7f48b55df51..4fa0f79144f4 100644
--- a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc
+++ b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc
@@ -11,7 +11,7 @@ fail() { # mesg
rmdir foo 2>/dev/null
echo $1
set -e
- exit $FAIL
+ exit_fail
}
cd instances
diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance.tc b/tools/testing/selftests/ftrace/test.d/instances/instance.tc
index ddda62203366..b84651283bf3 100644
--- a/tools/testing/selftests/ftrace/test.d/instances/instance.tc
+++ b/tools/testing/selftests/ftrace/test.d/instances/instance.tc
@@ -11,7 +11,7 @@ fail() { # mesg
rmdir x y z 2>/dev/null
echo $1
set -e
- exit $FAIL
+ exit_fail
}
cd instances
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
index 0e6f415c6152..bbc443a9190c 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
@@ -9,7 +9,7 @@ echo > kprobe_events
echo p:myevent _do_fork > kprobe_events
test -d events/kprobes/myevent
echo 1 > events/kprobes/myevent/enable
-echo > kprobe_events && exit 1 # this must fail
+echo > kprobe_events && exit_fail # this must fail
echo 0 > events/kprobes/myevent/enable
echo > kprobe_events # this must succeed
clear_trace
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
index 679bbd23bcc3..8b43c6804fc3 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
@@ -14,5 +14,5 @@ echo 1 > events/kprobes/testprobe/enable
echo 0 > events/kprobes/testprobe/enable
echo "-:testprobe" >> kprobe_events
clear_trace
-test -d events/kprobes/testprobe && exit 1 || exit 0
+test -d events/kprobes/testprobe && exit_fail || exit_pass
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc
index 17d33ba192f6..2a1755bfc290 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc
@@ -35,4 +35,4 @@ check_types $ARGS
echo "-:testprobe" >> kprobe_events
clear_trace
-test -d events/kprobes/testprobe && exit 1 || exit 0
+test -d events/kprobes/testprobe && exit_fail || exit_pass
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
index f1825bdbe3f3..321954683aaa 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
@@ -14,4 +14,4 @@ echo 1 > events/kprobes/testprobe2/enable
echo 0 > events/kprobes/testprobe2/enable
echo '-:testprobe2' >> kprobe_events
clear_trace
-test -d events/kprobes/testprobe2 && exit 1 || exit 0
+test -d events/kprobes/testprobe2 && exit_fail || exit_pass
diff --git a/tools/testing/selftests/ftrace/test.d/template b/tools/testing/selftests/ftrace/test.d/template
index 5448f7abad5f..5c39ceb18a0d 100644
--- a/tools/testing/selftests/ftrace/test.d/template
+++ b/tools/testing/selftests/ftrace/test.d/template
@@ -4,6 +4,7 @@
# Note that all tests are run with "errexit" option.
exit 0 # Return 0 if the test is passed, otherwise return !0
+# Or you can call exit_pass for passed test, and exit_fail for failed test.
# If the test could not run because of lack of feature, call exit_unsupported
# If the test returned unclear results, call exit_unresolved
# If the test is a dummy, or a placeholder, call exit_untested
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc
index 839ac4320b24..28cc355a3a7b 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc
@@ -12,7 +12,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
if [ ! -f set_event -o ! -d events/sched ]; then
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc
index 66873c4b12c9..a48e23eb8a8b 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc
@@ -12,7 +12,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
if [ ! -f set_event -o ! -d events/sched ]; then
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc
index 4237b32769f1..8da80efc44d8 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc
@@ -12,7 +12,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
if [ ! -f set_event -o ! -d events/sched ]; then
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc
index d24e2b8bd863..449fe9ff91a2 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc
@@ -12,7 +12,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
if [ ! -f set_event -o ! -d events/sched ]; then
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc
index 4c0774fff378..c5ef8b9d02b3 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc
@@ -12,7 +12,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
if [ ! -f set_event -o ! -d events/sched ]; then
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc
index 3fc6321e081f..ed38f0050d77 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc
@@ -11,7 +11,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
if [ ! -f set_event -o ! -d events/sched ]; then
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc
index 3652824f81ed..3121d795a868 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc
@@ -11,7 +11,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
if [ ! -f set_event -o ! -d events/sched ]; then
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc
index 6d9051cdf408..c59d9eb546da 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc
@@ -11,7 +11,7 @@ do_reset() {
fail() { #msg
do_reset
echo $1
- exit $FAIL
+ exit_fail
}
if [ ! -f set_event -o ! -d events/sched ]; then
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
index 845e5f67b6f0..132a54f74e88 100644
--- a/tools/testing/selftests/memfd/memfd_test.c
+++ b/tools/testing/selftests/memfd/memfd_test.c
@@ -515,7 +515,7 @@ static void mfd_assert_grow_write(int fd)
buf = malloc(mfd_def_size * 8);
if (!buf) {
- printf("malloc(%d) failed: %m\n", mfd_def_size * 8);
+ printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
abort();
}
@@ -535,7 +535,7 @@ static void mfd_fail_grow_write(int fd)
buf = malloc(mfd_def_size * 8);
if (!buf) {
- printf("malloc(%d) failed: %m\n", mfd_def_size * 8);
+ printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
abort();
}
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
index 23db11c94b59..86636d207adf 100644
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -4,10 +4,10 @@ all:
include ../lib.mk
TEST_PROGS := mem-on-off-test.sh
-override RUN_TESTS := ./mem-on-off-test.sh -r 2 || echo "selftests: memory-hotplug [FAIL]"
+override RUN_TESTS := ./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]"
override EMIT_TESTS := echo "$(RUN_TESTS)"
run_full_test:
- @/bin/bash ./mem-on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
+ @/bin/bash ./mem-on-off-test.sh && echo "memory-hotplug selftests: [PASS]" || echo "memory-hotplug selftests: [FAIL]"
clean:
diff --git a/tools/testing/selftests/seccomp/.gitignore b/tools/testing/selftests/seccomp/.gitignore
index 346d83ca8069..5af29d3a1b0a 100644
--- a/tools/testing/selftests/seccomp/.gitignore
+++ b/tools/testing/selftests/seccomp/.gitignore
@@ -1 +1,2 @@
seccomp_bpf
+seccomp_benchmark
diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore
index cc986621f512..2c8ac8416299 100644
--- a/tools/testing/selftests/timers/.gitignore
+++ b/tools/testing/selftests/timers/.gitignore
@@ -18,3 +18,5 @@ threadtest
valid-adjtimex
adjtick
set-tz
+freq-step
+rtctest_setdate
diff --git a/tools/testing/selftests/vDSO/vdso_test.c b/tools/testing/selftests/vDSO/vdso_test.c
index 8daeb7d7032c..2df26bd0099c 100644
--- a/tools/testing/selftests/vDSO/vdso_test.c
+++ b/tools/testing/selftests/vDSO/vdso_test.c
@@ -19,6 +19,19 @@ extern void *vdso_sym(const char *version, const char *name);
extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
extern void vdso_init_from_auxv(void *auxv);
+/*
+ * ARM64's vDSO exports its gettimeofday() implementation with a different
+ * name and version from other architectures, so we need to handle it as
+ * a special case.
+ */
+#if defined(__aarch64__)
+const char *version = "LINUX_2.6.39";
+const char *name = "__kernel_gettimeofday";
+#else
+const char *version = "LINUX_2.6";
+const char *name = "__vdso_gettimeofday";
+#endif
+
int main(int argc, char **argv)
{
unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
@@ -31,10 +44,10 @@ int main(int argc, char **argv)
/* Find gettimeofday. */
typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
- gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
+ gtod_t gtod = (gtod_t)vdso_sym(version, name);
if (!gtod) {
- printf("Could not find __vdso_gettimeofday\n");
+ printf("Could not find %s\n", name);
return 1;
}
@@ -45,7 +58,7 @@ int main(int argc, char **argv)
printf("The time is %lld.%06lld\n",
(long long)tv.tv_sec, (long long)tv.tv_usec);
} else {
- printf("__vdso_gettimeofday failed\n");
+ printf("%s failed\n", name);
}
return 0;
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
index 142c565bb351..1ca2ee4d15b9 100644
--- a/tools/testing/selftests/vm/.gitignore
+++ b/tools/testing/selftests/vm/.gitignore
@@ -8,3 +8,5 @@ on-fault-limit
transhuge-stress
userfaultfd
mlock-intersect-test
+mlock-random-test
+virtual_address_range
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index e49eca1915f8..7f45806bd863 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -18,6 +18,7 @@ TEST_GEN_FILES += transhuge-stress
TEST_GEN_FILES += userfaultfd
TEST_GEN_FILES += mlock-random-test
TEST_GEN_FILES += virtual_address_range
+TEST_GEN_FILES += gup_benchmark
TEST_PROGS := run_vmtests
diff --git a/tools/testing/selftests/vm/gup_benchmark.c b/tools/testing/selftests/vm/gup_benchmark.c
new file mode 100644
index 000000000000..36df55132036
--- /dev/null
+++ b/tools/testing/selftests/vm/gup_benchmark.c
@@ -0,0 +1,91 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/types.h>
+
+#define MB (1UL << 20)
+#define PAGE_SIZE sysconf(_SC_PAGESIZE)
+
+#define GUP_FAST_BENCHMARK _IOWR('g', 1, struct gup_benchmark)
+
+struct gup_benchmark {
+ __u64 delta_usec;
+ __u64 addr;
+ __u64 size;
+ __u32 nr_pages_per_call;
+ __u32 flags;
+};
+
+int main(int argc, char **argv)
+{
+ struct gup_benchmark gup;
+ unsigned long size = 128 * MB;
+ int i, fd, opt, nr_pages = 1, thp = -1, repeats = 1, write = 0;
+ char *p;
+
+ while ((opt = getopt(argc, argv, "m:r:n:tT")) != -1) {
+ switch (opt) {
+ case 'm':
+ size = atoi(optarg) * MB;
+ break;
+ case 'r':
+ repeats = atoi(optarg);
+ break;
+ case 'n':
+ nr_pages = atoi(optarg);
+ break;
+ case 't':
+ thp = 1;
+ break;
+ case 'T':
+ thp = 0;
+ break;
+ case 'w':
+ write = 1;
+ default:
+ return -1;
+ }
+ }
+
+ gup.nr_pages_per_call = nr_pages;
+ gup.flags = write;
+
+ fd = open("/sys/kernel/debug/gup_benchmark", O_RDWR);
+ if (fd == -1)
+ perror("open"), exit(1);
+
+ p = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (p == MAP_FAILED)
+ perror("mmap"), exit(1);
+ gup.addr = (unsigned long)p;
+
+ if (thp == 1)
+ madvise(p, size, MADV_HUGEPAGE);
+ else if (thp == 0)
+ madvise(p, size, MADV_NOHUGEPAGE);
+
+ for (; (unsigned long)p < gup.addr + size; p += PAGE_SIZE)
+ p[0] = 0;
+
+ for (i = 0; i < repeats; i++) {
+ gup.size = size;
+ if (ioctl(fd, GUP_FAST_BENCHMARK, &gup))
+ perror("ioctl"), exit(1);
+
+ printf("Time: %lld us", gup.delta_usec);
+ if (gup.size != size)
+ printf(", truncated (size: %lld)", gup.size);
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile
index 21169322baea..735a510230c3 100644
--- a/tools/thermal/tmon/Makefile
+++ b/tools/thermal/tmon/Makefile
@@ -1,10 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
+# We need this for the "cc-option" macro.
+include ../../../scripts/Kbuild.include
+
VERSION = 1.0
BINDIR=usr/bin
WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
-CFLAGS+= -O1 ${WARNFLAGS} -fstack-protector
-CC=$(CROSS_COMPILE)gcc
+CFLAGS+= -O1 ${WARNFLAGS}
+# Add "-fstack-protector" only if toolchain supports it.
+CFLAGS+= $(call cc-option,-fstack-protector)
+CC?= $(CROSS_COMPILE)gcc
+PKG_CONFIG?= pkg-config
CFLAGS+=-D VERSION=\"$(VERSION)\"
LDFLAGS+=
@@ -19,12 +25,12 @@ STATIC := --static
endif
TMON_LIBS=-lm -lpthread
-TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || \
- pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \
+TMON_LIBS += $(shell $(PKG_CONFIG) --libs $(STATIC) panelw ncursesw 2> /dev/null || \
+ $(PKG_CONFIG) --libs $(STATIC) panel ncurses 2> /dev/null || \
echo -lpanel -lncurses)
-CFLAGS += $(shell pkg-config --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
- pkg-config --cflags $(STATIC) panel ncurses 2> /dev/null)
+CFLAGS += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
+ $(PKG_CONFIG) --cflags $(STATIC) panel ncurses 2> /dev/null)
OBJS = tmon.o tui.o sysfs.o pid.o
OBJS +=
diff --git a/tools/wmi/Makefile b/tools/wmi/Makefile
new file mode 100644
index 000000000000..e664f1167388
--- /dev/null
+++ b/tools/wmi/Makefile
@@ -0,0 +1,18 @@
+PREFIX ?= /usr
+SBINDIR ?= sbin
+INSTALL ?= install
+CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
+CC = $(CROSS_COMPILE)gcc
+
+TARGET = dell-smbios-example
+
+all: $(TARGET)
+
+%: %.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+ $(RM) $(TARGET)
+
+install: dell-smbios-example
+ $(INSTALL) -D -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/$(SBINDIR)/$(TARGET)
diff --git a/tools/wmi/dell-smbios-example.c b/tools/wmi/dell-smbios-example.c
new file mode 100644
index 000000000000..9d3bde081249
--- /dev/null
+++ b/tools/wmi/dell-smbios-example.c
@@ -0,0 +1,210 @@
+/*
+ * Sample application for SMBIOS communication over WMI interface
+ * Performs the following:
+ * - Simple cmd_class/cmd_select lookup for TPM information
+ * - Simple query of known tokens and their values
+ * - Simple activation of a token
+ *
+ * Copyright (C) 2017 Dell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+/* if uapi header isn't installed, this might not yet exist */
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+#include <linux/wmi.h>
+
+/* It would be better to discover these using udev, but for a simple
+ * application they're hardcoded
+ */
+static const char *ioctl_devfs = "/dev/wmi/dell-smbios";
+static const char *token_sysfs =
+ "/sys/bus/platform/devices/dell-smbios.0/tokens";
+
+static void show_buffer(struct dell_wmi_smbios_buffer *buffer)
+{
+ printf("Call: %x/%x [%x,%x,%x,%x]\nResults: [%8x,%8x,%8x,%8x]\n",
+ buffer->std.cmd_class, buffer->std.cmd_select,
+ buffer->std.input[0], buffer->std.input[1],
+ buffer->std.input[2], buffer->std.input[3],
+ buffer->std.output[0], buffer->std.output[1],
+ buffer->std.output[2], buffer->std.output[3]);
+}
+
+static int run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer *buffer)
+{
+ int fd;
+ int ret;
+
+ fd = open(ioctl_devfs, O_NONBLOCK);
+ ret = ioctl(fd, DELL_WMI_SMBIOS_CMD, buffer);
+ close(fd);
+ return ret;
+}
+
+static int find_token(__u16 token, __u16 *location, __u16 *value)
+{
+ char location_sysfs[60];
+ char value_sysfs[57];
+ char buf[4096];
+ FILE *f;
+ int ret;
+
+ ret = sprintf(value_sysfs, "%s/%04x_value", token_sysfs, token);
+ if (ret < 0) {
+ printf("sprintf value failed\n");
+ return 2;
+ }
+ f = fopen(value_sysfs, "rb");
+ if (!f) {
+ printf("failed to open %s\n", value_sysfs);
+ return 2;
+ }
+ fread(buf, 1, 4096, f);
+ fclose(f);
+ *value = (__u16) strtol(buf, NULL, 16);
+
+ ret = sprintf(location_sysfs, "%s/%04x_location", token_sysfs, token);
+ if (ret < 0) {
+ printf("sprintf location failed\n");
+ return 1;
+ }
+ f = fopen(location_sysfs, "rb");
+ if (!f) {
+ printf("failed to open %s\n", location_sysfs);
+ return 2;
+ }
+ fread(buf, 1, 4096, f);
+ fclose(f);
+ *location = (__u16) strtol(buf, NULL, 16);
+
+ if (*location)
+ return 0;
+ return 2;
+}
+
+static int token_is_active(__u16 *location, __u16 *cmpvalue,
+ struct dell_wmi_smbios_buffer *buffer)
+{
+ int ret;
+
+ buffer->std.cmd_class = CLASS_TOKEN_READ;
+ buffer->std.cmd_select = SELECT_TOKEN_STD;
+ buffer->std.input[0] = *location;
+ ret = run_wmi_smbios_cmd(buffer);
+ if (ret != 0 || buffer->std.output[0] != 0)
+ return ret;
+ ret = (buffer->std.output[1] == *cmpvalue);
+ return ret;
+}
+
+static int query_token(__u16 token, struct dell_wmi_smbios_buffer *buffer)
+{
+ __u16 location;
+ __u16 value;
+ int ret;
+
+ ret = find_token(token, &location, &value);
+ if (ret != 0) {
+ printf("unable to find token %04x\n", token);
+ return 1;
+ }
+ return token_is_active(&location, &value, buffer);
+}
+
+static int activate_token(struct dell_wmi_smbios_buffer *buffer,
+ __u16 token)
+{
+ __u16 location;
+ __u16 value;
+ int ret;
+
+ ret = find_token(token, &location, &value);
+ if (ret != 0) {
+ printf("unable to find token %04x\n", token);
+ return 1;
+ }
+ buffer->std.cmd_class = CLASS_TOKEN_WRITE;
+ buffer->std.cmd_select = SELECT_TOKEN_STD;
+ buffer->std.input[0] = location;
+ buffer->std.input[1] = 1;
+ ret = run_wmi_smbios_cmd(buffer);
+ return ret;
+}
+
+static int query_buffer_size(__u64 *buffer_size)
+{
+ FILE *f;
+
+ f = fopen(ioctl_devfs, "rb");
+ if (!f)
+ return -EINVAL;
+ fread(buffer_size, sizeof(__u64), 1, f);
+ fclose(f);
+ return EXIT_SUCCESS;
+}
+
+int main(void)
+{
+ struct dell_wmi_smbios_buffer *buffer;
+ int ret;
+ __u64 value = 0;
+
+ ret = query_buffer_size(&value);
+ if (ret == EXIT_FAILURE || !value) {
+ printf("Unable to read buffer size\n");
+ goto out;
+ }
+ printf("Detected required buffer size %lld\n", value);
+
+ buffer = malloc(value);
+ if (buffer == NULL) {
+ printf("failed to alloc memory for ioctl\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ buffer->length = value;
+
+ /* simple SMBIOS call for looking up TPM info */
+ buffer->std.cmd_class = CLASS_FLASH_INTERFACE;
+ buffer->std.cmd_select = SELECT_FLASH_INTERFACE;
+ buffer->std.input[0] = 2;
+ ret = run_wmi_smbios_cmd(buffer);
+ if (ret) {
+ printf("smbios ioctl failed: %d\n", ret);
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ show_buffer(buffer);
+
+ /* query some tokens */
+ ret = query_token(CAPSULE_EN_TOKEN, buffer);
+ printf("UEFI Capsule enabled token is: %d\n", ret);
+ ret = query_token(CAPSULE_DIS_TOKEN, buffer);
+ printf("UEFI Capsule disabled token is: %d\n", ret);
+
+ /* activate UEFI capsule token if disabled */
+ if (ret) {
+ printf("Enabling UEFI capsule token");
+ if (activate_token(buffer, CAPSULE_EN_TOKEN)) {
+ printf("activate failed\n");
+ ret = -1;
+ goto out;
+ }
+ }
+ ret = EXIT_SUCCESS;
+out:
+ free(buffer);
+ return ret;
+}