diff options
Diffstat (limited to 'tools')
73 files changed, 2921 insertions, 230 deletions
diff --git a/tools/Makefile b/tools/Makefile index 0ba0df3b516f..6339f6ac3ccb 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -8,23 +8,24 @@ include scripts/Makefile.include | |||
8 | help: | 8 | help: |
9 | @echo 'Possible targets:' | 9 | @echo 'Possible targets:' |
10 | @echo '' | 10 | @echo '' |
11 | @echo ' acpi - ACPI tools' | 11 | @echo ' acpi - ACPI tools' |
12 | @echo ' cgroup - cgroup tools' | 12 | @echo ' cgroup - cgroup tools' |
13 | @echo ' cpupower - a tool for all things x86 CPU power' | 13 | @echo ' cpupower - a tool for all things x86 CPU power' |
14 | @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' | 14 | @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' |
15 | @echo ' hv - tools used when in Hyper-V clients' | 15 | @echo ' freefall - laptop accelerometer program for disk protection' |
16 | @echo ' iio - IIO tools' | 16 | @echo ' hv - tools used when in Hyper-V clients' |
17 | @echo ' lguest - a minimal 32-bit x86 hypervisor' | 17 | @echo ' iio - IIO tools' |
18 | @echo ' perf - Linux performance measurement and analysis tool' | 18 | @echo ' lguest - a minimal 32-bit x86 hypervisor' |
19 | @echo ' selftests - various kernel selftests' | 19 | @echo ' net - misc networking tools' |
20 | @echo ' turbostat - Intel CPU idle stats and freq reporting tool' | 20 | @echo ' perf - Linux performance measurement and analysis tool' |
21 | @echo ' usb - USB testing tools' | 21 | @echo ' selftests - various kernel selftests' |
22 | @echo ' virtio - vhost test module' | 22 | @echo ' spi - spi tools' |
23 | @echo ' net - misc networking tools' | 23 | @echo ' tmon - thermal monitoring and tuning tool' |
24 | @echo ' vm - misc vm tools' | 24 | @echo ' turbostat - Intel CPU idle stats and freq reporting tool' |
25 | @echo ' usb - USB testing tools' | ||
26 | @echo ' virtio - vhost test module' | ||
27 | @echo ' vm - misc vm tools' | ||
25 | @echo ' x86_energy_perf_policy - Intel energy policy tool' | 28 | @echo ' x86_energy_perf_policy - Intel energy policy tool' |
26 | @echo ' tmon - thermal monitoring and tuning tool' | ||
27 | @echo ' freefall - laptop accelerometer program for disk protection' | ||
28 | @echo '' | 29 | @echo '' |
29 | @echo 'You can do:' | 30 | @echo 'You can do:' |
30 | @echo ' $$ make -C tools/ <tool>_install' | 31 | @echo ' $$ make -C tools/ <tool>_install' |
@@ -52,7 +53,7 @@ acpi: FORCE | |||
52 | cpupower: FORCE | 53 | cpupower: FORCE |
53 | $(call descend,power/$@) | 54 | $(call descend,power/$@) |
54 | 55 | ||
55 | cgroup firewire hv guest usb virtio vm net iio: FORCE | 56 | cgroup firewire hv guest spi usb virtio vm net iio: FORCE |
56 | $(call descend,$@) | 57 | $(call descend,$@) |
57 | 58 | ||
58 | liblockdep: FORCE | 59 | liblockdep: FORCE |
@@ -118,7 +119,7 @@ acpi_clean: | |||
118 | cpupower_clean: | 119 | cpupower_clean: |
119 | $(call descend,power/cpupower,clean) | 120 | $(call descend,power/cpupower,clean) |
120 | 121 | ||
121 | cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean iio_clean: | 122 | cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean: |
122 | $(call descend,$(@:_clean=),clean) | 123 | $(call descend,$(@:_clean=),clean) |
123 | 124 | ||
124 | liblockdep_clean: | 125 | liblockdep_clean: |
@@ -127,6 +128,12 @@ liblockdep_clean: | |||
127 | libapi_clean: | 128 | libapi_clean: |
128 | $(call descend,lib/api,clean) | 129 | $(call descend,lib/api,clean) |
129 | 130 | ||
131 | libbpf_clean: | ||
132 | $(call descend,lib/bpf,clean) | ||
133 | |||
134 | libsubcmd_clean: | ||
135 | $(call descend,lib/subcmd,clean) | ||
136 | |||
130 | perf_clean: | 137 | perf_clean: |
131 | $(call descend,$(@:_clean=),clean) | 138 | $(call descend,$(@:_clean=),clean) |
132 | 139 | ||
@@ -142,9 +149,12 @@ tmon_clean: | |||
142 | freefall_clean: | 149 | freefall_clean: |
143 | $(call descend,laptop/freefall,clean) | 150 | $(call descend,laptop/freefall,clean) |
144 | 151 | ||
152 | build_clean: | ||
153 | $(call descend,build,clean) | ||
154 | |||
145 | clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ | 155 | clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ |
146 | perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \ | 156 | perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ |
147 | vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ | 157 | vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ |
148 | freefall_clean | 158 | freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean |
149 | 159 | ||
150 | .PHONY: FORCE | 160 | .PHONY: FORCE |
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c index 33cf6f20bd4e..81025cade45f 100644 --- a/tools/build/feature/test-all.c +++ b/tools/build/feature/test-all.c | |||
@@ -125,6 +125,10 @@ | |||
125 | # include "test-get_cpuid.c" | 125 | # include "test-get_cpuid.c" |
126 | #undef main | 126 | #undef main |
127 | 127 | ||
128 | #define main main_test_bpf | ||
129 | # include "test-bpf.c" | ||
130 | #undef main | ||
131 | |||
128 | int main(int argc, char *argv[]) | 132 | int main(int argc, char *argv[]) |
129 | { | 133 | { |
130 | main_test_libpython(); | 134 | main_test_libpython(); |
@@ -153,6 +157,7 @@ int main(int argc, char *argv[]) | |||
153 | main_test_pthread_attr_setaffinity_np(); | 157 | main_test_pthread_attr_setaffinity_np(); |
154 | main_test_lzma(); | 158 | main_test_lzma(); |
155 | main_test_get_cpuid(); | 159 | main_test_get_cpuid(); |
160 | main_test_bpf(); | ||
156 | 161 | ||
157 | return 0; | 162 | return 0; |
158 | } | 163 | } |
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c index 062bac811af9..b389026839b9 100644 --- a/tools/build/feature/test-bpf.c +++ b/tools/build/feature/test-bpf.c | |||
@@ -1,9 +1,23 @@ | |||
1 | #include <asm/unistd.h> | ||
1 | #include <linux/bpf.h> | 2 | #include <linux/bpf.h> |
3 | #include <unistd.h> | ||
4 | |||
5 | #ifndef __NR_bpf | ||
6 | # if defined(__i386__) | ||
7 | # define __NR_bpf 357 | ||
8 | # elif defined(__x86_64__) | ||
9 | # define __NR_bpf 321 | ||
10 | # elif defined(__aarch64__) | ||
11 | # define __NR_bpf 280 | ||
12 | # error __NR_bpf not defined. libbpf does not support your arch. | ||
13 | # endif | ||
14 | #endif | ||
2 | 15 | ||
3 | int main(void) | 16 | int main(void) |
4 | { | 17 | { |
5 | union bpf_attr attr; | 18 | union bpf_attr attr; |
6 | 19 | ||
20 | /* Check fields in attr */ | ||
7 | attr.prog_type = BPF_PROG_TYPE_KPROBE; | 21 | attr.prog_type = BPF_PROG_TYPE_KPROBE; |
8 | attr.insn_cnt = 0; | 22 | attr.insn_cnt = 0; |
9 | attr.insns = 0; | 23 | attr.insns = 0; |
@@ -14,5 +28,9 @@ int main(void) | |||
14 | attr.kern_version = 0; | 28 | attr.kern_version = 0; |
15 | 29 | ||
16 | attr = attr; | 30 | attr = attr; |
17 | return 0; | 31 | /* |
32 | * Test existence of __NR_bpf and BPF_PROG_LOAD. | ||
33 | * This call should fail if we run the testcase. | ||
34 | */ | ||
35 | return syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr)); | ||
18 | } | 36 | } |
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c index 5480e4e424eb..fdc9ca4c0356 100644 --- a/tools/hv/hv_fcopy_daemon.c +++ b/tools/hv/hv_fcopy_daemon.c | |||
@@ -37,12 +37,14 @@ | |||
37 | 37 | ||
38 | static int target_fd; | 38 | static int target_fd; |
39 | static char target_fname[W_MAX_PATH]; | 39 | static char target_fname[W_MAX_PATH]; |
40 | static unsigned long long filesize; | ||
40 | 41 | ||
41 | static int hv_start_fcopy(struct hv_start_fcopy *smsg) | 42 | static int hv_start_fcopy(struct hv_start_fcopy *smsg) |
42 | { | 43 | { |
43 | int error = HV_E_FAIL; | 44 | int error = HV_E_FAIL; |
44 | char *q, *p; | 45 | char *q, *p; |
45 | 46 | ||
47 | filesize = 0; | ||
46 | p = (char *)smsg->path_name; | 48 | p = (char *)smsg->path_name; |
47 | snprintf(target_fname, sizeof(target_fname), "%s/%s", | 49 | snprintf(target_fname, sizeof(target_fname), "%s/%s", |
48 | (char *)smsg->path_name, (char *)smsg->file_name); | 50 | (char *)smsg->path_name, (char *)smsg->file_name); |
@@ -98,14 +100,26 @@ done: | |||
98 | static int hv_copy_data(struct hv_do_fcopy *cpmsg) | 100 | static int hv_copy_data(struct hv_do_fcopy *cpmsg) |
99 | { | 101 | { |
100 | ssize_t bytes_written; | 102 | ssize_t bytes_written; |
103 | int ret = 0; | ||
101 | 104 | ||
102 | bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, | 105 | bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, |
103 | cpmsg->offset); | 106 | cpmsg->offset); |
104 | 107 | ||
105 | if (bytes_written != cpmsg->size) | 108 | filesize += cpmsg->size; |
106 | return HV_E_FAIL; | 109 | if (bytes_written != cpmsg->size) { |
110 | switch (errno) { | ||
111 | case ENOSPC: | ||
112 | ret = HV_ERROR_DISK_FULL; | ||
113 | break; | ||
114 | default: | ||
115 | ret = HV_E_FAIL; | ||
116 | break; | ||
117 | } | ||
118 | syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)", | ||
119 | filesize, (long)bytes_written, strerror(errno)); | ||
120 | } | ||
107 | 121 | ||
108 | return 0; | 122 | return ret; |
109 | } | 123 | } |
110 | 124 | ||
111 | static int hv_copy_finished(void) | 125 | static int hv_copy_finished(void) |
@@ -165,7 +179,7 @@ int main(int argc, char *argv[]) | |||
165 | } | 179 | } |
166 | 180 | ||
167 | openlog("HV_FCOPY", 0, LOG_USER); | 181 | openlog("HV_FCOPY", 0, LOG_USER); |
168 | syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid()); | 182 | syslog(LOG_INFO, "starting; pid is:%d", getpid()); |
169 | 183 | ||
170 | fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); | 184 | fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); |
171 | 185 | ||
@@ -201,7 +215,7 @@ int main(int argc, char *argv[]) | |||
201 | } | 215 | } |
202 | kernel_modver = *(__u32 *)buffer; | 216 | kernel_modver = *(__u32 *)buffer; |
203 | in_handshake = 0; | 217 | in_handshake = 0; |
204 | syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d", | 218 | syslog(LOG_INFO, "kernel module version: %d", |
205 | kernel_modver); | 219 | kernel_modver); |
206 | continue; | 220 | continue; |
207 | } | 221 | } |
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 96234b638249..5d51d6ff08e6 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c | |||
@@ -254,7 +254,7 @@ int main(int argc, char *argv[]) | |||
254 | syslog(LOG_ERR, "Illegal op:%d\n", op); | 254 | syslog(LOG_ERR, "Illegal op:%d\n", op); |
255 | } | 255 | } |
256 | vss_msg->error = error; | 256 | vss_msg->error = error; |
257 | len = write(vss_fd, &error, sizeof(struct hv_vss_msg)); | 257 | len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg)); |
258 | if (len != sizeof(struct hv_vss_msg)) { | 258 | if (len != sizeof(struct hv_vss_msg)) { |
259 | syslog(LOG_ERR, "write failed; error: %d %s", errno, | 259 | syslog(LOG_ERR, "write failed; error: %d %s", errno, |
260 | strerror(errno)); | 260 | strerror(errno)); |
diff --git a/tools/include/linux/list.h b/tools/include/linux/list.h index a017f1595676..1da423820ad4 100644 --- a/tools/include/linux/list.h +++ b/tools/include/linux/list.h | |||
@@ -1,11 +1,751 @@ | |||
1 | #include <linux/compiler.h> | 1 | #ifndef __TOOLS_LINUX_LIST_H |
2 | #include <linux/kernel.h> | 2 | #define __TOOLS_LINUX_LIST_H |
3 | |||
3 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/poison.h> | ||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/compiler.h> | ||
8 | |||
9 | /* | ||
10 | * Simple doubly linked list implementation. | ||
11 | * | ||
12 | * Some of the internal functions ("__xxx") are useful when | ||
13 | * manipulating whole lists rather than single entries, as | ||
14 | * sometimes we already know the next/prev entries and we can | ||
15 | * generate better code by using them directly rather than | ||
16 | * using the generic single-entry routines. | ||
17 | */ | ||
18 | |||
19 | #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||
20 | |||
21 | #define LIST_HEAD(name) \ | ||
22 | struct list_head name = LIST_HEAD_INIT(name) | ||
23 | |||
24 | static inline void INIT_LIST_HEAD(struct list_head *list) | ||
25 | { | ||
26 | list->next = list; | ||
27 | list->prev = list; | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * Insert a new entry between two known consecutive entries. | ||
32 | * | ||
33 | * This is only for internal list manipulation where we know | ||
34 | * the prev/next entries already! | ||
35 | */ | ||
36 | #ifndef CONFIG_DEBUG_LIST | ||
37 | static inline void __list_add(struct list_head *new, | ||
38 | struct list_head *prev, | ||
39 | struct list_head *next) | ||
40 | { | ||
41 | next->prev = new; | ||
42 | new->next = next; | ||
43 | new->prev = prev; | ||
44 | prev->next = new; | ||
45 | } | ||
46 | #else | ||
47 | extern void __list_add(struct list_head *new, | ||
48 | struct list_head *prev, | ||
49 | struct list_head *next); | ||
50 | #endif | ||
51 | |||
52 | /** | ||
53 | * list_add - add a new entry | ||
54 | * @new: new entry to be added | ||
55 | * @head: list head to add it after | ||
56 | * | ||
57 | * Insert a new entry after the specified head. | ||
58 | * This is good for implementing stacks. | ||
59 | */ | ||
60 | static inline void list_add(struct list_head *new, struct list_head *head) | ||
61 | { | ||
62 | __list_add(new, head, head->next); | ||
63 | } | ||
64 | |||
65 | |||
66 | /** | ||
67 | * list_add_tail - add a new entry | ||
68 | * @new: new entry to be added | ||
69 | * @head: list head to add it before | ||
70 | * | ||
71 | * Insert a new entry before the specified head. | ||
72 | * This is useful for implementing queues. | ||
73 | */ | ||
74 | static inline void list_add_tail(struct list_head *new, struct list_head *head) | ||
75 | { | ||
76 | __list_add(new, head->prev, head); | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Delete a list entry by making the prev/next entries | ||
81 | * point to each other. | ||
82 | * | ||
83 | * This is only for internal list manipulation where we know | ||
84 | * the prev/next entries already! | ||
85 | */ | ||
86 | static inline void __list_del(struct list_head * prev, struct list_head * next) | ||
87 | { | ||
88 | next->prev = prev; | ||
89 | WRITE_ONCE(prev->next, next); | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * list_del - deletes entry from list. | ||
94 | * @entry: the element to delete from the list. | ||
95 | * Note: list_empty() on entry does not return true after this, the entry is | ||
96 | * in an undefined state. | ||
97 | */ | ||
98 | #ifndef CONFIG_DEBUG_LIST | ||
99 | static inline void __list_del_entry(struct list_head *entry) | ||
100 | { | ||
101 | __list_del(entry->prev, entry->next); | ||
102 | } | ||
103 | |||
104 | static inline void list_del(struct list_head *entry) | ||
105 | { | ||
106 | __list_del(entry->prev, entry->next); | ||
107 | entry->next = LIST_POISON1; | ||
108 | entry->prev = LIST_POISON2; | ||
109 | } | ||
110 | #else | ||
111 | extern void __list_del_entry(struct list_head *entry); | ||
112 | extern void list_del(struct list_head *entry); | ||
113 | #endif | ||
114 | |||
115 | /** | ||
116 | * list_replace - replace old entry by new one | ||
117 | * @old : the element to be replaced | ||
118 | * @new : the new element to insert | ||
119 | * | ||
120 | * If @old was empty, it will be overwritten. | ||
121 | */ | ||
122 | static inline void list_replace(struct list_head *old, | ||
123 | struct list_head *new) | ||
124 | { | ||
125 | new->next = old->next; | ||
126 | new->next->prev = new; | ||
127 | new->prev = old->prev; | ||
128 | new->prev->next = new; | ||
129 | } | ||
130 | |||
131 | static inline void list_replace_init(struct list_head *old, | ||
132 | struct list_head *new) | ||
133 | { | ||
134 | list_replace(old, new); | ||
135 | INIT_LIST_HEAD(old); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * list_del_init - deletes entry from list and reinitialize it. | ||
140 | * @entry: the element to delete from the list. | ||
141 | */ | ||
142 | static inline void list_del_init(struct list_head *entry) | ||
143 | { | ||
144 | __list_del_entry(entry); | ||
145 | INIT_LIST_HEAD(entry); | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * list_move - delete from one list and add as another's head | ||
150 | * @list: the entry to move | ||
151 | * @head: the head that will precede our entry | ||
152 | */ | ||
153 | static inline void list_move(struct list_head *list, struct list_head *head) | ||
154 | { | ||
155 | __list_del_entry(list); | ||
156 | list_add(list, head); | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * list_move_tail - delete from one list and add as another's tail | ||
161 | * @list: the entry to move | ||
162 | * @head: the head that will follow our entry | ||
163 | */ | ||
164 | static inline void list_move_tail(struct list_head *list, | ||
165 | struct list_head *head) | ||
166 | { | ||
167 | __list_del_entry(list); | ||
168 | list_add_tail(list, head); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * list_is_last - tests whether @list is the last entry in list @head | ||
173 | * @list: the entry to test | ||
174 | * @head: the head of the list | ||
175 | */ | ||
176 | static inline int list_is_last(const struct list_head *list, | ||
177 | const struct list_head *head) | ||
178 | { | ||
179 | return list->next == head; | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * list_empty - tests whether a list is empty | ||
184 | * @head: the list to test. | ||
185 | */ | ||
186 | static inline int list_empty(const struct list_head *head) | ||
187 | { | ||
188 | return head->next == head; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * list_empty_careful - tests whether a list is empty and not being modified | ||
193 | * @head: the list to test | ||
194 | * | ||
195 | * Description: | ||
196 | * tests whether a list is empty _and_ checks that no other CPU might be | ||
197 | * in the process of modifying either member (next or prev) | ||
198 | * | ||
199 | * NOTE: using list_empty_careful() without synchronization | ||
200 | * can only be safe if the only activity that can happen | ||
201 | * to the list entry is list_del_init(). Eg. it cannot be used | ||
202 | * if another CPU could re-list_add() it. | ||
203 | */ | ||
204 | static inline int list_empty_careful(const struct list_head *head) | ||
205 | { | ||
206 | struct list_head *next = head->next; | ||
207 | return (next == head) && (next == head->prev); | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * list_rotate_left - rotate the list to the left | ||
212 | * @head: the head of the list | ||
213 | */ | ||
214 | static inline void list_rotate_left(struct list_head *head) | ||
215 | { | ||
216 | struct list_head *first; | ||
217 | |||
218 | if (!list_empty(head)) { | ||
219 | first = head->next; | ||
220 | list_move_tail(first, head); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * list_is_singular - tests whether a list has just one entry. | ||
226 | * @head: the list to test. | ||
227 | */ | ||
228 | static inline int list_is_singular(const struct list_head *head) | ||
229 | { | ||
230 | return !list_empty(head) && (head->next == head->prev); | ||
231 | } | ||
232 | |||
233 | static inline void __list_cut_position(struct list_head *list, | ||
234 | struct list_head *head, struct list_head *entry) | ||
235 | { | ||
236 | struct list_head *new_first = entry->next; | ||
237 | list->next = head->next; | ||
238 | list->next->prev = list; | ||
239 | list->prev = entry; | ||
240 | entry->next = list; | ||
241 | head->next = new_first; | ||
242 | new_first->prev = head; | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * list_cut_position - cut a list into two | ||
247 | * @list: a new list to add all removed entries | ||
248 | * @head: a list with entries | ||
249 | * @entry: an entry within head, could be the head itself | ||
250 | * and if so we won't cut the list | ||
251 | * | ||
252 | * This helper moves the initial part of @head, up to and | ||
253 | * including @entry, from @head to @list. You should | ||
254 | * pass on @entry an element you know is on @head. @list | ||
255 | * should be an empty list or a list you do not care about | ||
256 | * losing its data. | ||
257 | * | ||
258 | */ | ||
259 | static inline void list_cut_position(struct list_head *list, | ||
260 | struct list_head *head, struct list_head *entry) | ||
261 | { | ||
262 | if (list_empty(head)) | ||
263 | return; | ||
264 | if (list_is_singular(head) && | ||
265 | (head->next != entry && head != entry)) | ||
266 | return; | ||
267 | if (entry == head) | ||
268 | INIT_LIST_HEAD(list); | ||
269 | else | ||
270 | __list_cut_position(list, head, entry); | ||
271 | } | ||
272 | |||
273 | static inline void __list_splice(const struct list_head *list, | ||
274 | struct list_head *prev, | ||
275 | struct list_head *next) | ||
276 | { | ||
277 | struct list_head *first = list->next; | ||
278 | struct list_head *last = list->prev; | ||
279 | |||
280 | first->prev = prev; | ||
281 | prev->next = first; | ||
282 | |||
283 | last->next = next; | ||
284 | next->prev = last; | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * list_splice - join two lists, this is designed for stacks | ||
289 | * @list: the new list to add. | ||
290 | * @head: the place to add it in the first list. | ||
291 | */ | ||
292 | static inline void list_splice(const struct list_head *list, | ||
293 | struct list_head *head) | ||
294 | { | ||
295 | if (!list_empty(list)) | ||
296 | __list_splice(list, head, head->next); | ||
297 | } | ||
298 | |||
299 | /** | ||
300 | * list_splice_tail - join two lists, each list being a queue | ||
301 | * @list: the new list to add. | ||
302 | * @head: the place to add it in the first list. | ||
303 | */ | ||
304 | static inline void list_splice_tail(struct list_head *list, | ||
305 | struct list_head *head) | ||
306 | { | ||
307 | if (!list_empty(list)) | ||
308 | __list_splice(list, head->prev, head); | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * list_splice_init - join two lists and reinitialise the emptied list. | ||
313 | * @list: the new list to add. | ||
314 | * @head: the place to add it in the first list. | ||
315 | * | ||
316 | * The list at @list is reinitialised | ||
317 | */ | ||
318 | static inline void list_splice_init(struct list_head *list, | ||
319 | struct list_head *head) | ||
320 | { | ||
321 | if (!list_empty(list)) { | ||
322 | __list_splice(list, head, head->next); | ||
323 | INIT_LIST_HEAD(list); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | /** | ||
328 | * list_splice_tail_init - join two lists and reinitialise the emptied list | ||
329 | * @list: the new list to add. | ||
330 | * @head: the place to add it in the first list. | ||
331 | * | ||
332 | * Each of the lists is a queue. | ||
333 | * The list at @list is reinitialised | ||
334 | */ | ||
335 | static inline void list_splice_tail_init(struct list_head *list, | ||
336 | struct list_head *head) | ||
337 | { | ||
338 | if (!list_empty(list)) { | ||
339 | __list_splice(list, head->prev, head); | ||
340 | INIT_LIST_HEAD(list); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * list_entry - get the struct for this entry | ||
346 | * @ptr: the &struct list_head pointer. | ||
347 | * @type: the type of the struct this is embedded in. | ||
348 | * @member: the name of the list_head within the struct. | ||
349 | */ | ||
350 | #define list_entry(ptr, type, member) \ | ||
351 | container_of(ptr, type, member) | ||
352 | |||
353 | /** | ||
354 | * list_first_entry - get the first element from a list | ||
355 | * @ptr: the list head to take the element from. | ||
356 | * @type: the type of the struct this is embedded in. | ||
357 | * @member: the name of the list_head within the struct. | ||
358 | * | ||
359 | * Note, that list is expected to be not empty. | ||
360 | */ | ||
361 | #define list_first_entry(ptr, type, member) \ | ||
362 | list_entry((ptr)->next, type, member) | ||
363 | |||
364 | /** | ||
365 | * list_last_entry - get the last element from a list | ||
366 | * @ptr: the list head to take the element from. | ||
367 | * @type: the type of the struct this is embedded in. | ||
368 | * @member: the name of the list_head within the struct. | ||
369 | * | ||
370 | * Note, that list is expected to be not empty. | ||
371 | */ | ||
372 | #define list_last_entry(ptr, type, member) \ | ||
373 | list_entry((ptr)->prev, type, member) | ||
374 | |||
375 | /** | ||
376 | * list_first_entry_or_null - get the first element from a list | ||
377 | * @ptr: the list head to take the element from. | ||
378 | * @type: the type of the struct this is embedded in. | ||
379 | * @member: the name of the list_head within the struct. | ||
380 | * | ||
381 | * Note that if the list is empty, it returns NULL. | ||
382 | */ | ||
383 | #define list_first_entry_or_null(ptr, type, member) \ | ||
384 | (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) | ||
385 | |||
386 | /** | ||
387 | * list_next_entry - get the next element in list | ||
388 | * @pos: the type * to cursor | ||
389 | * @member: the name of the list_head within the struct. | ||
390 | */ | ||
391 | #define list_next_entry(pos, member) \ | ||
392 | list_entry((pos)->member.next, typeof(*(pos)), member) | ||
393 | |||
394 | /** | ||
395 | * list_prev_entry - get the prev element in list | ||
396 | * @pos: the type * to cursor | ||
397 | * @member: the name of the list_head within the struct. | ||
398 | */ | ||
399 | #define list_prev_entry(pos, member) \ | ||
400 | list_entry((pos)->member.prev, typeof(*(pos)), member) | ||
401 | |||
402 | /** | ||
403 | * list_for_each - iterate over a list | ||
404 | * @pos: the &struct list_head to use as a loop cursor. | ||
405 | * @head: the head for your list. | ||
406 | */ | ||
407 | #define list_for_each(pos, head) \ | ||
408 | for (pos = (head)->next; pos != (head); pos = pos->next) | ||
409 | |||
410 | /** | ||
411 | * list_for_each_prev - iterate over a list backwards | ||
412 | * @pos: the &struct list_head to use as a loop cursor. | ||
413 | * @head: the head for your list. | ||
414 | */ | ||
415 | #define list_for_each_prev(pos, head) \ | ||
416 | for (pos = (head)->prev; pos != (head); pos = pos->prev) | ||
417 | |||
418 | /** | ||
419 | * list_for_each_safe - iterate over a list safe against removal of list entry | ||
420 | * @pos: the &struct list_head to use as a loop cursor. | ||
421 | * @n: another &struct list_head to use as temporary storage | ||
422 | * @head: the head for your list. | ||
423 | */ | ||
424 | #define list_for_each_safe(pos, n, head) \ | ||
425 | for (pos = (head)->next, n = pos->next; pos != (head); \ | ||
426 | pos = n, n = pos->next) | ||
427 | |||
428 | /** | ||
429 | * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry | ||
430 | * @pos: the &struct list_head to use as a loop cursor. | ||
431 | * @n: another &struct list_head to use as temporary storage | ||
432 | * @head: the head for your list. | ||
433 | */ | ||
434 | #define list_for_each_prev_safe(pos, n, head) \ | ||
435 | for (pos = (head)->prev, n = pos->prev; \ | ||
436 | pos != (head); \ | ||
437 | pos = n, n = pos->prev) | ||
438 | |||
439 | /** | ||
440 | * list_for_each_entry - iterate over list of given type | ||
441 | * @pos: the type * to use as a loop cursor. | ||
442 | * @head: the head for your list. | ||
443 | * @member: the name of the list_head within the struct. | ||
444 | */ | ||
445 | #define list_for_each_entry(pos, head, member) \ | ||
446 | for (pos = list_first_entry(head, typeof(*pos), member); \ | ||
447 | &pos->member != (head); \ | ||
448 | pos = list_next_entry(pos, member)) | ||
449 | |||
450 | /** | ||
451 | * list_for_each_entry_reverse - iterate backwards over list of given type. | ||
452 | * @pos: the type * to use as a loop cursor. | ||
453 | * @head: the head for your list. | ||
454 | * @member: the name of the list_head within the struct. | ||
455 | */ | ||
456 | #define list_for_each_entry_reverse(pos, head, member) \ | ||
457 | for (pos = list_last_entry(head, typeof(*pos), member); \ | ||
458 | &pos->member != (head); \ | ||
459 | pos = list_prev_entry(pos, member)) | ||
460 | |||
461 | /** | ||
462 | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() | ||
463 | * @pos: the type * to use as a start point | ||
464 | * @head: the head of the list | ||
465 | * @member: the name of the list_head within the struct. | ||
466 | * | ||
467 | * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). | ||
468 | */ | ||
469 | #define list_prepare_entry(pos, head, member) \ | ||
470 | ((pos) ? : list_entry(head, typeof(*pos), member)) | ||
471 | |||
472 | /** | ||
473 | * list_for_each_entry_continue - continue iteration over list of given type | ||
474 | * @pos: the type * to use as a loop cursor. | ||
475 | * @head: the head for your list. | ||
476 | * @member: the name of the list_head within the struct. | ||
477 | * | ||
478 | * Continue to iterate over list of given type, continuing after | ||
479 | * the current position. | ||
480 | */ | ||
481 | #define list_for_each_entry_continue(pos, head, member) \ | ||
482 | for (pos = list_next_entry(pos, member); \ | ||
483 | &pos->member != (head); \ | ||
484 | pos = list_next_entry(pos, member)) | ||
485 | |||
486 | /** | ||
487 | * list_for_each_entry_continue_reverse - iterate backwards from the given point | ||
488 | * @pos: the type * to use as a loop cursor. | ||
489 | * @head: the head for your list. | ||
490 | * @member: the name of the list_head within the struct. | ||
491 | * | ||
492 | * Start to iterate over list of given type backwards, continuing after | ||
493 | * the current position. | ||
494 | */ | ||
495 | #define list_for_each_entry_continue_reverse(pos, head, member) \ | ||
496 | for (pos = list_prev_entry(pos, member); \ | ||
497 | &pos->member != (head); \ | ||
498 | pos = list_prev_entry(pos, member)) | ||
499 | |||
500 | /** | ||
501 | * list_for_each_entry_from - iterate over list of given type from the current point | ||
502 | * @pos: the type * to use as a loop cursor. | ||
503 | * @head: the head for your list. | ||
504 | * @member: the name of the list_head within the struct. | ||
505 | * | ||
506 | * Iterate over list of given type, continuing from current position. | ||
507 | */ | ||
508 | #define list_for_each_entry_from(pos, head, member) \ | ||
509 | for (; &pos->member != (head); \ | ||
510 | pos = list_next_entry(pos, member)) | ||
511 | |||
512 | /** | ||
513 | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry | ||
514 | * @pos: the type * to use as a loop cursor. | ||
515 | * @n: another type * to use as temporary storage | ||
516 | * @head: the head for your list. | ||
517 | * @member: the name of the list_head within the struct. | ||
518 | */ | ||
519 | #define list_for_each_entry_safe(pos, n, head, member) \ | ||
520 | for (pos = list_first_entry(head, typeof(*pos), member), \ | ||
521 | n = list_next_entry(pos, member); \ | ||
522 | &pos->member != (head); \ | ||
523 | pos = n, n = list_next_entry(n, member)) | ||
524 | |||
525 | /** | ||
526 | * list_for_each_entry_safe_continue - continue list iteration safe against removal | ||
527 | * @pos: the type * to use as a loop cursor. | ||
528 | * @n: another type * to use as temporary storage | ||
529 | * @head: the head for your list. | ||
530 | * @member: the name of the list_head within the struct. | ||
531 | * | ||
532 | * Iterate over list of given type, continuing after current point, | ||
533 | * safe against removal of list entry. | ||
534 | */ | ||
535 | #define list_for_each_entry_safe_continue(pos, n, head, member) \ | ||
536 | for (pos = list_next_entry(pos, member), \ | ||
537 | n = list_next_entry(pos, member); \ | ||
538 | &pos->member != (head); \ | ||
539 | pos = n, n = list_next_entry(n, member)) | ||
540 | |||
541 | /** | ||
542 | * list_for_each_entry_safe_from - iterate over list from current point safe against removal | ||
543 | * @pos: the type * to use as a loop cursor. | ||
544 | * @n: another type * to use as temporary storage | ||
545 | * @head: the head for your list. | ||
546 | * @member: the name of the list_head within the struct. | ||
547 | * | ||
548 | * Iterate over list of given type from current point, safe against | ||
549 | * removal of list entry. | ||
550 | */ | ||
551 | #define list_for_each_entry_safe_from(pos, n, head, member) \ | ||
552 | for (n = list_next_entry(pos, member); \ | ||
553 | &pos->member != (head); \ | ||
554 | pos = n, n = list_next_entry(n, member)) | ||
555 | |||
556 | /** | ||
557 | * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal | ||
558 | * @pos: the type * to use as a loop cursor. | ||
559 | * @n: another type * to use as temporary storage | ||
560 | * @head: the head for your list. | ||
561 | * @member: the name of the list_head within the struct. | ||
562 | * | ||
563 | * Iterate backwards over list of given type, safe against removal | ||
564 | * of list entry. | ||
565 | */ | ||
566 | #define list_for_each_entry_safe_reverse(pos, n, head, member) \ | ||
567 | for (pos = list_last_entry(head, typeof(*pos), member), \ | ||
568 | n = list_prev_entry(pos, member); \ | ||
569 | &pos->member != (head); \ | ||
570 | pos = n, n = list_prev_entry(n, member)) | ||
4 | 571 | ||
5 | #include "../../../include/linux/list.h" | 572 | /** |
573 | * list_safe_reset_next - reset a stale list_for_each_entry_safe loop | ||
574 | * @pos: the loop cursor used in the list_for_each_entry_safe loop | ||
575 | * @n: temporary storage used in list_for_each_entry_safe | ||
576 | * @member: the name of the list_head within the struct. | ||
577 | * | ||
578 | * list_safe_reset_next is not safe to use in general if the list may be | ||
579 | * modified concurrently (eg. the lock is dropped in the loop body). An | ||
580 | * exception to this is if the cursor element (pos) is pinned in the list, | ||
581 | * and list_safe_reset_next is called after re-taking the lock and before | ||
582 | * completing the current iteration of the loop body. | ||
583 | */ | ||
584 | #define list_safe_reset_next(pos, n, member) \ | ||
585 | n = list_next_entry(pos, member) | ||
586 | |||
587 | /* | ||
588 | * Double linked lists with a single pointer list head. | ||
589 | * Mostly useful for hash tables where the two pointer list head is | ||
590 | * too wasteful. | ||
591 | * You lose the ability to access the tail in O(1). | ||
592 | */ | ||
593 | |||
594 | #define HLIST_HEAD_INIT { .first = NULL } | ||
595 | #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } | ||
596 | #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) | ||
597 | static inline void INIT_HLIST_NODE(struct hlist_node *h) | ||
598 | { | ||
599 | h->next = NULL; | ||
600 | h->pprev = NULL; | ||
601 | } | ||
602 | |||
603 | static inline int hlist_unhashed(const struct hlist_node *h) | ||
604 | { | ||
605 | return !h->pprev; | ||
606 | } | ||
607 | |||
608 | static inline int hlist_empty(const struct hlist_head *h) | ||
609 | { | ||
610 | return !h->first; | ||
611 | } | ||
612 | |||
613 | static inline void __hlist_del(struct hlist_node *n) | ||
614 | { | ||
615 | struct hlist_node *next = n->next; | ||
616 | struct hlist_node **pprev = n->pprev; | ||
617 | |||
618 | WRITE_ONCE(*pprev, next); | ||
619 | if (next) | ||
620 | next->pprev = pprev; | ||
621 | } | ||
622 | |||
623 | static inline void hlist_del(struct hlist_node *n) | ||
624 | { | ||
625 | __hlist_del(n); | ||
626 | n->next = LIST_POISON1; | ||
627 | n->pprev = LIST_POISON2; | ||
628 | } | ||
629 | |||
630 | static inline void hlist_del_init(struct hlist_node *n) | ||
631 | { | ||
632 | if (!hlist_unhashed(n)) { | ||
633 | __hlist_del(n); | ||
634 | INIT_HLIST_NODE(n); | ||
635 | } | ||
636 | } | ||
637 | |||
638 | static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) | ||
639 | { | ||
640 | struct hlist_node *first = h->first; | ||
641 | n->next = first; | ||
642 | if (first) | ||
643 | first->pprev = &n->next; | ||
644 | h->first = n; | ||
645 | n->pprev = &h->first; | ||
646 | } | ||
647 | |||
648 | /* next must be != NULL */ | ||
649 | static inline void hlist_add_before(struct hlist_node *n, | ||
650 | struct hlist_node *next) | ||
651 | { | ||
652 | n->pprev = next->pprev; | ||
653 | n->next = next; | ||
654 | next->pprev = &n->next; | ||
655 | *(n->pprev) = n; | ||
656 | } | ||
657 | |||
658 | static inline void hlist_add_behind(struct hlist_node *n, | ||
659 | struct hlist_node *prev) | ||
660 | { | ||
661 | n->next = prev->next; | ||
662 | prev->next = n; | ||
663 | n->pprev = &prev->next; | ||
664 | |||
665 | if (n->next) | ||
666 | n->next->pprev = &n->next; | ||
667 | } | ||
668 | |||
669 | /* after that we'll appear to be on some hlist and hlist_del will work */ | ||
670 | static inline void hlist_add_fake(struct hlist_node *n) | ||
671 | { | ||
672 | n->pprev = &n->next; | ||
673 | } | ||
674 | |||
675 | static inline bool hlist_fake(struct hlist_node *h) | ||
676 | { | ||
677 | return h->pprev == &h->next; | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * Move a list from one list head to another. Fixup the pprev | ||
682 | * reference of the first entry if it exists. | ||
683 | */ | ||
684 | static inline void hlist_move_list(struct hlist_head *old, | ||
685 | struct hlist_head *new) | ||
686 | { | ||
687 | new->first = old->first; | ||
688 | if (new->first) | ||
689 | new->first->pprev = &new->first; | ||
690 | old->first = NULL; | ||
691 | } | ||
692 | |||
693 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member) | ||
694 | |||
695 | #define hlist_for_each(pos, head) \ | ||
696 | for (pos = (head)->first; pos ; pos = pos->next) | ||
697 | |||
698 | #define hlist_for_each_safe(pos, n, head) \ | ||
699 | for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ | ||
700 | pos = n) | ||
701 | |||
702 | #define hlist_entry_safe(ptr, type, member) \ | ||
703 | ({ typeof(ptr) ____ptr = (ptr); \ | ||
704 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ | ||
705 | }) | ||
706 | |||
707 | /** | ||
708 | * hlist_for_each_entry - iterate over list of given type | ||
709 | * @pos: the type * to use as a loop cursor. | ||
710 | * @head: the head for your list. | ||
711 | * @member: the name of the hlist_node within the struct. | ||
712 | */ | ||
713 | #define hlist_for_each_entry(pos, head, member) \ | ||
714 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ | ||
715 | pos; \ | ||
716 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) | ||
717 | |||
718 | /** | ||
719 | * hlist_for_each_entry_continue - iterate over a hlist continuing after current point | ||
720 | * @pos: the type * to use as a loop cursor. | ||
721 | * @member: the name of the hlist_node within the struct. | ||
722 | */ | ||
723 | #define hlist_for_each_entry_continue(pos, member) \ | ||
724 | for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\ | ||
725 | pos; \ | ||
726 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) | ||
727 | |||
728 | /** | ||
729 | * hlist_for_each_entry_from - iterate over a hlist continuing from current point | ||
730 | * @pos: the type * to use as a loop cursor. | ||
731 | * @member: the name of the hlist_node within the struct. | ||
732 | */ | ||
733 | #define hlist_for_each_entry_from(pos, member) \ | ||
734 | for (; pos; \ | ||
735 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) | ||
736 | |||
737 | /** | ||
738 | * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry | ||
739 | * @pos: the type * to use as a loop cursor. | ||
740 | * @n: another &struct hlist_node to use as temporary storage | ||
741 | * @head: the head for your list. | ||
742 | * @member: the name of the hlist_node within the struct. | ||
743 | */ | ||
744 | #define hlist_for_each_entry_safe(pos, n, head, member) \ | ||
745 | for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\ | ||
746 | pos && ({ n = pos->member.next; 1; }); \ | ||
747 | pos = hlist_entry_safe(n, typeof(*pos), member)) | ||
6 | 748 | ||
7 | #ifndef TOOLS_LIST_H | ||
8 | #define TOOLS_LIST_H | ||
9 | /** | 749 | /** |
10 | * list_del_range - deletes range of entries from list. | 750 | * list_del_range - deletes range of entries from list. |
11 | * @begin: first element in the range to delete from the list. | 751 | * @begin: first element in the range to delete from the list. |
@@ -27,4 +767,5 @@ static inline void list_del_range(struct list_head *begin, | |||
27 | */ | 767 | */ |
28 | #define list_for_each_from(pos, head) \ | 768 | #define list_for_each_from(pos, head) \ |
29 | for (; pos != (head); pos = pos->next) | 769 | for (; pos != (head); pos = pos->next) |
30 | #endif | 770 | |
771 | #endif /* __TOOLS_LINUX_LIST_H */ | ||
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 919b71780710..fc1bc75ae56d 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile | |||
@@ -6,6 +6,12 @@ BPF_EXTRAVERSION = 1 | |||
6 | 6 | ||
7 | MAKEFLAGS += --no-print-directory | 7 | MAKEFLAGS += --no-print-directory |
8 | 8 | ||
9 | ifeq ($(srctree),) | ||
10 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | ||
11 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
12 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
13 | #$(info Determined 'srctree' to be $(srctree)) | ||
14 | endif | ||
9 | 15 | ||
10 | # Makefiles suck: This macro sets a default value of $(2) for the | 16 | # Makefiles suck: This macro sets a default value of $(2) for the |
11 | # variable named by $(1), unless the variable has been set by | 17 | # variable named by $(1), unless the variable has been set by |
@@ -31,7 +37,8 @@ INSTALL = install | |||
31 | DESTDIR ?= | 37 | DESTDIR ?= |
32 | DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' | 38 | DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' |
33 | 39 | ||
34 | LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) | 40 | include $(srctree)/tools/scripts/Makefile.arch |
41 | |||
35 | ifeq ($(LP64), 1) | 42 | ifeq ($(LP64), 1) |
36 | libdir_relative = lib64 | 43 | libdir_relative = lib64 |
37 | else | 44 | else |
@@ -57,13 +64,6 @@ ifndef VERBOSE | |||
57 | VERBOSE = 0 | 64 | VERBOSE = 0 |
58 | endif | 65 | endif |
59 | 66 | ||
60 | ifeq ($(srctree),) | ||
61 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | ||
62 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
63 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
64 | #$(info Determined 'srctree' to be $(srctree)) | ||
65 | endif | ||
66 | |||
67 | FEATURE_USER = .libbpf | 67 | FEATURE_USER = .libbpf |
68 | FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf | 68 | FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf |
69 | FEATURE_DISPLAY = libelf bpf | 69 | FEATURE_DISPLAY = libelf bpf |
@@ -192,7 +192,7 @@ config-clean: | |||
192 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null | 192 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null |
193 | 193 | ||
194 | clean: | 194 | clean: |
195 | $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ | 195 | $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d .*.cmd \ |
196 | $(RM) LIBBPF-CFLAGS | 196 | $(RM) LIBBPF-CFLAGS |
197 | $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf | 197 | $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf |
198 | 198 | ||
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 5bdc6eab6852..1f91cc941b7c 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c | |||
@@ -14,8 +14,8 @@ | |||
14 | #include "bpf.h" | 14 | #include "bpf.h" |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * When building perf, unistd.h is override. Define __NR_bpf is | 17 | * When building perf, unistd.h is overrided. __NR_bpf is |
18 | * required to be defined. | 18 | * required to be defined explicitly. |
19 | */ | 19 | */ |
20 | #ifndef __NR_bpf | 20 | #ifndef __NR_bpf |
21 | # if defined(__i386__) | 21 | # if defined(__i386__) |
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index 7e319afac78a..90d2baeb621a 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile | |||
@@ -149,7 +149,7 @@ install_lib: all_cmd | |||
149 | install: install_lib | 149 | install: install_lib |
150 | 150 | ||
151 | clean: | 151 | clean: |
152 | $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d | 152 | $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d .*.cmd |
153 | $(RM) tags TAGS | 153 | $(RM) tags TAGS |
154 | 154 | ||
155 | PHONY += force | 155 | PHONY += force |
diff --git a/tools/lib/subcmd/parse-options.h b/tools/lib/subcmd/parse-options.h index 13a2cc1d6140..d60cab2726da 100644 --- a/tools/lib/subcmd/parse-options.h +++ b/tools/lib/subcmd/parse-options.h | |||
@@ -4,6 +4,10 @@ | |||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include <stdint.h> | 5 | #include <stdint.h> |
6 | 6 | ||
7 | #ifndef NORETURN | ||
8 | #define NORETURN __attribute__((__noreturn__)) | ||
9 | #endif | ||
10 | |||
7 | enum parse_opt_type { | 11 | enum parse_opt_type { |
8 | /* special types */ | 12 | /* special types */ |
9 | OPTION_END, | 13 | OPTION_END, |
diff --git a/tools/perf/Build b/tools/perf/Build index 6b67e6f4179f..a43fae7f439a 100644 --- a/tools/perf/Build +++ b/tools/perf/Build | |||
@@ -42,6 +42,7 @@ CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \ | |||
42 | -include $(OUTPUT)PERF-VERSION-FILE | 42 | -include $(OUTPUT)PERF-VERSION-FILE |
43 | CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" | 43 | CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" |
44 | CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))" | 44 | CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))" |
45 | CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)" | ||
45 | 46 | ||
46 | libperf-y += util/ | 47 | libperf-y += util/ |
47 | libperf-y += arch/ | 48 | libperf-y += arch/ |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 3a1a32f5479f..fbceb631387c 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -338,6 +338,9 @@ Options passed to clang when compiling BPF scriptlets. | |||
338 | Specify vmlinux path which has debuginfo. | 338 | Specify vmlinux path which has debuginfo. |
339 | (enabled when BPF prologue is on) | 339 | (enabled when BPF prologue is on) |
340 | 340 | ||
341 | --buildid-all:: | ||
342 | Record build-id of all DSOs regardless whether it's actually hit or not. | ||
343 | |||
341 | SEE ALSO | 344 | SEE ALSO |
342 | -------- | 345 | -------- |
343 | linkperf:perf-stat[1], linkperf:perf-list[1] | 346 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt index a1c10e360db5..e0ce9573b79b 100644 --- a/tools/perf/Documentation/tips.txt +++ b/tools/perf/Documentation/tips.txt | |||
@@ -12,3 +12,18 @@ List events using substring match: perf list <keyword> | |||
12 | To see list of saved events and attributes: perf evlist -v | 12 | To see list of saved events and attributes: perf evlist -v |
13 | Use --symfs <dir> if your symbol files are in non-standard locations | 13 | Use --symfs <dir> if your symbol files are in non-standard locations |
14 | To see callchains in a more compact form: perf report -g folded | 14 | To see callchains in a more compact form: perf report -g folded |
15 | Show individual samples with: perf script | ||
16 | Limit to show entries above 5% only: perf report --percent-limit 5 | ||
17 | Profiling branch (mis)predictions with: perf record -b / perf report | ||
18 | Treat branches as callchains: perf report --branch-history | ||
19 | To count events in every 1000 msec: perf stat -I 1000 | ||
20 | Print event counts in CSV format with: perf stat -x, | ||
21 | If you have debuginfo enabled, try: perf report -s sym,srcline | ||
22 | For memory address profiling, try: perf mem record / perf mem report | ||
23 | For tracepoint events, try: perf report -s trace_fields | ||
24 | To record callchains for each sample: perf record -g | ||
25 | To record every process run by an user: perf record -u <user> | ||
26 | Skip collecing build-id when recording: perf record -B | ||
27 | To change sampling frequency to 100 Hz: perf record -F 100 | ||
28 | See assembly instructions with percentage: perf annotate <symbol> | ||
29 | If you prefer Intel style assembly, try: perf annotate -M intel | ||
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index ddf922f93aa1..2e1fa2357528 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -28,6 +28,7 @@ tools/lib/string.c | |||
28 | tools/lib/symbol/kallsyms.c | 28 | tools/lib/symbol/kallsyms.c |
29 | tools/lib/symbol/kallsyms.h | 29 | tools/lib/symbol/kallsyms.h |
30 | tools/lib/find_bit.c | 30 | tools/lib/find_bit.c |
31 | tools/lib/bitmap.c | ||
31 | tools/include/asm/atomic.h | 32 | tools/include/asm/atomic.h |
32 | tools/include/asm/barrier.h | 33 | tools/include/asm/barrier.h |
33 | tools/include/asm/bug.h | 34 | tools/include/asm/bug.h |
@@ -57,6 +58,7 @@ tools/include/linux/rbtree_augmented.h | |||
57 | tools/include/linux/string.h | 58 | tools/include/linux/string.h |
58 | tools/include/linux/types.h | 59 | tools/include/linux/types.h |
59 | tools/include/linux/err.h | 60 | tools/include/linux/err.h |
61 | tools/include/linux/bitmap.h | ||
60 | include/asm-generic/bitops/arch_hweight.h | 62 | include/asm-generic/bitops/arch_hweight.h |
61 | include/asm-generic/bitops/const_hweight.h | 63 | include/asm-generic/bitops/const_hweight.h |
62 | include/asm-generic/bitops/fls64.h | 64 | include/asm-generic/bitops/fls64.h |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index dc4e0adf5c5b..319712a4e02b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -50,6 +50,7 @@ struct record { | |||
50 | int realtime_prio; | 50 | int realtime_prio; |
51 | bool no_buildid; | 51 | bool no_buildid; |
52 | bool no_buildid_cache; | 52 | bool no_buildid_cache; |
53 | bool buildid_all; | ||
53 | unsigned long long samples; | 54 | unsigned long long samples; |
54 | }; | 55 | }; |
55 | 56 | ||
@@ -362,6 +363,13 @@ static int process_buildids(struct record *rec) | |||
362 | */ | 363 | */ |
363 | symbol_conf.ignore_vmlinux_buildid = true; | 364 | symbol_conf.ignore_vmlinux_buildid = true; |
364 | 365 | ||
366 | /* | ||
367 | * If --buildid-all is given, it marks all DSO regardless of hits, | ||
368 | * so no need to process samples. | ||
369 | */ | ||
370 | if (rec->buildid_all) | ||
371 | rec->tool.sample = NULL; | ||
372 | |||
365 | return perf_session__process_events(session); | 373 | return perf_session__process_events(session); |
366 | } | 374 | } |
367 | 375 | ||
@@ -756,12 +764,8 @@ out_child: | |||
756 | 764 | ||
757 | if (!rec->no_buildid) { | 765 | if (!rec->no_buildid) { |
758 | process_buildids(rec); | 766 | process_buildids(rec); |
759 | /* | 767 | |
760 | * We take all buildids when the file contains | 768 | if (rec->buildid_all) |
761 | * AUX area tracing data because we do not decode the | ||
762 | * trace because it would take too long. | ||
763 | */ | ||
764 | if (rec->opts.full_auxtrace) | ||
765 | dsos__hit_all(rec->session); | 769 | dsos__hit_all(rec->session); |
766 | } | 770 | } |
767 | perf_session__write_header(rec->session, rec->evlist, fd, true); | 771 | perf_session__write_header(rec->session, rec->evlist, fd, true); |
@@ -1138,6 +1142,8 @@ struct option __record_options[] = { | |||
1138 | "options passed to clang when compiling BPF scriptlets"), | 1142 | "options passed to clang when compiling BPF scriptlets"), |
1139 | OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name, | 1143 | OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name, |
1140 | "file", "vmlinux pathname"), | 1144 | "file", "vmlinux pathname"), |
1145 | OPT_BOOLEAN(0, "buildid-all", &record.buildid_all, | ||
1146 | "Record build-id of all DSOs regardless of hits"), | ||
1141 | OPT_END() | 1147 | OPT_END() |
1142 | }; | 1148 | }; |
1143 | 1149 | ||
@@ -1255,6 +1261,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1255 | if (err) | 1261 | if (err) |
1256 | goto out_symbol_exit; | 1262 | goto out_symbol_exit; |
1257 | 1263 | ||
1264 | /* | ||
1265 | * We take all buildids when the file contains | ||
1266 | * AUX area tracing data because we do not decode the | ||
1267 | * trace because it would take too long. | ||
1268 | */ | ||
1269 | if (rec->opts.full_auxtrace) | ||
1270 | rec->buildid_all = true; | ||
1271 | |||
1258 | if (record_opts__config(&rec->opts)) { | 1272 | if (record_opts__config(&rec->opts)) { |
1259 | err = -EINVAL; | 1273 | err = -EINVAL; |
1260 | goto out_symbol_exit; | 1274 | goto out_symbol_exit; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index d5a42ee12529..2bf537f190a0 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "util/tool.h" | 28 | #include "util/tool.h" |
29 | 29 | ||
30 | #include <subcmd/parse-options.h> | 30 | #include <subcmd/parse-options.h> |
31 | #include <subcmd/exec-cmd.h> | ||
31 | #include "util/parse-events.h" | 32 | #include "util/parse-events.h" |
32 | 33 | ||
33 | #include "util/thread.h" | 34 | #include "util/thread.h" |
@@ -433,7 +434,14 @@ static int report__browse_hists(struct report *rep) | |||
433 | int ret; | 434 | int ret; |
434 | struct perf_session *session = rep->session; | 435 | struct perf_session *session = rep->session; |
435 | struct perf_evlist *evlist = session->evlist; | 436 | struct perf_evlist *evlist = session->evlist; |
436 | const char *help = perf_tip(TIPDIR); | 437 | const char *help = perf_tip(system_path(TIPDIR)); |
438 | |||
439 | if (help == NULL) { | ||
440 | /* fallback for people who don't install perf ;-) */ | ||
441 | help = perf_tip(DOCDIR); | ||
442 | if (help == NULL) | ||
443 | help = "Cannot load tips.txt file, please install perf!"; | ||
444 | } | ||
437 | 445 | ||
438 | switch (use_browser) { | 446 | switch (use_browser) { |
439 | case 1: | 447 | case 1: |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7f568244662b..038e877081b6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -1588,7 +1588,7 @@ static int add_default_attributes(void) | |||
1588 | return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); | 1588 | return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); |
1589 | } | 1589 | } |
1590 | 1590 | ||
1591 | static const char * const recort_usage[] = { | 1591 | static const char * const stat_record_usage[] = { |
1592 | "perf stat record [<options>]", | 1592 | "perf stat record [<options>]", |
1593 | NULL, | 1593 | NULL, |
1594 | }; | 1594 | }; |
@@ -1611,7 +1611,7 @@ static int __cmd_record(int argc, const char **argv) | |||
1611 | struct perf_session *session; | 1611 | struct perf_session *session; |
1612 | struct perf_data_file *file = &perf_stat.file; | 1612 | struct perf_data_file *file = &perf_stat.file; |
1613 | 1613 | ||
1614 | argc = parse_options(argc, argv, stat_options, record_usage, | 1614 | argc = parse_options(argc, argv, stat_options, stat_record_usage, |
1615 | PARSE_OPT_STOP_AT_NON_OPTION); | 1615 | PARSE_OPT_STOP_AT_NON_OPTION); |
1616 | 1616 | ||
1617 | if (output_name) | 1617 | if (output_name) |
@@ -1745,7 +1745,7 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused, | |||
1745 | return set_maps(st); | 1745 | return set_maps(st); |
1746 | } | 1746 | } |
1747 | 1747 | ||
1748 | static const char * const report_usage[] = { | 1748 | static const char * const stat_report_usage[] = { |
1749 | "perf stat report [<options>]", | 1749 | "perf stat report [<options>]", |
1750 | NULL, | 1750 | NULL, |
1751 | }; | 1751 | }; |
@@ -1779,7 +1779,7 @@ static int __cmd_report(int argc, const char **argv) | |||
1779 | struct stat st; | 1779 | struct stat st; |
1780 | int ret; | 1780 | int ret; |
1781 | 1781 | ||
1782 | argc = parse_options(argc, argv, options, report_usage, 0); | 1782 | argc = parse_options(argc, argv, options, stat_report_usage, 0); |
1783 | 1783 | ||
1784 | if (!input_name || !strlen(input_name)) { | 1784 | if (!input_name || !strlen(input_name)) { |
1785 | if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) | 1785 | if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 254d06e39bea..e5959c136a19 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -17,7 +17,7 @@ detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected) | |||
17 | 17 | ||
18 | CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) | 18 | CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) |
19 | 19 | ||
20 | include $(src-perf)/config/Makefile.arch | 20 | include $(srctree)/tools/scripts/Makefile.arch |
21 | 21 | ||
22 | $(call detected_var,ARCH) | 22 | $(call detected_var,ARCH) |
23 | 23 | ||
@@ -493,7 +493,7 @@ else | |||
493 | 493 | ||
494 | PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) | 494 | PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) |
495 | PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) | 495 | PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) |
496 | PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) | 496 | PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil |
497 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | 497 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) |
498 | FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | 498 | FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) |
499 | 499 | ||
@@ -692,6 +692,7 @@ template_dir = share/perf-core/templates | |||
692 | STRACE_GROUPS_DIR = share/perf-core/strace/groups | 692 | STRACE_GROUPS_DIR = share/perf-core/strace/groups |
693 | htmldir = share/doc/perf-doc | 693 | htmldir = share/doc/perf-doc |
694 | tipdir = share/doc/perf-tip | 694 | tipdir = share/doc/perf-tip |
695 | srcdir = $(srctree)/tools/perf | ||
695 | ifeq ($(prefix),/usr) | 696 | ifeq ($(prefix),/usr) |
696 | sysconfdir = /etc | 697 | sysconfdir = /etc |
697 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig | 698 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig |
@@ -722,6 +723,7 @@ tipdir_SQ = $(subst ','\'',$(tipdir)) | |||
722 | prefix_SQ = $(subst ','\'',$(prefix)) | 723 | prefix_SQ = $(subst ','\'',$(prefix)) |
723 | sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) | 724 | sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) |
724 | libdir_SQ = $(subst ','\'',$(libdir)) | 725 | libdir_SQ = $(subst ','\'',$(libdir)) |
726 | srcdir_SQ = $(subst ','\'',$(srcdir)) | ||
725 | 727 | ||
726 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) | 728 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) |
727 | perfexec_instdir = $(perfexecdir) | 729 | perfexec_instdir = $(perfexecdir) |
@@ -776,6 +778,7 @@ $(call detected_var,STRACE_GROUPS_DIR_SQ) | |||
776 | $(call detected_var,prefix_SQ) | 778 | $(call detected_var,prefix_SQ) |
777 | $(call detected_var,perfexecdir_SQ) | 779 | $(call detected_var,perfexecdir_SQ) |
778 | $(call detected_var,tipdir_SQ) | 780 | $(call detected_var,tipdir_SQ) |
781 | $(call detected_var,srcdir_SQ) | ||
779 | $(call detected_var,LIBDIR) | 782 | $(call detected_var,LIBDIR) |
780 | $(call detected_var,GTK_CFLAGS) | 783 | $(call detected_var,GTK_CFLAGS) |
781 | $(call detected_var,PERL_EMBED_CCOPTS) | 784 | $(call detected_var,PERL_EMBED_CCOPTS) |
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c index bcfd081ee1d2..071a8b5f5232 100644 --- a/tools/perf/tests/hists_common.c +++ b/tools/perf/tests/hists_common.c | |||
@@ -87,11 +87,6 @@ struct machine *setup_fake_machine(struct machines *machines) | |||
87 | return NULL; | 87 | return NULL; |
88 | } | 88 | } |
89 | 89 | ||
90 | if (machine__create_kernel_maps(machine)) { | ||
91 | pr_debug("Cannot create kernel maps\n"); | ||
92 | return NULL; | ||
93 | } | ||
94 | |||
95 | for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { | 90 | for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { |
96 | struct thread *thread; | 91 | struct thread *thread; |
97 | 92 | ||
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index e36089212061..5e6a86e50fb9 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c | |||
@@ -706,6 +706,7 @@ int test__hists_cumulate(int subtest __maybe_unused) | |||
706 | err = parse_events(evlist, "cpu-clock", NULL); | 706 | err = parse_events(evlist, "cpu-clock", NULL); |
707 | if (err) | 707 | if (err) |
708 | goto out; | 708 | goto out; |
709 | err = TEST_FAIL; | ||
709 | 710 | ||
710 | machines__init(&machines); | 711 | machines__init(&machines); |
711 | 712 | ||
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 2a784befd9ce..351a42463444 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c | |||
@@ -120,6 +120,7 @@ int test__hists_filter(int subtest __maybe_unused) | |||
120 | err = parse_events(evlist, "task-clock", NULL); | 120 | err = parse_events(evlist, "task-clock", NULL); |
121 | if (err) | 121 | if (err) |
122 | goto out; | 122 | goto out; |
123 | err = TEST_FAIL; | ||
123 | 124 | ||
124 | /* default sort order (comm,dso,sym) will be used */ | 125 | /* default sort order (comm,dso,sym) will be used */ |
125 | if (setup_sorting(NULL) < 0) | 126 | if (setup_sorting(NULL) < 0) |
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index c764d69ac6ef..64b257d8d557 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c | |||
@@ -293,6 +293,7 @@ int test__hists_link(int subtest __maybe_unused) | |||
293 | if (err) | 293 | if (err) |
294 | goto out; | 294 | goto out; |
295 | 295 | ||
296 | err = TEST_FAIL; | ||
296 | /* default sort order (comm,dso,sym) will be used */ | 297 | /* default sort order (comm,dso,sym) will be used */ |
297 | if (setup_sorting(NULL) < 0) | 298 | if (setup_sorting(NULL) < 0) |
298 | goto out; | 299 | goto out; |
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index ebe6cd485b5d..b231265148d8 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c | |||
@@ -597,6 +597,7 @@ int test__hists_output(int subtest __maybe_unused) | |||
597 | err = parse_events(evlist, "cpu-clock", NULL); | 597 | err = parse_events(evlist, "cpu-clock", NULL); |
598 | if (err) | 598 | if (err) |
599 | goto out; | 599 | goto out; |
600 | err = TEST_FAIL; | ||
600 | 601 | ||
601 | machines__init(&machines); | 602 | machines__init(&machines); |
602 | 603 | ||
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index c1fbb8e884c0..df38decc48c3 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -1,3 +1,5 @@ | |||
1 | include ../scripts/Makefile.include | ||
2 | |||
1 | ifndef MK | 3 | ifndef MK |
2 | ifeq ($(MAKECMDGOALS),) | 4 | ifeq ($(MAKECMDGOALS),) |
3 | # no target specified, trigger the whole suite | 5 | # no target specified, trigger the whole suite |
@@ -12,7 +14,19 @@ endif | |||
12 | else | 14 | else |
13 | PERF := . | 15 | PERF := . |
14 | 16 | ||
15 | include config/Makefile.arch | 17 | # As per kernel Makefile, avoid funny character set dependencies |
18 | unexport LC_ALL | ||
19 | LC_COLLATE=C | ||
20 | LC_NUMERIC=C | ||
21 | export LC_COLLATE LC_NUMERIC | ||
22 | |||
23 | ifeq ($(srctree),) | ||
24 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | ||
25 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
26 | #$(info Determined 'srctree' to be $(srctree)) | ||
27 | endif | ||
28 | |||
29 | include $(srctree)/tools/scripts/Makefile.arch | ||
16 | 30 | ||
17 | # FIXME looks like x86 is the only arch running tests ;-) | 31 | # FIXME looks like x86 is the only arch running tests ;-) |
18 | # we need some IS_(32/64) flag to make this generic | 32 | # we need some IS_(32/64) flag to make this generic |
@@ -280,5 +294,5 @@ all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools | |||
280 | out: $(run_O) | 294 | out: $(run_O) |
281 | @echo OK | 295 | @echo OK |
282 | 296 | ||
283 | .PHONY: all $(run) $(run_O) tarpkg clean | 297 | .PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools |
284 | endif # ifndef MK | 298 | endif # ifndef MK |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 901d481e6cea..08c09ad755d2 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -480,7 +480,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *help) | |||
480 | 480 | ||
481 | hists__browser_title(browser->hists, hbt, title, sizeof(title)); | 481 | hists__browser_title(browser->hists, hbt, title, sizeof(title)); |
482 | 482 | ||
483 | if (ui_browser__show(&browser->b, title, help) < 0) | 483 | if (ui_browser__show(&browser->b, title, "%s", help) < 0) |
484 | return -1; | 484 | return -1; |
485 | 485 | ||
486 | while (1) { | 486 | while (1) { |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index cd61bb1f3917..85155e91b61b 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -503,7 +503,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, | |||
503 | if (comm_event == NULL) | 503 | if (comm_event == NULL) |
504 | goto out; | 504 | goto out; |
505 | 505 | ||
506 | mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); | 506 | mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); |
507 | if (mmap_event == NULL) | 507 | if (mmap_event == NULL) |
508 | goto out_free_comm; | 508 | goto out_free_comm; |
509 | 509 | ||
@@ -577,7 +577,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
577 | if (comm_event == NULL) | 577 | if (comm_event == NULL) |
578 | goto out; | 578 | goto out; |
579 | 579 | ||
580 | mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); | 580 | mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); |
581 | if (mmap_event == NULL) | 581 | if (mmap_event == NULL) |
582 | goto out_free_comm; | 582 | goto out_free_comm; |
583 | 583 | ||
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index bdf98f6f27bb..0d3dfcb919b4 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c | |||
@@ -126,6 +126,11 @@ static int strlist__parse_list_entry(struct strlist *slist, const char *s, | |||
126 | err = strlist__load(slist, subst); | 126 | err = strlist__load(slist, subst); |
127 | goto out; | 127 | goto out; |
128 | } | 128 | } |
129 | |||
130 | if (slist->file_only) { | ||
131 | err = -ENOENT; | ||
132 | goto out; | ||
133 | } | ||
129 | } | 134 | } |
130 | 135 | ||
131 | err = strlist__add(slist, s); | 136 | err = strlist__add(slist, s); |
@@ -157,11 +162,13 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf | |||
157 | 162 | ||
158 | if (slist != NULL) { | 163 | if (slist != NULL) { |
159 | bool dupstr = true; | 164 | bool dupstr = true; |
165 | bool file_only = false; | ||
160 | const char *dirname = NULL; | 166 | const char *dirname = NULL; |
161 | 167 | ||
162 | if (config) { | 168 | if (config) { |
163 | dupstr = !config->dont_dupstr; | 169 | dupstr = !config->dont_dupstr; |
164 | dirname = config->dirname; | 170 | dirname = config->dirname; |
171 | file_only = config->file_only; | ||
165 | } | 172 | } |
166 | 173 | ||
167 | rblist__init(&slist->rblist); | 174 | rblist__init(&slist->rblist); |
@@ -170,6 +177,7 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf | |||
170 | slist->rblist.node_delete = strlist__node_delete; | 177 | slist->rblist.node_delete = strlist__node_delete; |
171 | 178 | ||
172 | slist->dupstr = dupstr; | 179 | slist->dupstr = dupstr; |
180 | slist->file_only = file_only; | ||
173 | 181 | ||
174 | if (list && strlist__parse_list(slist, list, dirname) != 0) | 182 | if (list && strlist__parse_list(slist, list, dirname) != 0) |
175 | goto out_error; | 183 | goto out_error; |
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h index 297565aa7535..ca990029e243 100644 --- a/tools/perf/util/strlist.h +++ b/tools/perf/util/strlist.h | |||
@@ -13,11 +13,18 @@ struct str_node { | |||
13 | 13 | ||
14 | struct strlist { | 14 | struct strlist { |
15 | struct rblist rblist; | 15 | struct rblist rblist; |
16 | bool dupstr; | 16 | bool dupstr; |
17 | bool file_only; | ||
17 | }; | 18 | }; |
18 | 19 | ||
20 | /* | ||
21 | * @file_only: When dirname is present, only consider entries as filenames, | ||
22 | * that should not be added to the list if dirname/entry is not | ||
23 | * found | ||
24 | */ | ||
19 | struct strlist_config { | 25 | struct strlist_config { |
20 | bool dont_dupstr; | 26 | bool dont_dupstr; |
27 | bool file_only; | ||
21 | const char *dirname; | 28 | const char *dirname; |
22 | }; | 29 | }; |
23 | 30 | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 88b8f8d21f58..ead9509835d2 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <unistd.h> | 17 | #include <unistd.h> |
18 | #include "callchain.h" | 18 | #include "callchain.h" |
19 | #include "strlist.h" | 19 | #include "strlist.h" |
20 | #include <subcmd/exec-cmd.h> | ||
21 | 20 | ||
22 | struct callchain_param callchain_param = { | 21 | struct callchain_param callchain_param = { |
23 | .mode = CHAIN_GRAPH_ABS, | 22 | .mode = CHAIN_GRAPH_ABS, |
@@ -672,14 +671,16 @@ const char *perf_tip(const char *dirpath) | |||
672 | struct str_node *node; | 671 | struct str_node *node; |
673 | char *tip = NULL; | 672 | char *tip = NULL; |
674 | struct strlist_config conf = { | 673 | struct strlist_config conf = { |
675 | .dirname = system_path(dirpath) , | 674 | .dirname = dirpath, |
675 | .file_only = true, | ||
676 | }; | 676 | }; |
677 | 677 | ||
678 | tips = strlist__new("tips.txt", &conf); | 678 | tips = strlist__new("tips.txt", &conf); |
679 | if (tips == NULL || strlist__nr_entries(tips) == 1) { | 679 | if (tips == NULL) |
680 | tip = (char *)"Cannot find tips.txt file"; | 680 | return errno == ENOENT ? NULL : "Tip: get more memory! ;-p"; |
681 | |||
682 | if (strlist__nr_entries(tips) == 0) | ||
681 | goto out; | 683 | goto out; |
682 | } | ||
683 | 684 | ||
684 | node = strlist__entry(tips, random() % strlist__nr_entries(tips)); | 685 | node = strlist__entry(tips, random() % strlist__nr_entries(tips)); |
685 | if (asprintf(&tip, "Tip: %s", node->s) < 0) | 686 | if (asprintf(&tip, "Tip: %s", node->s) < 0) |
diff --git a/tools/perf/config/Makefile.arch b/tools/scripts/Makefile.arch index e11fbd6fae78..e11fbd6fae78 100644 --- a/tools/perf/config/Makefile.arch +++ b/tools/scripts/Makefile.arch | |||
diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore new file mode 100644 index 000000000000..4280576397e8 --- /dev/null +++ b/tools/spi/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | spidev_fdx | ||
2 | spidev_test | ||
diff --git a/tools/spi/Makefile b/tools/spi/Makefile new file mode 100644 index 000000000000..cd0db62e4d9d --- /dev/null +++ b/tools/spi/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | all: spidev_test spidev_fdx | ||
2 | |||
3 | clean: | ||
4 | $(RM) spidev_test spidev_fdx | ||
diff --git a/tools/spi/spidev_fdx.c b/tools/spi/spidev_fdx.c new file mode 100644 index 000000000000..0ea3e51292fc --- /dev/null +++ b/tools/spi/spidev_fdx.c | |||
@@ -0,0 +1,158 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #include <sys/ioctl.h> | ||
8 | #include <sys/types.h> | ||
9 | #include <sys/stat.h> | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | #include <linux/spi/spidev.h> | ||
13 | |||
14 | |||
15 | static int verbose; | ||
16 | |||
17 | static void do_read(int fd, int len) | ||
18 | { | ||
19 | unsigned char buf[32], *bp; | ||
20 | int status; | ||
21 | |||
22 | /* read at least 2 bytes, no more than 32 */ | ||
23 | if (len < 2) | ||
24 | len = 2; | ||
25 | else if (len > sizeof(buf)) | ||
26 | len = sizeof(buf); | ||
27 | memset(buf, 0, sizeof buf); | ||
28 | |||
29 | status = read(fd, buf, len); | ||
30 | if (status < 0) { | ||
31 | perror("read"); | ||
32 | return; | ||
33 | } | ||
34 | if (status != len) { | ||
35 | fprintf(stderr, "short read\n"); | ||
36 | return; | ||
37 | } | ||
38 | |||
39 | printf("read(%2d, %2d): %02x %02x,", len, status, | ||
40 | buf[0], buf[1]); | ||
41 | status -= 2; | ||
42 | bp = buf + 2; | ||
43 | while (status-- > 0) | ||
44 | printf(" %02x", *bp++); | ||
45 | printf("\n"); | ||
46 | } | ||
47 | |||
48 | static void do_msg(int fd, int len) | ||
49 | { | ||
50 | struct spi_ioc_transfer xfer[2]; | ||
51 | unsigned char buf[32], *bp; | ||
52 | int status; | ||
53 | |||
54 | memset(xfer, 0, sizeof xfer); | ||
55 | memset(buf, 0, sizeof buf); | ||
56 | |||
57 | if (len > sizeof buf) | ||
58 | len = sizeof buf; | ||
59 | |||
60 | buf[0] = 0xaa; | ||
61 | xfer[0].tx_buf = (unsigned long)buf; | ||
62 | xfer[0].len = 1; | ||
63 | |||
64 | xfer[1].rx_buf = (unsigned long) buf; | ||
65 | xfer[1].len = len; | ||
66 | |||
67 | status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer); | ||
68 | if (status < 0) { | ||
69 | perror("SPI_IOC_MESSAGE"); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | printf("response(%2d, %2d): ", len, status); | ||
74 | for (bp = buf; len; len--) | ||
75 | printf(" %02x", *bp++); | ||
76 | printf("\n"); | ||
77 | } | ||
78 | |||
79 | static void dumpstat(const char *name, int fd) | ||
80 | { | ||
81 | __u8 lsb, bits; | ||
82 | __u32 mode, speed; | ||
83 | |||
84 | if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) { | ||
85 | perror("SPI rd_mode"); | ||
86 | return; | ||
87 | } | ||
88 | if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) { | ||
89 | perror("SPI rd_lsb_fist"); | ||
90 | return; | ||
91 | } | ||
92 | if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) { | ||
93 | perror("SPI bits_per_word"); | ||
94 | return; | ||
95 | } | ||
96 | if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) { | ||
97 | perror("SPI max_speed_hz"); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n", | ||
102 | name, mode, bits, lsb ? "(lsb first) " : "", speed); | ||
103 | } | ||
104 | |||
105 | int main(int argc, char **argv) | ||
106 | { | ||
107 | int c; | ||
108 | int readcount = 0; | ||
109 | int msglen = 0; | ||
110 | int fd; | ||
111 | const char *name; | ||
112 | |||
113 | while ((c = getopt(argc, argv, "hm:r:v")) != EOF) { | ||
114 | switch (c) { | ||
115 | case 'm': | ||
116 | msglen = atoi(optarg); | ||
117 | if (msglen < 0) | ||
118 | goto usage; | ||
119 | continue; | ||
120 | case 'r': | ||
121 | readcount = atoi(optarg); | ||
122 | if (readcount < 0) | ||
123 | goto usage; | ||
124 | continue; | ||
125 | case 'v': | ||
126 | verbose++; | ||
127 | continue; | ||
128 | case 'h': | ||
129 | case '?': | ||
130 | usage: | ||
131 | fprintf(stderr, | ||
132 | "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n", | ||
133 | argv[0]); | ||
134 | return 1; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | if ((optind + 1) != argc) | ||
139 | goto usage; | ||
140 | name = argv[optind]; | ||
141 | |||
142 | fd = open(name, O_RDWR); | ||
143 | if (fd < 0) { | ||
144 | perror("open"); | ||
145 | return 1; | ||
146 | } | ||
147 | |||
148 | dumpstat(name, fd); | ||
149 | |||
150 | if (msglen) | ||
151 | do_msg(fd, msglen); | ||
152 | |||
153 | if (readcount) | ||
154 | do_read(fd, readcount); | ||
155 | |||
156 | close(fd); | ||
157 | return 0; | ||
158 | } | ||
diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c new file mode 100644 index 000000000000..8a73d8185316 --- /dev/null +++ b/tools/spi/spidev_test.c | |||
@@ -0,0 +1,399 @@ | |||
1 | /* | ||
2 | * SPI testing utility (using spidev driver) | ||
3 | * | ||
4 | * Copyright (c) 2007 MontaVista Software, Inc. | ||
5 | * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License. | ||
10 | * | ||
11 | * Cross-compile with cross-gcc -I/path/to/cross-kernel/include | ||
12 | */ | ||
13 | |||
14 | #include <stdint.h> | ||
15 | #include <unistd.h> | ||
16 | #include <stdio.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | #include <getopt.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <sys/ioctl.h> | ||
22 | #include <sys/stat.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/spi/spidev.h> | ||
25 | |||
26 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) | ||
27 | |||
28 | static void pabort(const char *s) | ||
29 | { | ||
30 | perror(s); | ||
31 | abort(); | ||
32 | } | ||
33 | |||
34 | static const char *device = "/dev/spidev1.1"; | ||
35 | static uint32_t mode; | ||
36 | static uint8_t bits = 8; | ||
37 | static char *input_file; | ||
38 | static char *output_file; | ||
39 | static uint32_t speed = 500000; | ||
40 | static uint16_t delay; | ||
41 | static int verbose; | ||
42 | |||
43 | uint8_t default_tx[] = { | ||
44 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
45 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, | ||
46 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
47 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
48 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
49 | 0xF0, 0x0D, | ||
50 | }; | ||
51 | |||
52 | uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, }; | ||
53 | char *input_tx; | ||
54 | |||
55 | static void hex_dump(const void *src, size_t length, size_t line_size, | ||
56 | char *prefix) | ||
57 | { | ||
58 | int i = 0; | ||
59 | const unsigned char *address = src; | ||
60 | const unsigned char *line = address; | ||
61 | unsigned char c; | ||
62 | |||
63 | printf("%s | ", prefix); | ||
64 | while (length-- > 0) { | ||
65 | printf("%02X ", *address++); | ||
66 | if (!(++i % line_size) || (length == 0 && i % line_size)) { | ||
67 | if (length == 0) { | ||
68 | while (i++ % line_size) | ||
69 | printf("__ "); | ||
70 | } | ||
71 | printf(" | "); /* right close */ | ||
72 | while (line < address) { | ||
73 | c = *line++; | ||
74 | printf("%c", (c < 33 || c == 255) ? 0x2E : c); | ||
75 | } | ||
76 | printf("\n"); | ||
77 | if (length > 0) | ||
78 | printf("%s | ", prefix); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Unescape - process hexadecimal escape character | ||
85 | * converts shell input "\x23" -> 0x23 | ||
86 | */ | ||
87 | static int unescape(char *_dst, char *_src, size_t len) | ||
88 | { | ||
89 | int ret = 0; | ||
90 | int match; | ||
91 | char *src = _src; | ||
92 | char *dst = _dst; | ||
93 | unsigned int ch; | ||
94 | |||
95 | while (*src) { | ||
96 | if (*src == '\\' && *(src+1) == 'x') { | ||
97 | match = sscanf(src + 2, "%2x", &ch); | ||
98 | if (!match) | ||
99 | pabort("malformed input string"); | ||
100 | |||
101 | src += 4; | ||
102 | *dst++ = (unsigned char)ch; | ||
103 | } else { | ||
104 | *dst++ = *src++; | ||
105 | } | ||
106 | ret++; | ||
107 | } | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) | ||
112 | { | ||
113 | int ret; | ||
114 | int out_fd; | ||
115 | struct spi_ioc_transfer tr = { | ||
116 | .tx_buf = (unsigned long)tx, | ||
117 | .rx_buf = (unsigned long)rx, | ||
118 | .len = len, | ||
119 | .delay_usecs = delay, | ||
120 | .speed_hz = speed, | ||
121 | .bits_per_word = bits, | ||
122 | }; | ||
123 | |||
124 | if (mode & SPI_TX_QUAD) | ||
125 | tr.tx_nbits = 4; | ||
126 | else if (mode & SPI_TX_DUAL) | ||
127 | tr.tx_nbits = 2; | ||
128 | if (mode & SPI_RX_QUAD) | ||
129 | tr.rx_nbits = 4; | ||
130 | else if (mode & SPI_RX_DUAL) | ||
131 | tr.rx_nbits = 2; | ||
132 | if (!(mode & SPI_LOOP)) { | ||
133 | if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) | ||
134 | tr.rx_buf = 0; | ||
135 | else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) | ||
136 | tr.tx_buf = 0; | ||
137 | } | ||
138 | |||
139 | ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); | ||
140 | if (ret < 1) | ||
141 | pabort("can't send spi message"); | ||
142 | |||
143 | if (verbose) | ||
144 | hex_dump(tx, len, 32, "TX"); | ||
145 | |||
146 | if (output_file) { | ||
147 | out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); | ||
148 | if (out_fd < 0) | ||
149 | pabort("could not open output file"); | ||
150 | |||
151 | ret = write(out_fd, rx, len); | ||
152 | if (ret != len) | ||
153 | pabort("not all bytes written to output file"); | ||
154 | |||
155 | close(out_fd); | ||
156 | } | ||
157 | |||
158 | if (verbose || !output_file) | ||
159 | hex_dump(rx, len, 32, "RX"); | ||
160 | } | ||
161 | |||
162 | static void print_usage(const char *prog) | ||
163 | { | ||
164 | printf("Usage: %s [-DsbdlHOLC3]\n", prog); | ||
165 | puts(" -D --device device to use (default /dev/spidev1.1)\n" | ||
166 | " -s --speed max speed (Hz)\n" | ||
167 | " -d --delay delay (usec)\n" | ||
168 | " -b --bpw bits per word\n" | ||
169 | " -i --input input data from a file (e.g. \"test.bin\")\n" | ||
170 | " -o --output output data to a file (e.g. \"results.bin\")\n" | ||
171 | " -l --loop loopback\n" | ||
172 | " -H --cpha clock phase\n" | ||
173 | " -O --cpol clock polarity\n" | ||
174 | " -L --lsb least significant bit first\n" | ||
175 | " -C --cs-high chip select active high\n" | ||
176 | " -3 --3wire SI/SO signals shared\n" | ||
177 | " -v --verbose Verbose (show tx buffer)\n" | ||
178 | " -p Send data (e.g. \"1234\\xde\\xad\")\n" | ||
179 | " -N --no-cs no chip select\n" | ||
180 | " -R --ready slave pulls low to pause\n" | ||
181 | " -2 --dual dual transfer\n" | ||
182 | " -4 --quad quad transfer\n"); | ||
183 | exit(1); | ||
184 | } | ||
185 | |||
186 | static void parse_opts(int argc, char *argv[]) | ||
187 | { | ||
188 | while (1) { | ||
189 | static const struct option lopts[] = { | ||
190 | { "device", 1, 0, 'D' }, | ||
191 | { "speed", 1, 0, 's' }, | ||
192 | { "delay", 1, 0, 'd' }, | ||
193 | { "bpw", 1, 0, 'b' }, | ||
194 | { "input", 1, 0, 'i' }, | ||
195 | { "output", 1, 0, 'o' }, | ||
196 | { "loop", 0, 0, 'l' }, | ||
197 | { "cpha", 0, 0, 'H' }, | ||
198 | { "cpol", 0, 0, 'O' }, | ||
199 | { "lsb", 0, 0, 'L' }, | ||
200 | { "cs-high", 0, 0, 'C' }, | ||
201 | { "3wire", 0, 0, '3' }, | ||
202 | { "no-cs", 0, 0, 'N' }, | ||
203 | { "ready", 0, 0, 'R' }, | ||
204 | { "dual", 0, 0, '2' }, | ||
205 | { "verbose", 0, 0, 'v' }, | ||
206 | { "quad", 0, 0, '4' }, | ||
207 | { NULL, 0, 0, 0 }, | ||
208 | }; | ||
209 | int c; | ||
210 | |||
211 | c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v", | ||
212 | lopts, NULL); | ||
213 | |||
214 | if (c == -1) | ||
215 | break; | ||
216 | |||
217 | switch (c) { | ||
218 | case 'D': | ||
219 | device = optarg; | ||
220 | break; | ||
221 | case 's': | ||
222 | speed = atoi(optarg); | ||
223 | break; | ||
224 | case 'd': | ||
225 | delay = atoi(optarg); | ||
226 | break; | ||
227 | case 'b': | ||
228 | bits = atoi(optarg); | ||
229 | break; | ||
230 | case 'i': | ||
231 | input_file = optarg; | ||
232 | break; | ||
233 | case 'o': | ||
234 | output_file = optarg; | ||
235 | break; | ||
236 | case 'l': | ||
237 | mode |= SPI_LOOP; | ||
238 | break; | ||
239 | case 'H': | ||
240 | mode |= SPI_CPHA; | ||
241 | break; | ||
242 | case 'O': | ||
243 | mode |= SPI_CPOL; | ||
244 | break; | ||
245 | case 'L': | ||
246 | mode |= SPI_LSB_FIRST; | ||
247 | break; | ||
248 | case 'C': | ||
249 | mode |= SPI_CS_HIGH; | ||
250 | break; | ||
251 | case '3': | ||
252 | mode |= SPI_3WIRE; | ||
253 | break; | ||
254 | case 'N': | ||
255 | mode |= SPI_NO_CS; | ||
256 | break; | ||
257 | case 'v': | ||
258 | verbose = 1; | ||
259 | break; | ||
260 | case 'R': | ||
261 | mode |= SPI_READY; | ||
262 | break; | ||
263 | case 'p': | ||
264 | input_tx = optarg; | ||
265 | break; | ||
266 | case '2': | ||
267 | mode |= SPI_TX_DUAL; | ||
268 | break; | ||
269 | case '4': | ||
270 | mode |= SPI_TX_QUAD; | ||
271 | break; | ||
272 | default: | ||
273 | print_usage(argv[0]); | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | if (mode & SPI_LOOP) { | ||
278 | if (mode & SPI_TX_DUAL) | ||
279 | mode |= SPI_RX_DUAL; | ||
280 | if (mode & SPI_TX_QUAD) | ||
281 | mode |= SPI_RX_QUAD; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void transfer_escaped_string(int fd, char *str) | ||
286 | { | ||
287 | size_t size = strlen(str + 1); | ||
288 | uint8_t *tx; | ||
289 | uint8_t *rx; | ||
290 | |||
291 | tx = malloc(size); | ||
292 | if (!tx) | ||
293 | pabort("can't allocate tx buffer"); | ||
294 | |||
295 | rx = malloc(size); | ||
296 | if (!rx) | ||
297 | pabort("can't allocate rx buffer"); | ||
298 | |||
299 | size = unescape((char *)tx, str, size); | ||
300 | transfer(fd, tx, rx, size); | ||
301 | free(rx); | ||
302 | free(tx); | ||
303 | } | ||
304 | |||
305 | static void transfer_file(int fd, char *filename) | ||
306 | { | ||
307 | ssize_t bytes; | ||
308 | struct stat sb; | ||
309 | int tx_fd; | ||
310 | uint8_t *tx; | ||
311 | uint8_t *rx; | ||
312 | |||
313 | if (stat(filename, &sb) == -1) | ||
314 | pabort("can't stat input file"); | ||
315 | |||
316 | tx_fd = open(filename, O_RDONLY); | ||
317 | if (fd < 0) | ||
318 | pabort("can't open input file"); | ||
319 | |||
320 | tx = malloc(sb.st_size); | ||
321 | if (!tx) | ||
322 | pabort("can't allocate tx buffer"); | ||
323 | |||
324 | rx = malloc(sb.st_size); | ||
325 | if (!rx) | ||
326 | pabort("can't allocate rx buffer"); | ||
327 | |||
328 | bytes = read(tx_fd, tx, sb.st_size); | ||
329 | if (bytes != sb.st_size) | ||
330 | pabort("failed to read input file"); | ||
331 | |||
332 | transfer(fd, tx, rx, sb.st_size); | ||
333 | free(rx); | ||
334 | free(tx); | ||
335 | close(tx_fd); | ||
336 | } | ||
337 | |||
338 | int main(int argc, char *argv[]) | ||
339 | { | ||
340 | int ret = 0; | ||
341 | int fd; | ||
342 | |||
343 | parse_opts(argc, argv); | ||
344 | |||
345 | fd = open(device, O_RDWR); | ||
346 | if (fd < 0) | ||
347 | pabort("can't open device"); | ||
348 | |||
349 | /* | ||
350 | * spi mode | ||
351 | */ | ||
352 | ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode); | ||
353 | if (ret == -1) | ||
354 | pabort("can't set spi mode"); | ||
355 | |||
356 | ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode); | ||
357 | if (ret == -1) | ||
358 | pabort("can't get spi mode"); | ||
359 | |||
360 | /* | ||
361 | * bits per word | ||
362 | */ | ||
363 | ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); | ||
364 | if (ret == -1) | ||
365 | pabort("can't set bits per word"); | ||
366 | |||
367 | ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); | ||
368 | if (ret == -1) | ||
369 | pabort("can't get bits per word"); | ||
370 | |||
371 | /* | ||
372 | * max speed hz | ||
373 | */ | ||
374 | ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); | ||
375 | if (ret == -1) | ||
376 | pabort("can't set max speed hz"); | ||
377 | |||
378 | ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); | ||
379 | if (ret == -1) | ||
380 | pabort("can't get max speed hz"); | ||
381 | |||
382 | printf("spi mode: 0x%x\n", mode); | ||
383 | printf("bits per word: %d\n", bits); | ||
384 | printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); | ||
385 | |||
386 | if (input_tx && input_file) | ||
387 | pabort("only one of -p and --input may be selected"); | ||
388 | |||
389 | if (input_tx) | ||
390 | transfer_escaped_string(fd, input_tx); | ||
391 | else if (input_file) | ||
392 | transfer_file(fd, input_file); | ||
393 | else | ||
394 | transfer(fd, default_tx, default_rx, sizeof(default_tx)); | ||
395 | |||
396 | close(fd); | ||
397 | |||
398 | return ret; | ||
399 | } | ||
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 38b00ecb2ed5..a34bfd0c8928 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild | |||
@@ -9,6 +9,8 @@ ldflags-y += --wrap=memunmap | |||
9 | ldflags-y += --wrap=__devm_request_region | 9 | ldflags-y += --wrap=__devm_request_region |
10 | ldflags-y += --wrap=__request_region | 10 | ldflags-y += --wrap=__request_region |
11 | ldflags-y += --wrap=__release_region | 11 | ldflags-y += --wrap=__release_region |
12 | ldflags-y += --wrap=devm_memremap_pages | ||
13 | ldflags-y += --wrap=phys_to_pfn_t | ||
12 | 14 | ||
13 | DRIVERS := ../../../drivers | 15 | DRIVERS := ../../../drivers |
14 | NVDIMM_SRC := $(DRIVERS)/nvdimm | 16 | NVDIMM_SRC := $(DRIVERS)/nvdimm |
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index b7251314bbc0..7ec7df9e7fc7 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/mm.h> | ||
19 | #include "nfit_test.h" | 20 | #include "nfit_test.h" |
20 | 21 | ||
21 | static LIST_HEAD(iomap_head); | 22 | static LIST_HEAD(iomap_head); |
@@ -41,7 +42,7 @@ void nfit_test_teardown(void) | |||
41 | } | 42 | } |
42 | EXPORT_SYMBOL(nfit_test_teardown); | 43 | EXPORT_SYMBOL(nfit_test_teardown); |
43 | 44 | ||
44 | static struct nfit_test_resource *get_nfit_res(resource_size_t resource) | 45 | static struct nfit_test_resource *__get_nfit_res(resource_size_t resource) |
45 | { | 46 | { |
46 | struct iomap_ops *ops; | 47 | struct iomap_ops *ops; |
47 | 48 | ||
@@ -51,14 +52,22 @@ static struct nfit_test_resource *get_nfit_res(resource_size_t resource) | |||
51 | return NULL; | 52 | return NULL; |
52 | } | 53 | } |
53 | 54 | ||
54 | void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size, | 55 | static struct nfit_test_resource *get_nfit_res(resource_size_t resource) |
55 | void __iomem *(*fallback_fn)(resource_size_t, unsigned long)) | ||
56 | { | 56 | { |
57 | struct nfit_test_resource *nfit_res; | 57 | struct nfit_test_resource *res; |
58 | 58 | ||
59 | rcu_read_lock(); | 59 | rcu_read_lock(); |
60 | nfit_res = get_nfit_res(offset); | 60 | res = __get_nfit_res(resource); |
61 | rcu_read_unlock(); | 61 | rcu_read_unlock(); |
62 | |||
63 | return res; | ||
64 | } | ||
65 | |||
66 | void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size, | ||
67 | void __iomem *(*fallback_fn)(resource_size_t, unsigned long)) | ||
68 | { | ||
69 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); | ||
70 | |||
62 | if (nfit_res) | 71 | if (nfit_res) |
63 | return (void __iomem *) nfit_res->buf + offset | 72 | return (void __iomem *) nfit_res->buf + offset |
64 | - nfit_res->res->start; | 73 | - nfit_res->res->start; |
@@ -68,11 +77,8 @@ void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size, | |||
68 | void __iomem *__wrap_devm_ioremap_nocache(struct device *dev, | 77 | void __iomem *__wrap_devm_ioremap_nocache(struct device *dev, |
69 | resource_size_t offset, unsigned long size) | 78 | resource_size_t offset, unsigned long size) |
70 | { | 79 | { |
71 | struct nfit_test_resource *nfit_res; | 80 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); |
72 | 81 | ||
73 | rcu_read_lock(); | ||
74 | nfit_res = get_nfit_res(offset); | ||
75 | rcu_read_unlock(); | ||
76 | if (nfit_res) | 82 | if (nfit_res) |
77 | return (void __iomem *) nfit_res->buf + offset | 83 | return (void __iomem *) nfit_res->buf + offset |
78 | - nfit_res->res->start; | 84 | - nfit_res->res->start; |
@@ -83,25 +89,58 @@ EXPORT_SYMBOL(__wrap_devm_ioremap_nocache); | |||
83 | void *__wrap_devm_memremap(struct device *dev, resource_size_t offset, | 89 | void *__wrap_devm_memremap(struct device *dev, resource_size_t offset, |
84 | size_t size, unsigned long flags) | 90 | size_t size, unsigned long flags) |
85 | { | 91 | { |
86 | struct nfit_test_resource *nfit_res; | 92 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); |
87 | 93 | ||
88 | rcu_read_lock(); | ||
89 | nfit_res = get_nfit_res(offset); | ||
90 | rcu_read_unlock(); | ||
91 | if (nfit_res) | 94 | if (nfit_res) |
92 | return nfit_res->buf + offset - nfit_res->res->start; | 95 | return nfit_res->buf + offset - nfit_res->res->start; |
93 | return devm_memremap(dev, offset, size, flags); | 96 | return devm_memremap(dev, offset, size, flags); |
94 | } | 97 | } |
95 | EXPORT_SYMBOL(__wrap_devm_memremap); | 98 | EXPORT_SYMBOL(__wrap_devm_memremap); |
96 | 99 | ||
100 | #ifdef __HAVE_ARCH_PTE_DEVMAP | ||
101 | #include <linux/memremap.h> | ||
102 | #include <linux/pfn_t.h> | ||
103 | |||
104 | void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res, | ||
105 | struct percpu_ref *ref, struct vmem_altmap *altmap) | ||
106 | { | ||
107 | resource_size_t offset = res->start; | ||
108 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); | ||
109 | |||
110 | if (nfit_res) | ||
111 | return nfit_res->buf + offset - nfit_res->res->start; | ||
112 | return devm_memremap_pages(dev, res, ref, altmap); | ||
113 | } | ||
114 | EXPORT_SYMBOL(__wrap_devm_memremap_pages); | ||
115 | |||
116 | pfn_t __wrap_phys_to_pfn_t(dma_addr_t addr, unsigned long flags) | ||
117 | { | ||
118 | struct nfit_test_resource *nfit_res = get_nfit_res(addr); | ||
119 | |||
120 | if (nfit_res) | ||
121 | flags &= ~PFN_MAP; | ||
122 | return phys_to_pfn_t(addr, flags); | ||
123 | } | ||
124 | EXPORT_SYMBOL(__wrap_phys_to_pfn_t); | ||
125 | #else | ||
126 | /* to be removed post 4.5-rc1 */ | ||
127 | void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res) | ||
128 | { | ||
129 | resource_size_t offset = res->start; | ||
130 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); | ||
131 | |||
132 | if (nfit_res) | ||
133 | return nfit_res->buf + offset - nfit_res->res->start; | ||
134 | return devm_memremap_pages(dev, res); | ||
135 | } | ||
136 | EXPORT_SYMBOL(__wrap_devm_memremap_pages); | ||
137 | #endif | ||
138 | |||
97 | void *__wrap_memremap(resource_size_t offset, size_t size, | 139 | void *__wrap_memremap(resource_size_t offset, size_t size, |
98 | unsigned long flags) | 140 | unsigned long flags) |
99 | { | 141 | { |
100 | struct nfit_test_resource *nfit_res; | 142 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); |
101 | 143 | ||
102 | rcu_read_lock(); | ||
103 | nfit_res = get_nfit_res(offset); | ||
104 | rcu_read_unlock(); | ||
105 | if (nfit_res) | 144 | if (nfit_res) |
106 | return nfit_res->buf + offset - nfit_res->res->start; | 145 | return nfit_res->buf + offset - nfit_res->res->start; |
107 | return memremap(offset, size, flags); | 146 | return memremap(offset, size, flags); |
@@ -110,11 +149,8 @@ EXPORT_SYMBOL(__wrap_memremap); | |||
110 | 149 | ||
111 | void __wrap_devm_memunmap(struct device *dev, void *addr) | 150 | void __wrap_devm_memunmap(struct device *dev, void *addr) |
112 | { | 151 | { |
113 | struct nfit_test_resource *nfit_res; | 152 | struct nfit_test_resource *nfit_res = get_nfit_res((long) addr); |
114 | 153 | ||
115 | rcu_read_lock(); | ||
116 | nfit_res = get_nfit_res((unsigned long) addr); | ||
117 | rcu_read_unlock(); | ||
118 | if (nfit_res) | 154 | if (nfit_res) |
119 | return; | 155 | return; |
120 | return devm_memunmap(dev, addr); | 156 | return devm_memunmap(dev, addr); |
@@ -135,11 +171,7 @@ EXPORT_SYMBOL(__wrap_ioremap_wc); | |||
135 | 171 | ||
136 | void __wrap_iounmap(volatile void __iomem *addr) | 172 | void __wrap_iounmap(volatile void __iomem *addr) |
137 | { | 173 | { |
138 | struct nfit_test_resource *nfit_res; | 174 | struct nfit_test_resource *nfit_res = get_nfit_res((long) addr); |
139 | |||
140 | rcu_read_lock(); | ||
141 | nfit_res = get_nfit_res((unsigned long) addr); | ||
142 | rcu_read_unlock(); | ||
143 | if (nfit_res) | 175 | if (nfit_res) |
144 | return; | 176 | return; |
145 | return iounmap(addr); | 177 | return iounmap(addr); |
@@ -148,11 +180,8 @@ EXPORT_SYMBOL(__wrap_iounmap); | |||
148 | 180 | ||
149 | void __wrap_memunmap(void *addr) | 181 | void __wrap_memunmap(void *addr) |
150 | { | 182 | { |
151 | struct nfit_test_resource *nfit_res; | 183 | struct nfit_test_resource *nfit_res = get_nfit_res((long) addr); |
152 | 184 | ||
153 | rcu_read_lock(); | ||
154 | nfit_res = get_nfit_res((unsigned long) addr); | ||
155 | rcu_read_unlock(); | ||
156 | if (nfit_res) | 185 | if (nfit_res) |
157 | return; | 186 | return; |
158 | return memunmap(addr); | 187 | return memunmap(addr); |
@@ -166,9 +195,7 @@ static struct resource *nfit_test_request_region(struct device *dev, | |||
166 | struct nfit_test_resource *nfit_res; | 195 | struct nfit_test_resource *nfit_res; |
167 | 196 | ||
168 | if (parent == &iomem_resource) { | 197 | if (parent == &iomem_resource) { |
169 | rcu_read_lock(); | ||
170 | nfit_res = get_nfit_res(start); | 198 | nfit_res = get_nfit_res(start); |
171 | rcu_read_unlock(); | ||
172 | if (nfit_res) { | 199 | if (nfit_res) { |
173 | struct resource *res = nfit_res->res + 1; | 200 | struct resource *res = nfit_res->res + 1; |
174 | 201 | ||
@@ -218,9 +245,7 @@ void __wrap___release_region(struct resource *parent, resource_size_t start, | |||
218 | struct nfit_test_resource *nfit_res; | 245 | struct nfit_test_resource *nfit_res; |
219 | 246 | ||
220 | if (parent == &iomem_resource) { | 247 | if (parent == &iomem_resource) { |
221 | rcu_read_lock(); | ||
222 | nfit_res = get_nfit_res(start); | 248 | nfit_res = get_nfit_res(start); |
223 | rcu_read_unlock(); | ||
224 | if (nfit_res) { | 249 | if (nfit_res) { |
225 | struct resource *res = nfit_res->res + 1; | 250 | struct resource *res = nfit_res->res + 1; |
226 | 251 | ||
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 51cf8256c6cd..90bd2ea41032 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -248,6 +248,8 @@ static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd, | |||
248 | 248 | ||
249 | nd_cmd->out_length = 256; | 249 | nd_cmd->out_length = 256; |
250 | nd_cmd->num_records = 0; | 250 | nd_cmd->num_records = 0; |
251 | nd_cmd->address = 0; | ||
252 | nd_cmd->length = -1ULL; | ||
251 | nd_cmd->status = 0; | 253 | nd_cmd->status = 0; |
252 | 254 | ||
253 | return 0; | 255 | return 0; |
@@ -1088,6 +1090,8 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
1088 | struct acpi_nfit_memory_map *memdev; | 1090 | struct acpi_nfit_memory_map *memdev; |
1089 | struct acpi_nfit_control_region *dcr; | 1091 | struct acpi_nfit_control_region *dcr; |
1090 | struct acpi_nfit_system_address *spa; | 1092 | struct acpi_nfit_system_address *spa; |
1093 | struct nvdimm_bus_descriptor *nd_desc; | ||
1094 | struct acpi_nfit_desc *acpi_desc; | ||
1091 | 1095 | ||
1092 | offset = 0; | 1096 | offset = 0; |
1093 | /* spa0 (flat range with no bdw aliasing) */ | 1097 | /* spa0 (flat range with no bdw aliasing) */ |
@@ -1135,6 +1139,13 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
1135 | dcr->command_size = 0; | 1139 | dcr->command_size = 0; |
1136 | dcr->status_offset = 0; | 1140 | dcr->status_offset = 0; |
1137 | dcr->status_size = 0; | 1141 | dcr->status_size = 0; |
1142 | |||
1143 | acpi_desc = &t->acpi_desc; | ||
1144 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); | ||
1145 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); | ||
1146 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); | ||
1147 | nd_desc = &acpi_desc->nd_desc; | ||
1148 | nd_desc->ndctl = nfit_test_ctl; | ||
1138 | } | 1149 | } |
1139 | 1150 | ||
1140 | static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, | 1151 | static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index c8edff6803d1..b04afc3295df 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -1,10 +1,12 @@ | |||
1 | TARGETS = breakpoints | 1 | TARGETS = breakpoints |
2 | TARGETS += capabilities | ||
2 | TARGETS += cpu-hotplug | 3 | TARGETS += cpu-hotplug |
3 | TARGETS += efivarfs | 4 | TARGETS += efivarfs |
4 | TARGETS += exec | 5 | TARGETS += exec |
5 | TARGETS += firmware | 6 | TARGETS += firmware |
6 | TARGETS += ftrace | 7 | TARGETS += ftrace |
7 | TARGETS += futex | 8 | TARGETS += futex |
9 | TARGETS += ipc | ||
8 | TARGETS += kcmp | 10 | TARGETS += kcmp |
9 | TARGETS += lib | 11 | TARGETS += lib |
10 | TARGETS += membarrier | 12 | TARGETS += membarrier |
diff --git a/tools/testing/selftests/breakpoints/.gitignore b/tools/testing/selftests/breakpoints/.gitignore new file mode 100644 index 000000000000..9b3193d06608 --- /dev/null +++ b/tools/testing/selftests/breakpoints/.gitignore | |||
@@ -0,0 +1 @@ | |||
breakpoint_test | |||
diff --git a/tools/testing/selftests/capabilities/Makefile b/tools/testing/selftests/capabilities/Makefile index 8c8f0c1f0889..008602aed920 100644 --- a/tools/testing/selftests/capabilities/Makefile +++ b/tools/testing/selftests/capabilities/Makefile | |||
@@ -1,18 +1,15 @@ | |||
1 | all: | 1 | TEST_FILES := validate_cap |
2 | |||
3 | include ../lib.mk | ||
4 | |||
5 | .PHONY: all clean | ||
6 | |||
7 | TARGETS := validate_cap test_execve | ||
8 | TEST_PROGS := test_execve | 2 | TEST_PROGS := test_execve |
9 | 3 | ||
10 | CFLAGS := -O2 -g -std=gnu99 -Wall -lcap-ng | 4 | BINARIES := $(TEST_FILES) $(TEST_PROGS) |
11 | 5 | ||
12 | all: $(TARGETS) | 6 | CFLAGS += -O2 -g -std=gnu99 -Wall |
7 | LDLIBS += -lcap-ng -lrt -ldl | ||
8 | |||
9 | all: $(BINARIES) | ||
13 | 10 | ||
14 | clean: | 11 | clean: |
15 | $(RM) $(TARGETS) | 12 | $(RM) $(BINARIES) |
13 | |||
14 | include ../lib.mk | ||
16 | 15 | ||
17 | $(TARGETS): %: %.c | ||
18 | $(CC) -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl | ||
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index c4366dc74e01..5c495ad7958a 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh | |||
@@ -48,8 +48,21 @@ echo "ABCD0123" >"$FW" | |||
48 | 48 | ||
49 | NAME=$(basename "$FW") | 49 | NAME=$(basename "$FW") |
50 | 50 | ||
51 | if printf '\000' >"$DIR"/trigger_request; then | ||
52 | echo "$0: empty filename should not succeed" >&2 | ||
53 | exit 1 | ||
54 | fi | ||
55 | |||
56 | if printf '\000' >"$DIR"/trigger_async_request; then | ||
57 | echo "$0: empty filename should not succeed (async)" >&2 | ||
58 | exit 1 | ||
59 | fi | ||
60 | |||
51 | # Request a firmware that doesn't exist, it should fail. | 61 | # Request a firmware that doesn't exist, it should fail. |
52 | echo -n "nope-$NAME" >"$DIR"/trigger_request | 62 | if echo -n "nope-$NAME" >"$DIR"/trigger_request; then |
63 | echo "$0: firmware shouldn't have loaded" >&2 | ||
64 | exit 1 | ||
65 | fi | ||
53 | if diff -q "$FW" /dev/test_firmware >/dev/null ; then | 66 | if diff -q "$FW" /dev/test_firmware >/dev/null ; then |
54 | echo "$0: firmware was not expected to match" >&2 | 67 | echo "$0: firmware was not expected to match" >&2 |
55 | exit 1 | 68 | exit 1 |
@@ -74,4 +87,18 @@ else | |||
74 | echo "$0: filesystem loading works" | 87 | echo "$0: filesystem loading works" |
75 | fi | 88 | fi |
76 | 89 | ||
90 | # Try the asynchronous version too | ||
91 | if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then | ||
92 | echo "$0: could not trigger async request" >&2 | ||
93 | exit 1 | ||
94 | fi | ||
95 | |||
96 | # Verify the contents are what we expect. | ||
97 | if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then | ||
98 | echo "$0: firmware was not loaded (async)" >&2 | ||
99 | exit 1 | ||
100 | else | ||
101 | echo "$0: async filesystem loading works" | ||
102 | fi | ||
103 | |||
77 | exit 0 | 104 | exit 0 |
diff --git a/tools/testing/selftests/intel_pstate/Makefile b/tools/testing/selftests/intel_pstate/Makefile new file mode 100644 index 000000000000..f5f1a28715ff --- /dev/null +++ b/tools/testing/selftests/intel_pstate/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | CC := $(CROSS_COMPILE)gcc | ||
2 | CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE | ||
3 | LDFLAGS := $(LDFLAGS) -lm | ||
4 | |||
5 | TARGETS := msr aperf | ||
6 | |||
7 | TEST_PROGS := $(TARGETS) run.sh | ||
8 | |||
9 | .PHONY: all clean | ||
10 | all: $(TARGETS) | ||
11 | |||
12 | $(TARGETS): $(HEADERS) | ||
13 | |||
14 | clean: | ||
15 | rm -f $(TARGETS) | ||
diff --git a/tools/testing/selftests/intel_pstate/aperf.c b/tools/testing/selftests/intel_pstate/aperf.c new file mode 100644 index 000000000000..6046e183f4ad --- /dev/null +++ b/tools/testing/selftests/intel_pstate/aperf.c | |||
@@ -0,0 +1,80 @@ | |||
1 | #include <math.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <sys/types.h> | ||
6 | #include <sys/stat.h> | ||
7 | #include <fcntl.h> | ||
8 | #include <sys/timeb.h> | ||
9 | #include <sched.h> | ||
10 | #include <errno.h> | ||
11 | |||
12 | void usage(char *name) { | ||
13 | printf ("Usage: %s cpunum\n", name); | ||
14 | } | ||
15 | |||
16 | int main(int argc, char **argv) { | ||
17 | int i, cpu, fd; | ||
18 | char msr_file_name[64]; | ||
19 | long long tsc, old_tsc, new_tsc; | ||
20 | long long aperf, old_aperf, new_aperf; | ||
21 | long long mperf, old_mperf, new_mperf; | ||
22 | struct timeb before, after; | ||
23 | long long int start, finish, total; | ||
24 | cpu_set_t cpuset; | ||
25 | |||
26 | if (argc != 2) { | ||
27 | usage(argv[0]); | ||
28 | return 1; | ||
29 | } | ||
30 | |||
31 | errno = 0; | ||
32 | cpu = strtol(argv[1], (char **) NULL, 10); | ||
33 | |||
34 | if (errno) { | ||
35 | usage(argv[0]); | ||
36 | return 1; | ||
37 | } | ||
38 | |||
39 | sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu); | ||
40 | fd = open(msr_file_name, O_RDONLY); | ||
41 | |||
42 | if (fd == -1) { | ||
43 | perror("Failed to open"); | ||
44 | return 1; | ||
45 | } | ||
46 | |||
47 | CPU_ZERO(&cpuset); | ||
48 | CPU_SET(cpu, &cpuset); | ||
49 | |||
50 | if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset)) { | ||
51 | perror("Failed to set cpu affinity"); | ||
52 | return 1; | ||
53 | } | ||
54 | |||
55 | ftime(&before); | ||
56 | pread(fd, &old_tsc, sizeof(old_tsc), 0x10); | ||
57 | pread(fd, &old_aperf, sizeof(old_mperf), 0xe7); | ||
58 | pread(fd, &old_mperf, sizeof(old_aperf), 0xe8); | ||
59 | |||
60 | for (i=0; i<0x8fffffff; i++) { | ||
61 | sqrt(i); | ||
62 | } | ||
63 | |||
64 | ftime(&after); | ||
65 | pread(fd, &new_tsc, sizeof(new_tsc), 0x10); | ||
66 | pread(fd, &new_aperf, sizeof(new_mperf), 0xe7); | ||
67 | pread(fd, &new_mperf, sizeof(new_aperf), 0xe8); | ||
68 | |||
69 | tsc = new_tsc-old_tsc; | ||
70 | aperf = new_aperf-old_aperf; | ||
71 | mperf = new_mperf-old_mperf; | ||
72 | |||
73 | start = before.time*1000 + before.millitm; | ||
74 | finish = after.time*1000 + after.millitm; | ||
75 | total = finish - start; | ||
76 | |||
77 | printf("runTime: %4.2f\n", 1.0*total/1000); | ||
78 | printf("freq: %7.0f\n", tsc / (1.0*aperf / (1.0 * mperf)) / total); | ||
79 | return 0; | ||
80 | } | ||
diff --git a/tools/testing/selftests/intel_pstate/msr.c b/tools/testing/selftests/intel_pstate/msr.c new file mode 100644 index 000000000000..abbbfc84d359 --- /dev/null +++ b/tools/testing/selftests/intel_pstate/msr.c | |||
@@ -0,0 +1,39 @@ | |||
1 | #include <math.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <sys/types.h> | ||
6 | #include <sys/stat.h> | ||
7 | #include <fcntl.h> | ||
8 | #include <sys/timeb.h> | ||
9 | #include <sched.h> | ||
10 | #include <errno.h> | ||
11 | |||
12 | |||
13 | int main(int argc, char **argv) { | ||
14 | int cpu, fd; | ||
15 | long long msr; | ||
16 | char msr_file_name[64]; | ||
17 | |||
18 | if (argc != 2) | ||
19 | return 1; | ||
20 | |||
21 | errno = 0; | ||
22 | cpu = strtol(argv[1], (char **) NULL, 10); | ||
23 | |||
24 | if (errno) | ||
25 | return 1; | ||
26 | |||
27 | sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu); | ||
28 | fd = open(msr_file_name, O_RDONLY); | ||
29 | |||
30 | if (fd == -1) { | ||
31 | perror("Failed to open"); | ||
32 | return 1; | ||
33 | } | ||
34 | |||
35 | pread(fd, &msr, sizeof(msr), 0x199); | ||
36 | |||
37 | printf("msr 0x199: 0x%llx\n", msr); | ||
38 | return 0; | ||
39 | } | ||
diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh new file mode 100755 index 000000000000..bdaf37e92684 --- /dev/null +++ b/tools/testing/selftests/intel_pstate/run.sh | |||
@@ -0,0 +1,113 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # This test runs on Intel x86 based hardware which support the intel_pstate | ||
4 | # driver. The test checks the frequency settings from the maximum turbo | ||
5 | # state to the minimum supported frequency, in decrements of 100MHz. The | ||
6 | # test runs the aperf.c program to put load on each processor. | ||
7 | # | ||
8 | # The results are displayed in a table which indicate the "Target" state, | ||
9 | # or the requested frequency in MHz, the Actual frequency, as read from | ||
10 | # /proc/cpuinfo, the difference between the Target and Actual frequencies, | ||
11 | # and the value of MSR 0x199 (MSR_IA32_PERF_CTL) which indicates what | ||
12 | # pstate the cpu is in, and the value of | ||
13 | # /sys/devices/system/cpu/intel_pstate/max_perf_pct X maximum turbo state | ||
14 | # | ||
15 | # Notes: In some cases several frequency values may be placed in the | ||
16 | # /tmp/result.X files. This is done on purpose in order to catch cases | ||
17 | # where the pstate driver may not be working at all. There is the case | ||
18 | # where, for example, several "similar" frequencies are in the file: | ||
19 | # | ||
20 | # | ||
21 | #/tmp/result.3100:1:cpu MHz : 2899.980 | ||
22 | #/tmp/result.3100:2:cpu MHz : 2900.000 | ||
23 | #/tmp/result.3100:3:msr 0x199: 0x1e00 | ||
24 | #/tmp/result.3100:4:max_perf_pct 94 | ||
25 | # | ||
26 | # and the test will error out in those cases. The result.X file can be checked | ||
27 | # for consistency and modified to remove the extra MHz values. The result.X | ||
28 | # files can be re-evaluated by setting EVALUATE_ONLY to 1 below. | ||
29 | |||
30 | EVALUATE_ONLY=0 | ||
31 | |||
32 | max_cpus=$(($(nproc)-1)) | ||
33 | |||
34 | # compile programs | ||
35 | gcc -o aperf aperf.c -lm | ||
36 | [ $? -ne 0 ] && echo "Problem compiling aperf.c." && exit 1 | ||
37 | gcc -o msr msr.c -lm | ||
38 | [ $? -ne 0 ] && echo "Problem compiling msr.c." && exit 1 | ||
39 | |||
40 | function run_test () { | ||
41 | |||
42 | file_ext=$1 | ||
43 | for cpu in `seq 0 $max_cpus` | ||
44 | do | ||
45 | echo "launching aperf load on $cpu" | ||
46 | ./aperf $cpu & | ||
47 | done | ||
48 | |||
49 | echo "sleeping for 5 seconds" | ||
50 | sleep 5 | ||
51 | num_freqs=$(cat /proc/cpuinfo | grep MHz | sort -u | wc -l) | ||
52 | if [ $num_freqs -le 2 ]; then | ||
53 | cat /proc/cpuinfo | grep MHz | sort -u | tail -1 > /tmp/result.$1 | ||
54 | else | ||
55 | cat /proc/cpuinfo | grep MHz | sort -u > /tmp/result.$1 | ||
56 | fi | ||
57 | ./msr 0 >> /tmp/result.$1 | ||
58 | |||
59 | max_perf_pct=$(cat /sys/devices/system/cpu/intel_pstate/max_perf_pct) | ||
60 | echo "max_perf_pct $max_perf_pct" >> /tmp/result.$1 | ||
61 | |||
62 | for job in `jobs -p` | ||
63 | do | ||
64 | echo "waiting for job id $job" | ||
65 | wait $job | ||
66 | done | ||
67 | } | ||
68 | |||
69 | # | ||
70 | # MAIN (ALL UNITS IN MHZ) | ||
71 | # | ||
72 | |||
73 | # Get the marketing frequency | ||
74 | _mkt_freq=$(cat /proc/cpuinfo | grep -m 1 "model name" | awk '{print $NF}') | ||
75 | _mkt_freq=$(echo $_mkt_freq | tr -d [:alpha:][:punct:]) | ||
76 | mkt_freq=${_mkt_freq}0 | ||
77 | |||
78 | # Get the ranges from cpupower | ||
79 | _min_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $1 } ') | ||
80 | min_freq=$(($_min_freq / 1000)) | ||
81 | _max_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $2 } ') | ||
82 | max_freq=$(($_max_freq / 1000)) | ||
83 | |||
84 | |||
85 | for freq in `seq $max_freq -100 $min_freq` | ||
86 | do | ||
87 | echo "Setting maximum frequency to $freq" | ||
88 | cpupower frequency-set -g powersave --max=${freq}MHz >& /dev/null | ||
89 | [ $EVALUATE_ONLY -eq 0 ] && run_test $freq | ||
90 | done | ||
91 | |||
92 | echo "==============================================================================" | ||
93 | |||
94 | echo "The marketing frequency of the cpu is $mkt_freq MHz" | ||
95 | echo "The maximum frequency of the cpu is $max_freq MHz" | ||
96 | echo "The minimum frequency of the cpu is $min_freq MHz" | ||
97 | |||
98 | cpupower frequency-set -g powersave --max=${max_freq}MHz >& /dev/null | ||
99 | |||
100 | # make a pretty table | ||
101 | echo "Target Actual Difference MSR(0x199) max_perf_pct" | ||
102 | for freq in `seq $max_freq -100 $min_freq` | ||
103 | do | ||
104 | result_freq=$(cat /tmp/result.${freq} | grep "cpu MHz" | awk ' { print $4 } ' | awk -F "." ' { print $1 } ') | ||
105 | msr=$(cat /tmp/result.${freq} | grep "msr" | awk ' { print $3 } ') | ||
106 | max_perf_pct=$(cat /tmp/result.${freq} | grep "max_perf_pct" | awk ' { print $2 } ' ) | ||
107 | if [ $result_freq -eq $freq ]; then | ||
108 | echo " $freq $result_freq 0 $msr $(($max_perf_pct*3300))" | ||
109 | else | ||
110 | echo " $freq $result_freq $(($result_freq-$freq)) $msr $(($max_perf_pct*$max_freq))" | ||
111 | fi | ||
112 | done | ||
113 | exit 0 | ||
diff --git a/tools/testing/selftests/powerpc/benchmarks/.gitignore b/tools/testing/selftests/powerpc/benchmarks/.gitignore index b4709ea588c1..6fa673316ac2 100644 --- a/tools/testing/selftests/powerpc/benchmarks/.gitignore +++ b/tools/testing/selftests/powerpc/benchmarks/.gitignore | |||
@@ -1 +1,2 @@ | |||
1 | gettimeofday | 1 | gettimeofday |
2 | context_switch | ||
diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile index 5fa48702070d..912445ff7ce7 100644 --- a/tools/testing/selftests/powerpc/benchmarks/Makefile +++ b/tools/testing/selftests/powerpc/benchmarks/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | TEST_PROGS := gettimeofday | 1 | TEST_PROGS := gettimeofday context_switch |
2 | 2 | ||
3 | CFLAGS += -O2 | 3 | CFLAGS += -O2 |
4 | 4 | ||
@@ -6,6 +6,9 @@ all: $(TEST_PROGS) | |||
6 | 6 | ||
7 | $(TEST_PROGS): ../harness.c | 7 | $(TEST_PROGS): ../harness.c |
8 | 8 | ||
9 | context_switch: ../utils.c | ||
10 | context_switch: LDLIBS += -lpthread | ||
11 | |||
9 | include ../../lib.mk | 12 | include ../../lib.mk |
10 | 13 | ||
11 | clean: | 14 | clean: |
diff --git a/tools/testing/selftests/powerpc/benchmarks/context_switch.c b/tools/testing/selftests/powerpc/benchmarks/context_switch.c new file mode 100644 index 000000000000..7b785941adec --- /dev/null +++ b/tools/testing/selftests/powerpc/benchmarks/context_switch.c | |||
@@ -0,0 +1,466 @@ | |||
1 | /* | ||
2 | * Context switch microbenchmark. | ||
3 | * | ||
4 | * Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <sched.h> | ||
14 | #include <string.h> | ||
15 | #include <stdio.h> | ||
16 | #include <unistd.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <getopt.h> | ||
19 | #include <signal.h> | ||
20 | #include <assert.h> | ||
21 | #include <pthread.h> | ||
22 | #include <limits.h> | ||
23 | #include <sys/time.h> | ||
24 | #include <sys/syscall.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <sys/shm.h> | ||
27 | #include <linux/futex.h> | ||
28 | |||
29 | #include "../utils.h" | ||
30 | |||
31 | static unsigned int timeout = 30; | ||
32 | |||
33 | static int touch_vdso; | ||
34 | struct timeval tv; | ||
35 | |||
36 | static int touch_fp = 1; | ||
37 | double fp; | ||
38 | |||
39 | static int touch_vector = 1; | ||
40 | typedef int v4si __attribute__ ((vector_size (16))); | ||
41 | v4si a, b, c; | ||
42 | |||
43 | #ifdef __powerpc__ | ||
44 | static int touch_altivec = 1; | ||
45 | |||
46 | static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void) | ||
47 | { | ||
48 | c = a + b; | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | static void touch(void) | ||
53 | { | ||
54 | if (touch_vdso) | ||
55 | gettimeofday(&tv, NULL); | ||
56 | |||
57 | if (touch_fp) | ||
58 | fp += 0.1; | ||
59 | |||
60 | #ifdef __powerpc__ | ||
61 | if (touch_altivec) | ||
62 | altivec_touch_fn(); | ||
63 | #endif | ||
64 | |||
65 | if (touch_vector) | ||
66 | c = a + b; | ||
67 | |||
68 | asm volatile("# %0 %1 %2": : "r"(&tv), "r"(&fp), "r"(&c)); | ||
69 | } | ||
70 | |||
71 | static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu) | ||
72 | { | ||
73 | pthread_t tid; | ||
74 | cpu_set_t cpuset; | ||
75 | pthread_attr_t attr; | ||
76 | |||
77 | CPU_ZERO(&cpuset); | ||
78 | CPU_SET(cpu, &cpuset); | ||
79 | |||
80 | pthread_attr_init(&attr); | ||
81 | |||
82 | if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset)) { | ||
83 | perror("pthread_attr_setaffinity_np"); | ||
84 | exit(1); | ||
85 | } | ||
86 | |||
87 | if (pthread_create(&tid, &attr, fn, arg)) { | ||
88 | perror("pthread_create"); | ||
89 | exit(1); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static void start_process_on(void *(*fn)(void *), void *arg, unsigned long cpu) | ||
94 | { | ||
95 | int pid; | ||
96 | cpu_set_t cpuset; | ||
97 | |||
98 | pid = fork(); | ||
99 | if (pid == -1) { | ||
100 | perror("fork"); | ||
101 | exit(1); | ||
102 | } | ||
103 | |||
104 | if (pid) | ||
105 | return; | ||
106 | |||
107 | CPU_ZERO(&cpuset); | ||
108 | CPU_SET(cpu, &cpuset); | ||
109 | |||
110 | if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) { | ||
111 | perror("sched_setaffinity"); | ||
112 | exit(1); | ||
113 | } | ||
114 | |||
115 | fn(arg); | ||
116 | |||
117 | exit(0); | ||
118 | } | ||
119 | |||
120 | static unsigned long iterations; | ||
121 | static unsigned long iterations_prev; | ||
122 | |||
123 | static void sigalrm_handler(int junk) | ||
124 | { | ||
125 | unsigned long i = iterations; | ||
126 | |||
127 | printf("%ld\n", i - iterations_prev); | ||
128 | iterations_prev = i; | ||
129 | |||
130 | if (--timeout == 0) | ||
131 | kill(0, SIGUSR1); | ||
132 | |||
133 | alarm(1); | ||
134 | } | ||
135 | |||
136 | static void sigusr1_handler(int junk) | ||
137 | { | ||
138 | exit(0); | ||
139 | } | ||
140 | |||
141 | struct actions { | ||
142 | void (*setup)(int, int); | ||
143 | void *(*thread1)(void *); | ||
144 | void *(*thread2)(void *); | ||
145 | }; | ||
146 | |||
147 | #define READ 0 | ||
148 | #define WRITE 1 | ||
149 | |||
150 | static int pipe_fd1[2]; | ||
151 | static int pipe_fd2[2]; | ||
152 | |||
153 | static void pipe_setup(int cpu1, int cpu2) | ||
154 | { | ||
155 | if (pipe(pipe_fd1) || pipe(pipe_fd2)) | ||
156 | exit(1); | ||
157 | } | ||
158 | |||
159 | static void *pipe_thread1(void *arg) | ||
160 | { | ||
161 | signal(SIGALRM, sigalrm_handler); | ||
162 | alarm(1); | ||
163 | |||
164 | while (1) { | ||
165 | assert(read(pipe_fd1[READ], &c, 1) == 1); | ||
166 | touch(); | ||
167 | |||
168 | assert(write(pipe_fd2[WRITE], &c, 1) == 1); | ||
169 | touch(); | ||
170 | |||
171 | iterations += 2; | ||
172 | } | ||
173 | |||
174 | return NULL; | ||
175 | } | ||
176 | |||
177 | static void *pipe_thread2(void *arg) | ||
178 | { | ||
179 | while (1) { | ||
180 | assert(write(pipe_fd1[WRITE], &c, 1) == 1); | ||
181 | touch(); | ||
182 | |||
183 | assert(read(pipe_fd2[READ], &c, 1) == 1); | ||
184 | touch(); | ||
185 | } | ||
186 | |||
187 | return NULL; | ||
188 | } | ||
189 | |||
190 | static struct actions pipe_actions = { | ||
191 | .setup = pipe_setup, | ||
192 | .thread1 = pipe_thread1, | ||
193 | .thread2 = pipe_thread2, | ||
194 | }; | ||
195 | |||
196 | static void yield_setup(int cpu1, int cpu2) | ||
197 | { | ||
198 | if (cpu1 != cpu2) { | ||
199 | fprintf(stderr, "Both threads must be on the same CPU for yield test\n"); | ||
200 | exit(1); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | static void *yield_thread1(void *arg) | ||
205 | { | ||
206 | signal(SIGALRM, sigalrm_handler); | ||
207 | alarm(1); | ||
208 | |||
209 | while (1) { | ||
210 | sched_yield(); | ||
211 | touch(); | ||
212 | |||
213 | iterations += 2; | ||
214 | } | ||
215 | |||
216 | return NULL; | ||
217 | } | ||
218 | |||
219 | static void *yield_thread2(void *arg) | ||
220 | { | ||
221 | while (1) { | ||
222 | sched_yield(); | ||
223 | touch(); | ||
224 | } | ||
225 | |||
226 | return NULL; | ||
227 | } | ||
228 | |||
229 | static struct actions yield_actions = { | ||
230 | .setup = yield_setup, | ||
231 | .thread1 = yield_thread1, | ||
232 | .thread2 = yield_thread2, | ||
233 | }; | ||
234 | |||
235 | static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout, | ||
236 | void *addr2, int val3) | ||
237 | { | ||
238 | return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); | ||
239 | } | ||
240 | |||
241 | static unsigned long cmpxchg(unsigned long *p, unsigned long expected, | ||
242 | unsigned long desired) | ||
243 | { | ||
244 | unsigned long exp = expected; | ||
245 | |||
246 | __atomic_compare_exchange_n(p, &exp, desired, 0, | ||
247 | __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); | ||
248 | return exp; | ||
249 | } | ||
250 | |||
251 | static unsigned long xchg(unsigned long *p, unsigned long val) | ||
252 | { | ||
253 | return __atomic_exchange_n(p, val, __ATOMIC_SEQ_CST); | ||
254 | } | ||
255 | |||
256 | static int mutex_lock(unsigned long *m) | ||
257 | { | ||
258 | int c; | ||
259 | |||
260 | c = cmpxchg(m, 0, 1); | ||
261 | if (!c) | ||
262 | return 0; | ||
263 | |||
264 | if (c == 1) | ||
265 | c = xchg(m, 2); | ||
266 | |||
267 | while (c) { | ||
268 | sys_futex(m, FUTEX_WAIT, 2, NULL, NULL, 0); | ||
269 | c = xchg(m, 2); | ||
270 | } | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int mutex_unlock(unsigned long *m) | ||
276 | { | ||
277 | if (*m == 2) | ||
278 | *m = 0; | ||
279 | else if (xchg(m, 0) == 1) | ||
280 | return 0; | ||
281 | |||
282 | sys_futex(m, FUTEX_WAKE, 1, NULL, NULL, 0); | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static unsigned long *m1, *m2; | ||
288 | |||
289 | static void futex_setup(int cpu1, int cpu2) | ||
290 | { | ||
291 | int shmid; | ||
292 | void *shmaddr; | ||
293 | |||
294 | shmid = shmget(IPC_PRIVATE, getpagesize(), SHM_R | SHM_W); | ||
295 | if (shmid < 0) { | ||
296 | perror("shmget"); | ||
297 | exit(1); | ||
298 | } | ||
299 | |||
300 | shmaddr = shmat(shmid, NULL, 0); | ||
301 | if (shmaddr == (char *)-1) { | ||
302 | perror("shmat"); | ||
303 | shmctl(shmid, IPC_RMID, NULL); | ||
304 | exit(1); | ||
305 | } | ||
306 | |||
307 | shmctl(shmid, IPC_RMID, NULL); | ||
308 | |||
309 | m1 = shmaddr; | ||
310 | m2 = shmaddr + sizeof(*m1); | ||
311 | |||
312 | *m1 = 0; | ||
313 | *m2 = 0; | ||
314 | |||
315 | mutex_lock(m1); | ||
316 | mutex_lock(m2); | ||
317 | } | ||
318 | |||
319 | static void *futex_thread1(void *arg) | ||
320 | { | ||
321 | signal(SIGALRM, sigalrm_handler); | ||
322 | alarm(1); | ||
323 | |||
324 | while (1) { | ||
325 | mutex_lock(m2); | ||
326 | mutex_unlock(m1); | ||
327 | |||
328 | iterations += 2; | ||
329 | } | ||
330 | |||
331 | return NULL; | ||
332 | } | ||
333 | |||
334 | static void *futex_thread2(void *arg) | ||
335 | { | ||
336 | while (1) { | ||
337 | mutex_unlock(m2); | ||
338 | mutex_lock(m1); | ||
339 | } | ||
340 | |||
341 | return NULL; | ||
342 | } | ||
343 | |||
344 | static struct actions futex_actions = { | ||
345 | .setup = futex_setup, | ||
346 | .thread1 = futex_thread1, | ||
347 | .thread2 = futex_thread2, | ||
348 | }; | ||
349 | |||
350 | static int processes; | ||
351 | |||
352 | static struct option options[] = { | ||
353 | { "test", required_argument, 0, 't' }, | ||
354 | { "process", no_argument, &processes, 1 }, | ||
355 | { "timeout", required_argument, 0, 's' }, | ||
356 | { "vdso", no_argument, &touch_vdso, 1 }, | ||
357 | { "no-fp", no_argument, &touch_fp, 0 }, | ||
358 | #ifdef __powerpc__ | ||
359 | { "no-altivec", no_argument, &touch_altivec, 0 }, | ||
360 | #endif | ||
361 | { "no-vector", no_argument, &touch_vector, 0 }, | ||
362 | { 0, }, | ||
363 | }; | ||
364 | |||
365 | static void usage(void) | ||
366 | { | ||
367 | fprintf(stderr, "Usage: context_switch2 <options> CPU1 CPU2\n\n"); | ||
368 | fprintf(stderr, "\t\t--test=X\tpipe, futex or yield (default)\n"); | ||
369 | fprintf(stderr, "\t\t--process\tUse processes (default threads)\n"); | ||
370 | fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n"); | ||
371 | fprintf(stderr, "\t\t--vdso\t\ttouch VDSO\n"); | ||
372 | fprintf(stderr, "\t\t--fp\t\ttouch FP\n"); | ||
373 | #ifdef __powerpc__ | ||
374 | fprintf(stderr, "\t\t--altivec\ttouch altivec\n"); | ||
375 | #endif | ||
376 | fprintf(stderr, "\t\t--vector\ttouch vector\n"); | ||
377 | } | ||
378 | |||
379 | int main(int argc, char *argv[]) | ||
380 | { | ||
381 | signed char c; | ||
382 | struct actions *actions = &yield_actions; | ||
383 | int cpu1; | ||
384 | int cpu2; | ||
385 | static void (*start_fn)(void *(*fn)(void *), void *arg, unsigned long cpu); | ||
386 | |||
387 | while (1) { | ||
388 | int option_index = 0; | ||
389 | |||
390 | c = getopt_long(argc, argv, "", options, &option_index); | ||
391 | |||
392 | if (c == -1) | ||
393 | break; | ||
394 | |||
395 | switch (c) { | ||
396 | case 0: | ||
397 | if (options[option_index].flag != 0) | ||
398 | break; | ||
399 | |||
400 | usage(); | ||
401 | exit(1); | ||
402 | break; | ||
403 | |||
404 | case 't': | ||
405 | if (!strcmp(optarg, "pipe")) { | ||
406 | actions = &pipe_actions; | ||
407 | } else if (!strcmp(optarg, "yield")) { | ||
408 | actions = &yield_actions; | ||
409 | } else if (!strcmp(optarg, "futex")) { | ||
410 | actions = &futex_actions; | ||
411 | } else { | ||
412 | usage(); | ||
413 | exit(1); | ||
414 | } | ||
415 | break; | ||
416 | |||
417 | case 's': | ||
418 | timeout = atoi(optarg); | ||
419 | break; | ||
420 | |||
421 | default: | ||
422 | usage(); | ||
423 | exit(1); | ||
424 | } | ||
425 | } | ||
426 | |||
427 | if (processes) | ||
428 | start_fn = start_process_on; | ||
429 | else | ||
430 | start_fn = start_thread_on; | ||
431 | |||
432 | if (((argc - optind) != 2)) { | ||
433 | cpu1 = cpu2 = pick_online_cpu(); | ||
434 | } else { | ||
435 | cpu1 = atoi(argv[optind++]); | ||
436 | cpu2 = atoi(argv[optind++]); | ||
437 | } | ||
438 | |||
439 | printf("Using %s with ", processes ? "processes" : "threads"); | ||
440 | |||
441 | if (actions == &pipe_actions) | ||
442 | printf("pipe"); | ||
443 | else if (actions == &yield_actions) | ||
444 | printf("yield"); | ||
445 | else | ||
446 | printf("futex"); | ||
447 | |||
448 | printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n", | ||
449 | cpu1, cpu2, touch_fp ? "yes" : "no", touch_altivec ? "yes" : "no", | ||
450 | touch_vector ? "yes" : "no", touch_vdso ? "yes" : "no"); | ||
451 | |||
452 | /* Create a new process group so we can signal everyone for exit */ | ||
453 | setpgid(getpid(), getpid()); | ||
454 | |||
455 | signal(SIGUSR1, sigusr1_handler); | ||
456 | |||
457 | actions->setup(cpu1, cpu2); | ||
458 | |||
459 | start_fn(actions->thread1, NULL, cpu1); | ||
460 | start_fn(actions->thread2, NULL, cpu2); | ||
461 | |||
462 | while (1) | ||
463 | sleep(3600); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c index 8265504de571..08a8b95e3bc1 100644 --- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c +++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c | |||
@@ -60,14 +60,6 @@ int dscr_inherit_exec(void) | |||
60 | else | 60 | else |
61 | set_dscr(dscr); | 61 | set_dscr(dscr); |
62 | 62 | ||
63 | /* | ||
64 | * XXX: Force a context switch out so that DSCR | ||
65 | * current value is copied into the thread struct | ||
66 | * which is required for the child to inherit the | ||
67 | * changed value. | ||
68 | */ | ||
69 | sleep(1); | ||
70 | |||
71 | pid = fork(); | 63 | pid = fork(); |
72 | if (pid == -1) { | 64 | if (pid == -1) { |
73 | perror("fork() failed"); | 65 | perror("fork() failed"); |
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c index 4e414caf7f40..3e5a6d195e9a 100644 --- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c +++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c | |||
@@ -40,14 +40,6 @@ int dscr_inherit(void) | |||
40 | else | 40 | else |
41 | set_dscr(dscr); | 41 | set_dscr(dscr); |
42 | 42 | ||
43 | /* | ||
44 | * XXX: Force a context switch out so that DSCR | ||
45 | * current value is copied into the thread struct | ||
46 | * which is required for the child to inherit the | ||
47 | * changed value. | ||
48 | */ | ||
49 | sleep(1); | ||
50 | |||
51 | pid = fork(); | 43 | pid = fork(); |
52 | if (pid == -1) { | 44 | if (pid == -1) { |
53 | perror("fork() failed"); | 45 | perror("fork() failed"); |
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c index f7997affd143..52f9be7f61f0 100644 --- a/tools/testing/selftests/powerpc/harness.c +++ b/tools/testing/selftests/powerpc/harness.c | |||
@@ -116,46 +116,3 @@ int test_harness(int (test_function)(void), char *name) | |||
116 | 116 | ||
117 | return rc; | 117 | return rc; |
118 | } | 118 | } |
119 | |||
120 | static char auxv[4096]; | ||
121 | |||
122 | void *get_auxv_entry(int type) | ||
123 | { | ||
124 | ElfW(auxv_t) *p; | ||
125 | void *result; | ||
126 | ssize_t num; | ||
127 | int fd; | ||
128 | |||
129 | fd = open("/proc/self/auxv", O_RDONLY); | ||
130 | if (fd == -1) { | ||
131 | perror("open"); | ||
132 | return NULL; | ||
133 | } | ||
134 | |||
135 | result = NULL; | ||
136 | |||
137 | num = read(fd, auxv, sizeof(auxv)); | ||
138 | if (num < 0) { | ||
139 | perror("read"); | ||
140 | goto out; | ||
141 | } | ||
142 | |||
143 | if (num > sizeof(auxv)) { | ||
144 | printf("Overflowed auxv buffer\n"); | ||
145 | goto out; | ||
146 | } | ||
147 | |||
148 | p = (ElfW(auxv_t) *)auxv; | ||
149 | |||
150 | while (p->a_type != AT_NULL) { | ||
151 | if (p->a_type == type) { | ||
152 | result = (void *)p->a_un.a_val; | ||
153 | break; | ||
154 | } | ||
155 | |||
156 | p++; | ||
157 | } | ||
158 | out: | ||
159 | close(fd); | ||
160 | return result; | ||
161 | } | ||
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile index a9099d9f8f39..ac41a7177f2e 100644 --- a/tools/testing/selftests/powerpc/pmu/Makefile +++ b/tools/testing/selftests/powerpc/pmu/Makefile | |||
@@ -2,7 +2,7 @@ noarg: | |||
2 | $(MAKE) -C ../ | 2 | $(MAKE) -C ../ |
3 | 3 | ||
4 | TEST_PROGS := count_instructions l3_bank_test per_event_excludes | 4 | TEST_PROGS := count_instructions l3_bank_test per_event_excludes |
5 | EXTRA_SOURCES := ../harness.c event.c lib.c | 5 | EXTRA_SOURCES := ../harness.c event.c lib.c ../utils.c |
6 | 6 | ||
7 | all: $(TEST_PROGS) ebb | 7 | all: $(TEST_PROGS) ebb |
8 | 8 | ||
@@ -12,6 +12,8 @@ $(TEST_PROGS): $(EXTRA_SOURCES) | |||
12 | count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES) | 12 | count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES) |
13 | $(CC) $(CFLAGS) -m64 -o $@ $^ | 13 | $(CC) $(CFLAGS) -m64 -o $@ $^ |
14 | 14 | ||
15 | per_event_excludes: ../utils.c | ||
16 | |||
15 | include ../../lib.mk | 17 | include ../../lib.mk |
16 | 18 | ||
17 | DEFAULT_RUN_TESTS := $(RUN_TESTS) | 19 | DEFAULT_RUN_TESTS := $(RUN_TESTS) |
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile index 5cdc9dbf2b27..8d2279c4bb4b 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile +++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile | |||
@@ -18,7 +18,8 @@ TEST_PROGS := reg_access_test event_attributes_test cycles_test \ | |||
18 | 18 | ||
19 | all: $(TEST_PROGS) | 19 | all: $(TEST_PROGS) |
20 | 20 | ||
21 | $(TEST_PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S | 21 | $(TEST_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c \ |
22 | ebb.c ebb_handler.S trace.c busy_loop.S | ||
22 | 23 | ||
23 | instruction_count_test: ../loop.S | 24 | instruction_count_test: ../loop.S |
24 | 25 | ||
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c index 9729d9f90218..e67452f1bcff 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c +++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <stdlib.h> | 13 | #include <stdlib.h> |
14 | #include <string.h> | 14 | #include <string.h> |
15 | #include <sys/ioctl.h> | 15 | #include <sys/ioctl.h> |
16 | #include <linux/auxvec.h> | ||
17 | 16 | ||
18 | #include "trace.h" | 17 | #include "trace.h" |
19 | #include "reg.h" | 18 | #include "reg.h" |
@@ -324,7 +323,7 @@ bool ebb_is_supported(void) | |||
324 | { | 323 | { |
325 | #ifdef PPC_FEATURE2_EBB | 324 | #ifdef PPC_FEATURE2_EBB |
326 | /* EBB requires at least POWER8 */ | 325 | /* EBB requires at least POWER8 */ |
327 | return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_EBB); | 326 | return have_hwcap2(PPC_FEATURE2_EBB); |
328 | #else | 327 | #else |
329 | return false; | 328 | return false; |
330 | #endif | 329 | #endif |
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c index a07104c2afe6..a361ad3334ce 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.c +++ b/tools/testing/selftests/powerpc/pmu/lib.c | |||
@@ -15,32 +15,6 @@ | |||
15 | #include "lib.h" | 15 | #include "lib.h" |
16 | 16 | ||
17 | 17 | ||
18 | int pick_online_cpu(void) | ||
19 | { | ||
20 | cpu_set_t mask; | ||
21 | int cpu; | ||
22 | |||
23 | CPU_ZERO(&mask); | ||
24 | |||
25 | if (sched_getaffinity(0, sizeof(mask), &mask)) { | ||
26 | perror("sched_getaffinity"); | ||
27 | return -1; | ||
28 | } | ||
29 | |||
30 | /* We prefer a primary thread, but skip 0 */ | ||
31 | for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8) | ||
32 | if (CPU_ISSET(cpu, &mask)) | ||
33 | return cpu; | ||
34 | |||
35 | /* Search for anything, but in reverse */ | ||
36 | for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) | ||
37 | if (CPU_ISSET(cpu, &mask)) | ||
38 | return cpu; | ||
39 | |||
40 | printf("No cpus in affinity mask?!\n"); | ||
41 | return -1; | ||
42 | } | ||
43 | |||
44 | int bind_to_cpu(int cpu) | 18 | int bind_to_cpu(int cpu) |
45 | { | 19 | { |
46 | cpu_set_t mask; | 20 | cpu_set_t mask; |
diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h index ca5d72ae3be6..0213af4ff332 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.h +++ b/tools/testing/selftests/powerpc/pmu/lib.h | |||
@@ -19,7 +19,6 @@ union pipe { | |||
19 | int fds[2]; | 19 | int fds[2]; |
20 | }; | 20 | }; |
21 | 21 | ||
22 | extern int pick_online_cpu(void); | ||
23 | extern int bind_to_cpu(int cpu); | 22 | extern int bind_to_cpu(int cpu); |
24 | extern int kill_child_and_wait(pid_t child_pid); | 23 | extern int kill_child_and_wait(pid_t child_pid); |
25 | extern int wait_for_child(pid_t child_pid); | 24 | extern int wait_for_child(pid_t child_pid); |
diff --git a/tools/testing/selftests/powerpc/scripts/hmi.sh b/tools/testing/selftests/powerpc/scripts/hmi.sh new file mode 100755 index 000000000000..83fb253ae3bd --- /dev/null +++ b/tools/testing/selftests/powerpc/scripts/hmi.sh | |||
@@ -0,0 +1,89 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # Copyright 2015, Daniel Axtens, IBM Corporation | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; version 2 of the License. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | # GNU General Public License for more details. | ||
13 | |||
14 | |||
15 | # do we have ./getscom, ./putscom? | ||
16 | if [ -x ./getscom ] && [ -x ./putscom ]; then | ||
17 | GETSCOM=./getscom | ||
18 | PUTSCOM=./putscom | ||
19 | elif which getscom > /dev/null; then | ||
20 | GETSCOM=$(which getscom) | ||
21 | PUTSCOM=$(which putscom) | ||
22 | else | ||
23 | cat <<EOF | ||
24 | Can't find getscom/putscom in . or \$PATH. | ||
25 | See https://github.com/open-power/skiboot. | ||
26 | The tool is in external/xscom-utils | ||
27 | EOF | ||
28 | exit 1 | ||
29 | fi | ||
30 | |||
31 | # We will get 8 HMI events per injection | ||
32 | # todo: deal with things being offline | ||
33 | expected_hmis=8 | ||
34 | COUNT_HMIS() { | ||
35 | dmesg | grep -c 'Harmless Hypervisor Maintenance interrupt' | ||
36 | } | ||
37 | |||
38 | # massively expand snooze delay, allowing injection on all cores | ||
39 | ppc64_cpu --smt-snooze-delay=1000000000 | ||
40 | |||
41 | # when we exit, restore it | ||
42 | trap "ppc64_cpu --smt-snooze-delay=100" 0 1 | ||
43 | |||
44 | # for each chip+core combination | ||
45 | # todo - less fragile parsing | ||
46 | egrep -o 'OCC: Chip [0-9a-f]+ Core [0-9a-f]' < /sys/firmware/opal/msglog | | ||
47 | while read chipcore; do | ||
48 | chip=$(echo "$chipcore"|awk '{print $3}') | ||
49 | core=$(echo "$chipcore"|awk '{print $5}') | ||
50 | fir="0x1${core}013100" | ||
51 | |||
52 | # verify that Core FIR is zero as expected | ||
53 | if [ "$($GETSCOM -c 0x${chip} $fir)" != 0 ]; then | ||
54 | echo "FIR was not zero before injection for chip $chip, core $core. Aborting!" | ||
55 | echo "Result of $GETSCOM -c 0x${chip} $fir:" | ||
56 | $GETSCOM -c 0x${chip} $fir | ||
57 | echo "If you get a -5 error, the core may be in idle state. Try stress-ng." | ||
58 | echo "Otherwise, try $PUTSCOM -c 0x${chip} $fir 0" | ||
59 | exit 1 | ||
60 | fi | ||
61 | |||
62 | # keep track of the number of HMIs handled | ||
63 | old_hmis=$(COUNT_HMIS) | ||
64 | |||
65 | # do injection, adding a marker to dmesg for clarity | ||
66 | echo "Injecting HMI on core $core, chip $chip" | tee /dev/kmsg | ||
67 | # inject a RegFile recoverable error | ||
68 | if ! $PUTSCOM -c 0x${chip} $fir 2000000000000000 > /dev/null; then | ||
69 | echo "Error injecting. Aborting!" | ||
70 | exit 1 | ||
71 | fi | ||
72 | |||
73 | # now we want to wait for all the HMIs to be processed | ||
74 | # we expect one per thread on the core | ||
75 | i=0; | ||
76 | new_hmis=$(COUNT_HMIS) | ||
77 | while [ $new_hmis -lt $((old_hmis + expected_hmis)) ] && [ $i -lt 12 ]; do | ||
78 | echo "Seen $((new_hmis - old_hmis)) HMI(s) out of $expected_hmis expected, sleeping" | ||
79 | sleep 5; | ||
80 | i=$((i + 1)) | ||
81 | new_hmis=$(COUNT_HMIS) | ||
82 | done | ||
83 | if [ $i = 12 ]; then | ||
84 | echo "Haven't seen expected $expected_hmis recoveries after 1 min. Aborting." | ||
85 | exit 1 | ||
86 | fi | ||
87 | echo "Processed $expected_hmis events; presumed success. Check dmesg." | ||
88 | echo "" | ||
89 | done | ||
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 2699635d2cd9..7d0f14b8cb2e 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore | |||
@@ -1,2 +1,5 @@ | |||
1 | tm-resched-dscr | 1 | tm-resched-dscr |
2 | tm-syscall | 2 | tm-syscall |
3 | tm-signal-msr-resv | ||
4 | tm-signal-stack | ||
5 | tm-vmxcopy | ||
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 4bea62a319dc..737f72c964e6 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile | |||
@@ -1,8 +1,8 @@ | |||
1 | TEST_PROGS := tm-resched-dscr tm-syscall | 1 | TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack tm-vmxcopy |
2 | 2 | ||
3 | all: $(TEST_PROGS) | 3 | all: $(TEST_PROGS) |
4 | 4 | ||
5 | $(TEST_PROGS): ../harness.c | 5 | $(TEST_PROGS): ../harness.c ../utils.c |
6 | 6 | ||
7 | tm-syscall: tm-syscall-asm.S | 7 | tm-syscall: tm-syscall-asm.S |
8 | tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include | 8 | tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include |
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c index 42d4c8caad81..8fde93d6021f 100644 --- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c +++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <asm/tm.h> | 29 | #include <asm/tm.h> |
30 | 30 | ||
31 | #include "utils.h" | 31 | #include "utils.h" |
32 | #include "tm.h" | ||
32 | 33 | ||
33 | #define TBEGIN ".long 0x7C00051D ;" | 34 | #define TBEGIN ".long 0x7C00051D ;" |
34 | #define TEND ".long 0x7C00055D ;" | 35 | #define TEND ".long 0x7C00055D ;" |
@@ -42,6 +43,8 @@ int test_body(void) | |||
42 | { | 43 | { |
43 | uint64_t rv, dscr1 = 1, dscr2, texasr; | 44 | uint64_t rv, dscr1 = 1, dscr2, texasr; |
44 | 45 | ||
46 | SKIP_IF(!have_htm()); | ||
47 | |||
45 | printf("Check DSCR TM context switch: "); | 48 | printf("Check DSCR TM context switch: "); |
46 | fflush(stdout); | 49 | fflush(stdout); |
47 | for (;;) { | 50 | for (;;) { |
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c new file mode 100644 index 000000000000..d86653f282b1 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Michael Neuling, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * | ||
5 | * Test the kernel's signal return code to ensure that it doesn't | ||
6 | * crash when both the transactional and suspend MSR bits are set in | ||
7 | * the signal context. | ||
8 | * | ||
9 | * For this test, we send ourselves a SIGUSR1. In the SIGUSR1 handler | ||
10 | * we modify the signal context to set both MSR TM S and T bits (which | ||
11 | * is "reserved" by the PowerISA). When we return from the signal | ||
12 | * handler (implicit sigreturn), the kernel should detect reserved MSR | ||
13 | * value and send us with a SIGSEGV. | ||
14 | */ | ||
15 | |||
16 | #include <stdlib.h> | ||
17 | #include <stdio.h> | ||
18 | #include <signal.h> | ||
19 | #include <unistd.h> | ||
20 | |||
21 | #include "utils.h" | ||
22 | #include "tm.h" | ||
23 | |||
24 | int segv_expected = 0; | ||
25 | |||
26 | void signal_segv(int signum) | ||
27 | { | ||
28 | if (segv_expected && (signum == SIGSEGV)) | ||
29 | _exit(0); | ||
30 | _exit(1); | ||
31 | } | ||
32 | |||
33 | void signal_usr1(int signum, siginfo_t *info, void *uc) | ||
34 | { | ||
35 | ucontext_t *ucp = uc; | ||
36 | |||
37 | /* Link tm checkpointed context to normal context */ | ||
38 | ucp->uc_link = ucp; | ||
39 | /* Set all TM bits so that the context is now invalid */ | ||
40 | #ifdef __powerpc64__ | ||
41 | ucp->uc_mcontext.gp_regs[PT_MSR] |= (7ULL << 32); | ||
42 | #else | ||
43 | ucp->uc_mcontext.regs->gpr[PT_MSR] |= (7ULL); | ||
44 | #endif | ||
45 | /* Should segv on return becuase of invalid context */ | ||
46 | segv_expected = 1; | ||
47 | } | ||
48 | |||
49 | int tm_signal_msr_resv() | ||
50 | { | ||
51 | struct sigaction act; | ||
52 | |||
53 | SKIP_IF(!have_htm()); | ||
54 | |||
55 | act.sa_sigaction = signal_usr1; | ||
56 | sigemptyset(&act.sa_mask); | ||
57 | act.sa_flags = SA_SIGINFO; | ||
58 | if (sigaction(SIGUSR1, &act, NULL) < 0) { | ||
59 | perror("sigaction sigusr1"); | ||
60 | exit(1); | ||
61 | } | ||
62 | if (signal(SIGSEGV, signal_segv) == SIG_ERR) | ||
63 | exit(1); | ||
64 | |||
65 | raise(SIGUSR1); | ||
66 | |||
67 | /* We shouldn't get here as we exit in the segv handler */ | ||
68 | return 1; | ||
69 | } | ||
70 | |||
71 | int main(void) | ||
72 | { | ||
73 | return test_harness(tm_signal_msr_resv, "tm_signal_msr_resv"); | ||
74 | } | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-stack.c b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c new file mode 100644 index 000000000000..e44a238c1d77 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Michael Neuling, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * | ||
5 | * Test the kernel's signal delievery code to ensure that we don't | ||
6 | * trelaim twice in the kernel signal delivery code. This can happen | ||
7 | * if we trigger a signal when in a transaction and the stack pointer | ||
8 | * is bogus. | ||
9 | * | ||
10 | * This test case registers a SEGV handler, sets the stack pointer | ||
11 | * (r1) to NULL, starts a transaction and then generates a SEGV. The | ||
12 | * SEGV should be handled but we exit here as the stack pointer is | ||
13 | * invalid and hance we can't sigreturn. We only need to check that | ||
14 | * this flow doesn't crash the kernel. | ||
15 | */ | ||
16 | |||
17 | #include <unistd.h> | ||
18 | #include <sys/types.h> | ||
19 | #include <sys/wait.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <stdio.h> | ||
22 | #include <signal.h> | ||
23 | |||
24 | #include "utils.h" | ||
25 | #include "tm.h" | ||
26 | |||
27 | void signal_segv(int signum) | ||
28 | { | ||
29 | /* This should never actually run since stack is foobar */ | ||
30 | exit(1); | ||
31 | } | ||
32 | |||
33 | int tm_signal_stack() | ||
34 | { | ||
35 | int pid; | ||
36 | |||
37 | SKIP_IF(!have_htm()); | ||
38 | |||
39 | pid = fork(); | ||
40 | if (pid < 0) | ||
41 | exit(1); | ||
42 | |||
43 | if (pid) { /* Parent */ | ||
44 | /* | ||
45 | * It's likely the whole machine will crash here so if | ||
46 | * the child ever exits, we are good. | ||
47 | */ | ||
48 | wait(NULL); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * The flow here is: | ||
54 | * 1) register a signal handler (so signal delievery occurs) | ||
55 | * 2) make stack pointer (r1) = NULL | ||
56 | * 3) start transaction | ||
57 | * 4) cause segv | ||
58 | */ | ||
59 | if (signal(SIGSEGV, signal_segv) == SIG_ERR) | ||
60 | exit(1); | ||
61 | asm volatile("li 1, 0 ;" /* stack ptr == NULL */ | ||
62 | "1:" | ||
63 | ".long 0x7C00051D ;" /* tbegin */ | ||
64 | "beq 1b ;" /* retry forever */ | ||
65 | ".long 0x7C0005DD ; ;" /* tsuspend */ | ||
66 | "ld 2, 0(1) ;" /* trigger segv" */ | ||
67 | : : : "memory"); | ||
68 | |||
69 | /* This should never get here due to above segv */ | ||
70 | return 1; | ||
71 | } | ||
72 | |||
73 | int main(void) | ||
74 | { | ||
75 | return test_harness(tm_signal_stack, "tm_signal_stack"); | ||
76 | } | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-syscall.c b/tools/testing/selftests/powerpc/tm/tm-syscall.c index e835bf7ec7ae..60560cb20e38 100644 --- a/tools/testing/selftests/powerpc/tm/tm-syscall.c +++ b/tools/testing/selftests/powerpc/tm/tm-syscall.c | |||
@@ -13,12 +13,11 @@ | |||
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include <sys/syscall.h> | 14 | #include <sys/syscall.h> |
15 | #include <asm/tm.h> | 15 | #include <asm/tm.h> |
16 | #include <asm/cputable.h> | ||
17 | #include <linux/auxvec.h> | ||
18 | #include <sys/time.h> | 16 | #include <sys/time.h> |
19 | #include <stdlib.h> | 17 | #include <stdlib.h> |
20 | 18 | ||
21 | #include "utils.h" | 19 | #include "utils.h" |
20 | #include "tm.h" | ||
22 | 21 | ||
23 | extern int getppid_tm_active(void); | 22 | extern int getppid_tm_active(void); |
24 | extern int getppid_tm_suspended(void); | 23 | extern int getppid_tm_suspended(void); |
@@ -77,16 +76,6 @@ pid_t getppid_tm(bool suspend) | |||
77 | exit(-1); | 76 | exit(-1); |
78 | } | 77 | } |
79 | 78 | ||
80 | static inline bool have_htm_nosc(void) | ||
81 | { | ||
82 | #ifdef PPC_FEATURE2_HTM_NOSC | ||
83 | return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_HTM_NOSC); | ||
84 | #else | ||
85 | printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n"); | ||
86 | return false; | ||
87 | #endif | ||
88 | } | ||
89 | |||
90 | int tm_syscall(void) | 79 | int tm_syscall(void) |
91 | { | 80 | { |
92 | unsigned count = 0; | 81 | unsigned count = 0; |
diff --git a/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c new file mode 100644 index 000000000000..0274de7b11f3 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Michael Neuling, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * | ||
5 | * Original: Michael Neuling 4/12/2013 | ||
6 | * Edited: Rashmica Gupta 4/12/2015 | ||
7 | * | ||
8 | * See if the altivec state is leaked out of an aborted transaction due to | ||
9 | * kernel vmx copy loops. | ||
10 | * | ||
11 | * When the transaction aborts, VSR values should rollback to the values | ||
12 | * they held before the transaction commenced. Using VSRs while transaction | ||
13 | * is suspended should not affect the checkpointed values. | ||
14 | * | ||
15 | * (1) write A to a VSR | ||
16 | * (2) start transaction | ||
17 | * (3) suspend transaction | ||
18 | * (4) change the VSR to B | ||
19 | * (5) trigger kernel vmx copy loop | ||
20 | * (6) abort transaction | ||
21 | * (7) check that the VSR value is A | ||
22 | */ | ||
23 | |||
24 | #include <inttypes.h> | ||
25 | #include <stdio.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <unistd.h> | ||
28 | #include <sys/mman.h> | ||
29 | #include <string.h> | ||
30 | #include <assert.h> | ||
31 | |||
32 | #include "tm.h" | ||
33 | #include "utils.h" | ||
34 | |||
35 | int test_vmxcopy() | ||
36 | { | ||
37 | long double vecin = 1.3; | ||
38 | long double vecout; | ||
39 | unsigned long pgsize = getpagesize(); | ||
40 | int i; | ||
41 | int fd; | ||
42 | int size = pgsize*16; | ||
43 | char tmpfile[] = "/tmp/page_faultXXXXXX"; | ||
44 | char buf[pgsize]; | ||
45 | char *a; | ||
46 | uint64_t aborted = 0; | ||
47 | |||
48 | SKIP_IF(!have_htm()); | ||
49 | |||
50 | fd = mkstemp(tmpfile); | ||
51 | assert(fd >= 0); | ||
52 | |||
53 | memset(buf, 0, pgsize); | ||
54 | for (i = 0; i < size; i += pgsize) | ||
55 | assert(write(fd, buf, pgsize) == pgsize); | ||
56 | |||
57 | unlink(tmpfile); | ||
58 | |||
59 | a = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); | ||
60 | assert(a != MAP_FAILED); | ||
61 | |||
62 | asm __volatile__( | ||
63 | "lxvd2x 40,0,%[vecinptr];" /* set 40 to initial value*/ | ||
64 | "tbegin.;" | ||
65 | "beq 3f;" | ||
66 | "tsuspend.;" | ||
67 | "xxlxor 40,40,40;" /* set 40 to 0 */ | ||
68 | "std 5, 0(%[map]);" /* cause kernel vmx copy page */ | ||
69 | "tabort. 0;" | ||
70 | "tresume.;" | ||
71 | "tend.;" | ||
72 | "li %[res], 0;" | ||
73 | "b 5f;" | ||
74 | |||
75 | /* Abort handler */ | ||
76 | "3:;" | ||
77 | "li %[res], 1;" | ||
78 | |||
79 | "5:;" | ||
80 | "stxvd2x 40,0,%[vecoutptr];" | ||
81 | : [res]"=r"(aborted) | ||
82 | : [vecinptr]"r"(&vecin), | ||
83 | [vecoutptr]"r"(&vecout), | ||
84 | [map]"r"(a) | ||
85 | : "memory", "r0", "r3", "r4", "r5", "r6", "r7"); | ||
86 | |||
87 | if (aborted && (vecin != vecout)){ | ||
88 | printf("FAILED: vector state leaked on abort %f != %f\n", | ||
89 | (double)vecin, (double)vecout); | ||
90 | return 1; | ||
91 | } | ||
92 | |||
93 | munmap(a, size); | ||
94 | |||
95 | close(fd); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | int main(void) | ||
101 | { | ||
102 | return test_harness(test_vmxcopy, "tm_vmxcopy"); | ||
103 | } | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h new file mode 100644 index 000000000000..24144b25772c --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Michael Ellerman, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | */ | ||
5 | |||
6 | #ifndef _SELFTESTS_POWERPC_TM_TM_H | ||
7 | #define _SELFTESTS_POWERPC_TM_TM_H | ||
8 | |||
9 | #include <stdbool.h> | ||
10 | #include <asm/cputable.h> | ||
11 | |||
12 | #include "../utils.h" | ||
13 | |||
14 | static inline bool have_htm(void) | ||
15 | { | ||
16 | #ifdef PPC_FEATURE2_HTM | ||
17 | return have_hwcap2(PPC_FEATURE2_HTM); | ||
18 | #else | ||
19 | printf("PPC_FEATURE2_HTM not defined, can't check AT_HWCAP2\n"); | ||
20 | return false; | ||
21 | #endif | ||
22 | } | ||
23 | |||
24 | static inline bool have_htm_nosc(void) | ||
25 | { | ||
26 | #ifdef PPC_FEATURE2_HTM_NOSC | ||
27 | return have_hwcap2(PPC_FEATURE2_HTM_NOSC); | ||
28 | #else | ||
29 | printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n"); | ||
30 | return false; | ||
31 | #endif | ||
32 | } | ||
33 | |||
34 | #endif /* _SELFTESTS_POWERPC_TM_TM_H */ | ||
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c new file mode 100644 index 000000000000..dcf74184bfd0 --- /dev/null +++ b/tools/testing/selftests/powerpc/utils.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Copyright 2013-2015, Michael Ellerman, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | */ | ||
5 | |||
6 | #define _GNU_SOURCE /* For CPU_ZERO etc. */ | ||
7 | |||
8 | #include <elf.h> | ||
9 | #include <errno.h> | ||
10 | #include <fcntl.h> | ||
11 | #include <link.h> | ||
12 | #include <sched.h> | ||
13 | #include <stdio.h> | ||
14 | #include <sys/stat.h> | ||
15 | #include <sys/types.h> | ||
16 | #include <unistd.h> | ||
17 | |||
18 | #include "utils.h" | ||
19 | |||
20 | static char auxv[4096]; | ||
21 | |||
22 | void *get_auxv_entry(int type) | ||
23 | { | ||
24 | ElfW(auxv_t) *p; | ||
25 | void *result; | ||
26 | ssize_t num; | ||
27 | int fd; | ||
28 | |||
29 | fd = open("/proc/self/auxv", O_RDONLY); | ||
30 | if (fd == -1) { | ||
31 | perror("open"); | ||
32 | return NULL; | ||
33 | } | ||
34 | |||
35 | result = NULL; | ||
36 | |||
37 | num = read(fd, auxv, sizeof(auxv)); | ||
38 | if (num < 0) { | ||
39 | perror("read"); | ||
40 | goto out; | ||
41 | } | ||
42 | |||
43 | if (num > sizeof(auxv)) { | ||
44 | printf("Overflowed auxv buffer\n"); | ||
45 | goto out; | ||
46 | } | ||
47 | |||
48 | p = (ElfW(auxv_t) *)auxv; | ||
49 | |||
50 | while (p->a_type != AT_NULL) { | ||
51 | if (p->a_type == type) { | ||
52 | result = (void *)p->a_un.a_val; | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | p++; | ||
57 | } | ||
58 | out: | ||
59 | close(fd); | ||
60 | return result; | ||
61 | } | ||
62 | |||
63 | int pick_online_cpu(void) | ||
64 | { | ||
65 | cpu_set_t mask; | ||
66 | int cpu; | ||
67 | |||
68 | CPU_ZERO(&mask); | ||
69 | |||
70 | if (sched_getaffinity(0, sizeof(mask), &mask)) { | ||
71 | perror("sched_getaffinity"); | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | /* We prefer a primary thread, but skip 0 */ | ||
76 | for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8) | ||
77 | if (CPU_ISSET(cpu, &mask)) | ||
78 | return cpu; | ||
79 | |||
80 | /* Search for anything, but in reverse */ | ||
81 | for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) | ||
82 | if (CPU_ISSET(cpu, &mask)) | ||
83 | return cpu; | ||
84 | |||
85 | printf("No cpus in affinity mask?!\n"); | ||
86 | return -1; | ||
87 | } | ||
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h index b7d41086bb0a..175ac6ad10dd 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/utils.h | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include <stdint.h> | 9 | #include <stdint.h> |
10 | #include <stdbool.h> | 10 | #include <stdbool.h> |
11 | #include <linux/auxvec.h> | ||
11 | 12 | ||
12 | /* Avoid headaches with PRI?64 - just use %ll? always */ | 13 | /* Avoid headaches with PRI?64 - just use %ll? always */ |
13 | typedef unsigned long long u64; | 14 | typedef unsigned long long u64; |
@@ -21,6 +22,12 @@ typedef uint8_t u8; | |||
21 | 22 | ||
22 | int test_harness(int (test_function)(void), char *name); | 23 | int test_harness(int (test_function)(void), char *name); |
23 | extern void *get_auxv_entry(int type); | 24 | extern void *get_auxv_entry(int type); |
25 | int pick_online_cpu(void); | ||
26 | |||
27 | static inline bool have_hwcap2(unsigned long ftr2) | ||
28 | { | ||
29 | return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2; | ||
30 | } | ||
24 | 31 | ||
25 | /* Yes, this is evil */ | 32 | /* Yes, this is evil */ |
26 | #define FAIL_IF(x) \ | 33 | #define FAIL_IF(x) \ |
diff --git a/tools/testing/selftests/ptrace/.gitignore b/tools/testing/selftests/ptrace/.gitignore new file mode 100644 index 000000000000..b3e59d41fd82 --- /dev/null +++ b/tools/testing/selftests/ptrace/.gitignore | |||
@@ -0,0 +1 @@ | |||
peeksiginfo | |||
diff --git a/tools/testing/selftests/seccomp/test_harness.h b/tools/testing/selftests/seccomp/test_harness.h index fb2841601f2f..a786c69c7584 100644 --- a/tools/testing/selftests/seccomp/test_harness.h +++ b/tools/testing/selftests/seccomp/test_harness.h | |||
@@ -42,6 +42,7 @@ | |||
42 | #define TEST_HARNESS_H_ | 42 | #define TEST_HARNESS_H_ |
43 | 43 | ||
44 | #define _GNU_SOURCE | 44 | #define _GNU_SOURCE |
45 | #include <stdint.h> | ||
45 | #include <stdio.h> | 46 | #include <stdio.h> |
46 | #include <stdlib.h> | 47 | #include <stdlib.h> |
47 | #include <string.h> | 48 | #include <string.h> |
@@ -370,8 +371,8 @@ | |||
370 | __typeof__(_expected) __exp = (_expected); \ | 371 | __typeof__(_expected) __exp = (_expected); \ |
371 | __typeof__(_seen) __seen = (_seen); \ | 372 | __typeof__(_seen) __seen = (_seen); \ |
372 | if (!(__exp _t __seen)) { \ | 373 | if (!(__exp _t __seen)) { \ |
373 | unsigned long long __exp_print = (unsigned long long)__exp; \ | 374 | unsigned long long __exp_print = (uintptr_t)__exp; \ |
374 | unsigned long long __seen_print = (unsigned long long)__seen; \ | 375 | unsigned long long __seen_print = (uintptr_t)__seen; \ |
375 | __TH_LOG("Expected %s (%llu) %s %s (%llu)", \ | 376 | __TH_LOG("Expected %s (%llu) %s %s (%llu)", \ |
376 | #_expected, __exp_print, #_t, \ | 377 | #_expected, __exp_print, #_t, \ |
377 | #_seen, __seen_print); \ | 378 | #_seen, __seen_print); \ |
diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore index ced998151bc4..68f3fc71ac44 100644 --- a/tools/testing/selftests/timers/.gitignore +++ b/tools/testing/selftests/timers/.gitignore | |||
@@ -16,3 +16,4 @@ set-timer-lat | |||
16 | skew_consistency | 16 | skew_consistency |
17 | threadtest | 17 | threadtest |
18 | valid-adjtimex | 18 | valid-adjtimex |
19 | adjtick | ||
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore index ff1bb16cec4f..a937a9d26b60 100644 --- a/tools/testing/selftests/vm/.gitignore +++ b/tools/testing/selftests/vm/.gitignore | |||
@@ -2,3 +2,8 @@ hugepage-mmap | |||
2 | hugepage-shm | 2 | hugepage-shm |
3 | map_hugetlb | 3 | map_hugetlb |
4 | thuge-gen | 4 | thuge-gen |
5 | compaction_test | ||
6 | mlock2-tests | ||
7 | on-fault-limit | ||
8 | transhuge-stress | ||
9 | userfaultfd | ||
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index eabcff411984..d0c473f65850 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile | |||
@@ -4,9 +4,11 @@ include ../lib.mk | |||
4 | 4 | ||
5 | .PHONY: all all_32 all_64 warn_32bit_failure clean | 5 | .PHONY: all all_32 all_64 warn_32bit_failure clean |
6 | 6 | ||
7 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs ldt_gdt syscall_nt ptrace_syscall | 7 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall |
8 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \ | 8 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \ |
9 | test_FCMOV test_FCOMI test_FISTTP | 9 | test_FCMOV test_FCOMI test_FISTTP \ |
10 | ldt_gdt \ | ||
11 | vdso_restorer | ||
10 | 12 | ||
11 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) | 13 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) |
12 | BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) | 14 | BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) |
diff --git a/tools/testing/selftests/x86/vdso_restorer.c b/tools/testing/selftests/x86/vdso_restorer.c new file mode 100644 index 000000000000..cb038424a403 --- /dev/null +++ b/tools/testing/selftests/x86/vdso_restorer.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * vdso_restorer.c - tests vDSO-based signal restore | ||
3 | * Copyright (c) 2015 Andrew Lutomirski | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * This makes sure that sa_restorer == NULL keeps working on 32-bit | ||
15 | * configurations. Modern glibc doesn't use it under any circumstances, | ||
16 | * so it's easy to overlook breakage. | ||
17 | * | ||
18 | * 64-bit userspace has never supported sa_restorer == NULL, so this is | ||
19 | * 32-bit only. | ||
20 | */ | ||
21 | |||
22 | #define _GNU_SOURCE | ||
23 | |||
24 | #include <err.h> | ||
25 | #include <stdio.h> | ||
26 | #include <string.h> | ||
27 | #include <signal.h> | ||
28 | #include <unistd.h> | ||
29 | #include <syscall.h> | ||
30 | #include <sys/syscall.h> | ||
31 | |||
32 | /* Open-code this -- the headers are too messy to easily use them. */ | ||
33 | struct real_sigaction { | ||
34 | void *handler; | ||
35 | unsigned long flags; | ||
36 | void *restorer; | ||
37 | unsigned int mask[2]; | ||
38 | }; | ||
39 | |||
40 | static volatile sig_atomic_t handler_called; | ||
41 | |||
42 | static void handler_with_siginfo(int sig, siginfo_t *info, void *ctx_void) | ||
43 | { | ||
44 | handler_called = 1; | ||
45 | } | ||
46 | |||
47 | static void handler_without_siginfo(int sig) | ||
48 | { | ||
49 | handler_called = 1; | ||
50 | } | ||
51 | |||
52 | int main() | ||
53 | { | ||
54 | int nerrs = 0; | ||
55 | struct real_sigaction sa; | ||
56 | |||
57 | memset(&sa, 0, sizeof(sa)); | ||
58 | sa.handler = handler_with_siginfo; | ||
59 | sa.flags = SA_SIGINFO; | ||
60 | sa.restorer = NULL; /* request kernel-provided restorer */ | ||
61 | |||
62 | if (syscall(SYS_rt_sigaction, SIGUSR1, &sa, NULL, 8) != 0) | ||
63 | err(1, "raw rt_sigaction syscall"); | ||
64 | |||
65 | raise(SIGUSR1); | ||
66 | |||
67 | if (handler_called) { | ||
68 | printf("[OK]\tSA_SIGINFO handler returned successfully\n"); | ||
69 | } else { | ||
70 | printf("[FAIL]\tSA_SIGINFO handler was not called\n"); | ||
71 | nerrs++; | ||
72 | } | ||
73 | |||
74 | sa.flags = 0; | ||
75 | sa.handler = handler_without_siginfo; | ||
76 | if (syscall(SYS_sigaction, SIGUSR1, &sa, 0) != 0) | ||
77 | err(1, "raw sigaction syscall"); | ||
78 | handler_called = 0; | ||
79 | |||
80 | raise(SIGUSR1); | ||
81 | |||
82 | if (handler_called) { | ||
83 | printf("[OK]\t!SA_SIGINFO handler returned successfully\n"); | ||
84 | } else { | ||
85 | printf("[FAIL]\t!SA_SIGINFO handler was not called\n"); | ||
86 | nerrs++; | ||
87 | } | ||
88 | } | ||