diff options
Diffstat (limited to 'tools')
146 files changed, 6932 insertions, 793 deletions
diff --git a/tools/Makefile b/tools/Makefile index daa8fb3e4363..00caacd3ed92 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -17,6 +17,7 @@ help: | |||
17 | @echo ' hv - tools used when in Hyper-V clients' | 17 | @echo ' hv - tools used when in Hyper-V clients' |
18 | @echo ' iio - IIO tools' | 18 | @echo ' iio - IIO tools' |
19 | @echo ' kvm_stat - top-like utility for displaying kvm statistics' | 19 | @echo ' kvm_stat - top-like utility for displaying kvm statistics' |
20 | @echo ' leds - LEDs tools' | ||
20 | @echo ' lguest - a minimal 32-bit x86 hypervisor' | 21 | @echo ' lguest - a minimal 32-bit x86 hypervisor' |
21 | @echo ' net - misc networking tools' | 22 | @echo ' net - misc networking tools' |
22 | @echo ' perf - Linux performance measurement and analysis tool' | 23 | @echo ' perf - Linux performance measurement and analysis tool' |
@@ -56,7 +57,7 @@ acpi: FORCE | |||
56 | cpupower: FORCE | 57 | cpupower: FORCE |
57 | $(call descend,power/$@) | 58 | $(call descend,power/$@) |
58 | 59 | ||
59 | cgroup firewire hv guest spi usb virtio vm net iio gpio objtool: FORCE | 60 | cgroup firewire hv guest spi usb virtio vm net iio gpio objtool leds: FORCE |
60 | $(call descend,$@) | 61 | $(call descend,$@) |
61 | 62 | ||
62 | liblockdep: FORCE | 63 | liblockdep: FORCE |
@@ -126,7 +127,7 @@ acpi_clean: | |||
126 | cpupower_clean: | 127 | cpupower_clean: |
127 | $(call descend,power/cpupower,clean) | 128 | $(call descend,power/cpupower,clean) |
128 | 129 | ||
129 | cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean gpio_clean objtool_clean: | 130 | cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean gpio_clean objtool_clean leds_clean: |
130 | $(call descend,$(@:_clean=),clean) | 131 | $(call descend,$(@:_clean=),clean) |
131 | 132 | ||
132 | liblockdep_clean: | 133 | liblockdep_clean: |
@@ -164,6 +165,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_cle | |||
164 | perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ | 165 | perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ |
165 | vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ | 166 | vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ |
166 | freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ | 167 | freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ |
167 | gpio_clean objtool_clean | 168 | gpio_clean objtool_clean leds_clean |
168 | 169 | ||
169 | .PHONY: FORCE | 170 | .PHONY: FORCE |
diff --git a/tools/build/Makefile b/tools/build/Makefile index 8332959fbca4..aaf7ed329a45 100644 --- a/tools/build/Makefile +++ b/tools/build/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | ifeq ($(srctree),) | 1 | ifeq ($(srctree),) |
2 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 2 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
3 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 3 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
4 | endif | 4 | endif |
5 | 5 | ||
diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index 250a891e6ef0..b4401536cfa9 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile | |||
@@ -3,7 +3,7 @@ include ../scripts/Makefile.include | |||
3 | bindir ?= /usr/bin | 3 | bindir ?= /usr/bin |
4 | 4 | ||
5 | ifeq ($(srctree),) | 5 | ifeq ($(srctree),) |
6 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 6 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
7 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 7 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
8 | endif | 8 | endif |
9 | 9 | ||
diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c index 37b3f141053d..f1eab587dfea 100644 --- a/tools/gpio/gpio-hammer.c +++ b/tools/gpio/gpio-hammer.c | |||
@@ -23,54 +23,31 @@ | |||
23 | #include <getopt.h> | 23 | #include <getopt.h> |
24 | #include <sys/ioctl.h> | 24 | #include <sys/ioctl.h> |
25 | #include <linux/gpio.h> | 25 | #include <linux/gpio.h> |
26 | #include "gpio-utils.h" | ||
26 | 27 | ||
27 | int hammer_device(const char *device_name, unsigned int *lines, int nlines, | 28 | int hammer_device(const char *device_name, unsigned int *lines, int nlines, |
28 | unsigned int loops) | 29 | unsigned int loops) |
29 | { | 30 | { |
30 | struct gpiohandle_request req; | ||
31 | struct gpiohandle_data data; | 31 | struct gpiohandle_data data; |
32 | char *chrdev_name; | ||
33 | char swirr[] = "-\\|/"; | 32 | char swirr[] = "-\\|/"; |
34 | int fd; | 33 | int fd; |
35 | int ret; | 34 | int ret; |
36 | int i, j; | 35 | int i, j; |
37 | unsigned int iteration = 0; | 36 | unsigned int iteration = 0; |
38 | 37 | ||
39 | ret = asprintf(&chrdev_name, "/dev/%s", device_name); | 38 | memset(&data.values, 0, sizeof(data.values)); |
39 | ret = gpiotools_request_linehandle(device_name, lines, nlines, | ||
40 | GPIOHANDLE_REQUEST_OUTPUT, &data, | ||
41 | "gpio-hammler"); | ||
40 | if (ret < 0) | 42 | if (ret < 0) |
41 | return -ENOMEM; | 43 | goto exit_error; |
44 | else | ||
45 | fd = ret; | ||
42 | 46 | ||
43 | fd = open(chrdev_name, 0); | 47 | ret = gpiotools_get_values(fd, &data); |
44 | if (fd == -1) { | 48 | if (ret < 0) |
45 | ret = -errno; | ||
46 | fprintf(stderr, "Failed to open %s\n", chrdev_name); | ||
47 | goto exit_close_error; | ||
48 | } | ||
49 | |||
50 | /* Request lines as output */ | ||
51 | for (i = 0; i < nlines; i++) | ||
52 | req.lineoffsets[i] = lines[i]; | ||
53 | req.flags = GPIOHANDLE_REQUEST_OUTPUT; /* Request as output */ | ||
54 | strcpy(req.consumer_label, "gpio-hammer"); | ||
55 | req.lines = nlines; | ||
56 | ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); | ||
57 | if (ret == -1) { | ||
58 | ret = -errno; | ||
59 | fprintf(stderr, "Failed to issue GET LINEHANDLE " | ||
60 | "IOCTL (%d)\n", | ||
61 | ret); | ||
62 | goto exit_close_error; | 49 | goto exit_close_error; |
63 | } | ||
64 | 50 | ||
65 | /* Read initial states */ | ||
66 | ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); | ||
67 | if (ret == -1) { | ||
68 | ret = -errno; | ||
69 | fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " | ||
70 | "VALUES IOCTL (%d)\n", | ||
71 | ret); | ||
72 | goto exit_close_error; | ||
73 | } | ||
74 | fprintf(stdout, "Hammer lines ["); | 51 | fprintf(stdout, "Hammer lines ["); |
75 | for (i = 0; i < nlines; i++) { | 52 | for (i = 0; i < nlines; i++) { |
76 | fprintf(stdout, "%d", lines[i]); | 53 | fprintf(stdout, "%d", lines[i]); |
@@ -92,23 +69,14 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, | |||
92 | for (i = 0; i < nlines; i++) | 69 | for (i = 0; i < nlines; i++) |
93 | data.values[i] = !data.values[i]; | 70 | data.values[i] = !data.values[i]; |
94 | 71 | ||
95 | ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); | 72 | ret = gpiotools_set_values(fd, &data); |
96 | if (ret == -1) { | 73 | if (ret < 0) |
97 | ret = -errno; | ||
98 | fprintf(stderr, "Failed to issue GPIOHANDLE SET LINE " | ||
99 | "VALUES IOCTL (%d)\n", | ||
100 | ret); | ||
101 | goto exit_close_error; | 74 | goto exit_close_error; |
102 | } | 75 | |
103 | /* Re-read values to get status */ | 76 | /* Re-read values to get status */ |
104 | ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); | 77 | ret = gpiotools_get_values(fd, &data); |
105 | if (ret == -1) { | 78 | if (ret < 0) |
106 | ret = -errno; | ||
107 | fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " | ||
108 | "VALUES IOCTL (%d)\n", | ||
109 | ret); | ||
110 | goto exit_close_error; | 79 | goto exit_close_error; |
111 | } | ||
112 | 80 | ||
113 | fprintf(stdout, "[%c] ", swirr[j]); | 81 | fprintf(stdout, "[%c] ", swirr[j]); |
114 | j++; | 82 | j++; |
@@ -132,9 +100,8 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, | |||
132 | ret = 0; | 100 | ret = 0; |
133 | 101 | ||
134 | exit_close_error: | 102 | exit_close_error: |
135 | if (close(fd) == -1) | 103 | gpiotools_release_linehandle(fd); |
136 | perror("Failed to close GPIO character device file"); | 104 | exit_error: |
137 | free(chrdev_name); | ||
138 | return ret; | 105 | return ret; |
139 | } | 106 | } |
140 | 107 | ||
diff --git a/tools/gpio/gpio-utils.c b/tools/gpio/gpio-utils.c index 8208718f2c99..b86a32d90d88 100644 --- a/tools/gpio/gpio-utils.c +++ b/tools/gpio/gpio-utils.c | |||
@@ -2,10 +2,266 @@ | |||
2 | * GPIO tools - helpers library for the GPIO tools | 2 | * GPIO tools - helpers library for the GPIO tools |
3 | * | 3 | * |
4 | * Copyright (C) 2015 Linus Walleij | 4 | * Copyright (C) 2015 Linus Walleij |
5 | * Copyright (C) 2016 Bamvor Jian Zhang | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License version 2 as published by | 8 | * under the terms of the GNU General Public License version 2 as published by |
8 | * the Free Software Foundation. | 9 | * the Free Software Foundation. |
9 | */ | 10 | */ |
10 | 11 | ||
12 | #include <unistd.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <stdio.h> | ||
15 | #include <errno.h> | ||
16 | #include <string.h> | ||
17 | #include <fcntl.h> | ||
18 | #include <getopt.h> | ||
19 | #include <sys/ioctl.h> | ||
20 | #include <linux/gpio.h> | ||
11 | #include "gpio-utils.h" | 21 | #include "gpio-utils.h" |
22 | |||
23 | #define COMSUMER "gpio-utils" | ||
24 | |||
25 | /** | ||
26 | * doc: Operation of gpio | ||
27 | * | ||
28 | * Provide the api of gpiochip for chardev interface. There are two | ||
29 | * types of api. The first one provide as same function as each | ||
30 | * ioctl, including request and release for lines of gpio, read/write | ||
31 | * the value of gpio. If the user want to do lots of read and write of | ||
32 | * lines of gpio, user should use this type of api. | ||
33 | * | ||
34 | * The second one provide the easy to use api for user. Each of the | ||
35 | * following api will request gpio lines, do the operation and then | ||
36 | * release these lines. | ||
37 | */ | ||
38 | /** | ||
39 | * gpiotools_request_linehandle() - request gpio lines in a gpiochip | ||
40 | * @device_name: The name of gpiochip without prefix "/dev/", | ||
41 | * such as "gpiochip0" | ||
42 | * @lines: An array desired lines, specified by offset | ||
43 | * index for the associated GPIO device. | ||
44 | * @nline: The number of lines to request. | ||
45 | * @flag: The new flag for requsted gpio. Reference | ||
46 | * "linux/gpio.h" for the meaning of flag. | ||
47 | * @data: Default value will be set to gpio when flag is | ||
48 | * GPIOHANDLE_REQUEST_OUTPUT. | ||
49 | * @consumer_label: The name of consumer, such as "sysfs", | ||
50 | * "powerkey". This is useful for other users to | ||
51 | * know who is using. | ||
52 | * | ||
53 | * Request gpio lines through the ioctl provided by chardev. User | ||
54 | * could call gpiotools_set_values() and gpiotools_get_values() to | ||
55 | * read and write respectively through the returned fd. Call | ||
56 | * gpiotools_release_linehandle() to release these lines after that. | ||
57 | * | ||
58 | * Return: On success return the fd; | ||
59 | * On failure return the errno. | ||
60 | */ | ||
61 | int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, | ||
62 | unsigned int nlines, unsigned int flag, | ||
63 | struct gpiohandle_data *data, | ||
64 | const char *consumer_label) | ||
65 | { | ||
66 | struct gpiohandle_request req; | ||
67 | char *chrdev_name; | ||
68 | int fd; | ||
69 | int i; | ||
70 | int ret; | ||
71 | |||
72 | ret = asprintf(&chrdev_name, "/dev/%s", device_name); | ||
73 | if (ret < 0) | ||
74 | return -ENOMEM; | ||
75 | |||
76 | fd = open(chrdev_name, 0); | ||
77 | if (fd == -1) { | ||
78 | ret = -errno; | ||
79 | fprintf(stderr, "Failed to open %s\n", chrdev_name); | ||
80 | goto exit_close_error; | ||
81 | } | ||
82 | |||
83 | for (i = 0; i < nlines; i++) | ||
84 | req.lineoffsets[i] = lines[i]; | ||
85 | |||
86 | req.flags = flag; | ||
87 | strcpy(req.consumer_label, consumer_label); | ||
88 | req.lines = nlines; | ||
89 | if (flag & GPIOHANDLE_REQUEST_OUTPUT) | ||
90 | memcpy(req.default_values, data, sizeof(req.default_values)); | ||
91 | |||
92 | ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); | ||
93 | if (ret == -1) { | ||
94 | ret = -errno; | ||
95 | fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n", | ||
96 | ret); | ||
97 | } | ||
98 | |||
99 | exit_close_error: | ||
100 | if (close(fd) == -1) | ||
101 | perror("Failed to close GPIO character device file"); | ||
102 | free(chrdev_name); | ||
103 | return ret < 0 ? ret : req.fd; | ||
104 | } | ||
105 | /** | ||
106 | * gpiotools_set_values(): Set the value of gpio(s) | ||
107 | * @fd: The fd returned by | ||
108 | * gpiotools_request_linehandle(). | ||
109 | * @data: The array of values want to set. | ||
110 | * | ||
111 | * Return: On success return 0; | ||
112 | * On failure return the errno. | ||
113 | */ | ||
114 | int gpiotools_set_values(const int fd, struct gpiohandle_data *data) | ||
115 | { | ||
116 | int ret; | ||
117 | |||
118 | ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data); | ||
119 | if (ret == -1) { | ||
120 | ret = -errno; | ||
121 | fprintf(stderr, "Failed to issue %s (%d)\n", | ||
122 | "GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret); | ||
123 | } | ||
124 | |||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * gpiotools_get_values(): Get the value of gpio(s) | ||
130 | * @fd: The fd returned by | ||
131 | * gpiotools_request_linehandle(). | ||
132 | * @data: The array of values get from hardware. | ||
133 | * | ||
134 | * Return: On success return 0; | ||
135 | * On failure return the errno. | ||
136 | */ | ||
137 | int gpiotools_get_values(const int fd, struct gpiohandle_data *data) | ||
138 | { | ||
139 | int ret; | ||
140 | |||
141 | ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data); | ||
142 | if (ret == -1) { | ||
143 | ret = -errno; | ||
144 | fprintf(stderr, "Failed to issue %s (%d)\n", | ||
145 | "GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret); | ||
146 | } | ||
147 | |||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * gpiotools_release_linehandle(): Release the line(s) of gpiochip | ||
153 | * @fd: The fd returned by | ||
154 | * gpiotools_request_linehandle(). | ||
155 | * | ||
156 | * Return: On success return 0; | ||
157 | * On failure return the errno. | ||
158 | */ | ||
159 | int gpiotools_release_linehandle(const int fd) | ||
160 | { | ||
161 | int ret; | ||
162 | |||
163 | ret = close(fd); | ||
164 | if (ret == -1) { | ||
165 | perror("Failed to close GPIO LINEHANDLE device file"); | ||
166 | ret = -errno; | ||
167 | } | ||
168 | |||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * gpiotools_get(): Get value from specific line | ||
174 | * @device_name: The name of gpiochip without prefix "/dev/", | ||
175 | * such as "gpiochip0" | ||
176 | * @line: number of line, such as 2. | ||
177 | * | ||
178 | * Return: On success return 0; | ||
179 | * On failure return the errno. | ||
180 | */ | ||
181 | int gpiotools_get(const char *device_name, unsigned int line) | ||
182 | { | ||
183 | struct gpiohandle_data data; | ||
184 | unsigned int lines[] = {line}; | ||
185 | |||
186 | gpiotools_gets(device_name, lines, 1, &data); | ||
187 | return data.values[0]; | ||
188 | } | ||
189 | |||
190 | |||
191 | /** | ||
192 | * gpiotools_gets(): Get values from specific lines. | ||
193 | * @device_name: The name of gpiochip without prefix "/dev/", | ||
194 | * such as "gpiochip0". | ||
195 | * @lines: An array desired lines, specified by offset | ||
196 | * index for the associated GPIO device. | ||
197 | * @nline: The number of lines to request. | ||
198 | * @data: The array of values get from gpiochip. | ||
199 | * | ||
200 | * Return: On success return 0; | ||
201 | * On failure return the errno. | ||
202 | */ | ||
203 | int gpiotools_gets(const char *device_name, unsigned int *lines, | ||
204 | unsigned int nlines, struct gpiohandle_data *data) | ||
205 | { | ||
206 | int fd; | ||
207 | int ret; | ||
208 | int ret_close; | ||
209 | |||
210 | ret = gpiotools_request_linehandle(device_name, lines, nlines, | ||
211 | GPIOHANDLE_REQUEST_INPUT, data, | ||
212 | COMSUMER); | ||
213 | if (ret < 0) | ||
214 | return ret; | ||
215 | |||
216 | fd = ret; | ||
217 | ret = gpiotools_get_values(fd, data); | ||
218 | ret_close = gpiotools_release_linehandle(fd); | ||
219 | return ret < 0 ? ret : ret_close; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * gpiotools_set(): Set value to specific line | ||
224 | * @device_name: The name of gpiochip without prefix "/dev/", | ||
225 | * such as "gpiochip0" | ||
226 | * @line: number of line, such as 2. | ||
227 | * @value: The value of gpio, must be 0(low) or 1(high). | ||
228 | * | ||
229 | * Return: On success return 0; | ||
230 | * On failure return the errno. | ||
231 | */ | ||
232 | int gpiotools_set(const char *device_name, unsigned int line, | ||
233 | unsigned int value) | ||
234 | { | ||
235 | struct gpiohandle_data data; | ||
236 | unsigned int lines[] = {line}; | ||
237 | |||
238 | data.values[0] = value; | ||
239 | return gpiotools_sets(device_name, lines, 1, &data); | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * gpiotools_sets(): Set values to specific lines. | ||
244 | * @device_name: The name of gpiochip without prefix "/dev/", | ||
245 | * such as "gpiochip0". | ||
246 | * @lines: An array desired lines, specified by offset | ||
247 | * index for the associated GPIO device. | ||
248 | * @nline: The number of lines to request. | ||
249 | * @data: The array of values set to gpiochip, must be | ||
250 | * 0(low) or 1(high). | ||
251 | * | ||
252 | * Return: On success return 0; | ||
253 | * On failure return the errno. | ||
254 | */ | ||
255 | int gpiotools_sets(const char *device_name, unsigned int *lines, | ||
256 | unsigned int nlines, struct gpiohandle_data *data) | ||
257 | { | ||
258 | int ret; | ||
259 | |||
260 | ret = gpiotools_request_linehandle(device_name, lines, nlines, | ||
261 | GPIOHANDLE_REQUEST_OUTPUT, data, | ||
262 | COMSUMER); | ||
263 | if (ret < 0) | ||
264 | return ret; | ||
265 | |||
266 | return gpiotools_release_linehandle(ret); | ||
267 | } | ||
diff --git a/tools/gpio/gpio-utils.h b/tools/gpio/gpio-utils.h index 5f57133b8c04..344ea041f8d4 100644 --- a/tools/gpio/gpio-utils.h +++ b/tools/gpio/gpio-utils.h | |||
@@ -24,4 +24,20 @@ static inline int check_prefix(const char *str, const char *prefix) | |||
24 | strncmp(str, prefix, strlen(prefix)) == 0; | 24 | strncmp(str, prefix, strlen(prefix)) == 0; |
25 | } | 25 | } |
26 | 26 | ||
27 | int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, | ||
28 | unsigned int nlines, unsigned int flag, | ||
29 | struct gpiohandle_data *data, | ||
30 | const char *consumer_label); | ||
31 | int gpiotools_set_values(const int fd, struct gpiohandle_data *data); | ||
32 | int gpiotools_get_values(const int fd, struct gpiohandle_data *data); | ||
33 | int gpiotools_release_linehandle(const int fd); | ||
34 | |||
35 | int gpiotools_get(const char *device_name, unsigned int line); | ||
36 | int gpiotools_gets(const char *device_name, unsigned int *lines, | ||
37 | unsigned int nlines, struct gpiohandle_data *data); | ||
38 | int gpiotools_set(const char *device_name, unsigned int line, | ||
39 | unsigned int value); | ||
40 | int gpiotools_sets(const char *device_name, unsigned int *lines, | ||
41 | unsigned int nlines, struct gpiohandle_data *data); | ||
42 | |||
27 | #endif /* _GPIO_UTILS_H_ */ | 43 | #endif /* _GPIO_UTILS_H_ */ |
diff --git a/tools/hv/Makefile b/tools/hv/Makefile index a8c4644022a6..0d1e61b81844 100644 --- a/tools/hv/Makefile +++ b/tools/hv/Makefile | |||
@@ -1,9 +1,8 @@ | |||
1 | # Makefile for Hyper-V tools | 1 | # Makefile for Hyper-V tools |
2 | 2 | ||
3 | CC = $(CROSS_COMPILE)gcc | 3 | CC = $(CROSS_COMPILE)gcc |
4 | PTHREAD_LIBS = -lpthread | ||
5 | WARNINGS = -Wall -Wextra | 4 | WARNINGS = -Wall -Wextra |
6 | CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) $(shell getconf LFS_CFLAGS) | 5 | CFLAGS = $(WARNINGS) -g $(shell getconf LFS_CFLAGS) |
7 | 6 | ||
8 | CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include | 7 | CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include |
9 | 8 | ||
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c index fdc9ca4c0356..26ae609a9448 100644 --- a/tools/hv/hv_fcopy_daemon.c +++ b/tools/hv/hv_fcopy_daemon.c | |||
@@ -18,21 +18,14 @@ | |||
18 | 18 | ||
19 | 19 | ||
20 | #include <sys/types.h> | 20 | #include <sys/types.h> |
21 | #include <sys/socket.h> | ||
22 | #include <sys/poll.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/kdev_t.h> | ||
25 | #include <stdio.h> | 21 | #include <stdio.h> |
26 | #include <stdlib.h> | 22 | #include <stdlib.h> |
27 | #include <unistd.h> | 23 | #include <unistd.h> |
28 | #include <string.h> | ||
29 | #include <ctype.h> | ||
30 | #include <errno.h> | 24 | #include <errno.h> |
31 | #include <linux/hyperv.h> | 25 | #include <linux/hyperv.h> |
32 | #include <syslog.h> | 26 | #include <syslog.h> |
33 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
34 | #include <fcntl.h> | 28 | #include <fcntl.h> |
35 | #include <dirent.h> | ||
36 | #include <getopt.h> | 29 | #include <getopt.h> |
37 | 30 | ||
38 | static int target_fd; | 31 | static int target_fd; |
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index bc7adb84e679..f1758fcbc37d 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -22,8 +22,6 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | 24 | ||
25 | #include <sys/types.h> | ||
26 | #include <sys/socket.h> | ||
27 | #include <sys/poll.h> | 25 | #include <sys/poll.h> |
28 | #include <sys/utsname.h> | 26 | #include <sys/utsname.h> |
29 | #include <stdio.h> | 27 | #include <stdio.h> |
@@ -34,7 +32,6 @@ | |||
34 | #include <errno.h> | 32 | #include <errno.h> |
35 | #include <arpa/inet.h> | 33 | #include <arpa/inet.h> |
36 | #include <linux/hyperv.h> | 34 | #include <linux/hyperv.h> |
37 | #include <linux/netlink.h> | ||
38 | #include <ifaddrs.h> | 35 | #include <ifaddrs.h> |
39 | #include <netdb.h> | 36 | #include <netdb.h> |
40 | #include <syslog.h> | 37 | #include <syslog.h> |
@@ -96,13 +93,13 @@ static struct utsname uts_buf; | |||
96 | 93 | ||
97 | #define KVP_CONFIG_LOC "/var/lib/hyperv" | 94 | #define KVP_CONFIG_LOC "/var/lib/hyperv" |
98 | 95 | ||
96 | #ifndef KVP_SCRIPTS_PATH | ||
97 | #define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/" | ||
98 | #endif | ||
99 | |||
99 | #define MAX_FILE_NAME 100 | 100 | #define MAX_FILE_NAME 100 |
100 | #define ENTRIES_PER_BLOCK 50 | 101 | #define ENTRIES_PER_BLOCK 50 |
101 | 102 | ||
102 | #ifndef SOL_NETLINK | ||
103 | #define SOL_NETLINK 270 | ||
104 | #endif | ||
105 | |||
106 | struct kvp_record { | 103 | struct kvp_record { |
107 | char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; | 104 | char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; |
108 | char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; | 105 | char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; |
@@ -702,7 +699,7 @@ static char *kvp_mac_to_if_name(char *mac) | |||
702 | if (dir == NULL) | 699 | if (dir == NULL) |
703 | return NULL; | 700 | return NULL; |
704 | 701 | ||
705 | snprintf(dev_id, sizeof(dev_id), kvp_net_dir); | 702 | snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir); |
706 | q = dev_id + strlen(kvp_net_dir); | 703 | q = dev_id + strlen(kvp_net_dir); |
707 | 704 | ||
708 | while ((entry = readdir(dir)) != NULL) { | 705 | while ((entry = readdir(dir)) != NULL) { |
@@ -825,7 +822,7 @@ static void kvp_get_ipconfig_info(char *if_name, | |||
825 | * . | 822 | * . |
826 | */ | 823 | */ |
827 | 824 | ||
828 | sprintf(cmd, "%s", "hv_get_dns_info"); | 825 | sprintf(cmd, KVP_SCRIPTS_PATH "%s", "hv_get_dns_info"); |
829 | 826 | ||
830 | /* | 827 | /* |
831 | * Execute the command to gather DNS info. | 828 | * Execute the command to gather DNS info. |
@@ -842,7 +839,7 @@ static void kvp_get_ipconfig_info(char *if_name, | |||
842 | * Enabled: DHCP enabled. | 839 | * Enabled: DHCP enabled. |
843 | */ | 840 | */ |
844 | 841 | ||
845 | sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name); | 842 | sprintf(cmd, KVP_SCRIPTS_PATH "%s %s", "hv_get_dhcp_info", if_name); |
846 | 843 | ||
847 | file = popen(cmd, "r"); | 844 | file = popen(cmd, "r"); |
848 | if (file == NULL) | 845 | if (file == NULL) |
@@ -1348,7 +1345,8 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) | |||
1348 | * invoke the external script to do its magic. | 1345 | * invoke the external script to do its magic. |
1349 | */ | 1346 | */ |
1350 | 1347 | ||
1351 | snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file); | 1348 | snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s", |
1349 | "hv_set_ifconfig", if_file); | ||
1352 | if (system(cmd)) { | 1350 | if (system(cmd)) { |
1353 | syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s", | 1351 | syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s", |
1354 | cmd, errno, strerror(errno)); | 1352 | cmd, errno, strerror(errno)); |
diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index f39c0e9c0d5c..f0c6f54a8b2f 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c | |||
@@ -247,6 +247,7 @@ void print_usage(void) | |||
247 | fprintf(stderr, "Usage: generic_buffer [options]...\n" | 247 | fprintf(stderr, "Usage: generic_buffer [options]...\n" |
248 | "Capture, convert and output data from IIO device buffer\n" | 248 | "Capture, convert and output data from IIO device buffer\n" |
249 | " -a Auto-activate all available channels\n" | 249 | " -a Auto-activate all available channels\n" |
250 | " -A Force-activate ALL channels\n" | ||
250 | " -c <n> Do n conversions\n" | 251 | " -c <n> Do n conversions\n" |
251 | " -e Disable wait for event (new data)\n" | 252 | " -e Disable wait for event (new data)\n" |
252 | " -g Use trigger-less mode\n" | 253 | " -g Use trigger-less mode\n" |
@@ -347,16 +348,22 @@ int main(int argc, char **argv) | |||
347 | int noevents = 0; | 348 | int noevents = 0; |
348 | int notrigger = 0; | 349 | int notrigger = 0; |
349 | char *dummy; | 350 | char *dummy; |
351 | bool force_autochannels = false; | ||
350 | 352 | ||
351 | struct iio_channel_info *channels = NULL; | 353 | struct iio_channel_info *channels = NULL; |
352 | 354 | ||
353 | register_cleanup(); | 355 | register_cleanup(); |
354 | 356 | ||
355 | while ((c = getopt_long(argc, argv, "ac:egl:n:N:t:T:w:", longopts, NULL)) != -1) { | 357 | while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, |
358 | NULL)) != -1) { | ||
356 | switch (c) { | 359 | switch (c) { |
357 | case 'a': | 360 | case 'a': |
358 | autochannels = AUTOCHANNELS_ENABLED; | 361 | autochannels = AUTOCHANNELS_ENABLED; |
359 | break; | 362 | break; |
363 | case 'A': | ||
364 | autochannels = AUTOCHANNELS_ENABLED; | ||
365 | force_autochannels = true; | ||
366 | break; | ||
360 | case 'c': | 367 | case 'c': |
361 | errno = 0; | 368 | errno = 0; |
362 | num_loops = strtoul(optarg, &dummy, 10); | 369 | num_loops = strtoul(optarg, &dummy, 10); |
@@ -519,15 +526,16 @@ int main(int argc, char **argv) | |||
519 | "diag %s\n", dev_dir_name); | 526 | "diag %s\n", dev_dir_name); |
520 | goto error; | 527 | goto error; |
521 | } | 528 | } |
522 | if (num_channels && autochannels == AUTOCHANNELS_ENABLED) { | 529 | if (num_channels && autochannels == AUTOCHANNELS_ENABLED && |
530 | !force_autochannels) { | ||
523 | fprintf(stderr, "Auto-channels selected but some channels " | 531 | fprintf(stderr, "Auto-channels selected but some channels " |
524 | "are already activated in sysfs\n"); | 532 | "are already activated in sysfs\n"); |
525 | fprintf(stderr, "Proceeding without activating any channels\n"); | 533 | fprintf(stderr, "Proceeding without activating any channels\n"); |
526 | } | 534 | } |
527 | 535 | ||
528 | if (!num_channels && autochannels == AUTOCHANNELS_ENABLED) { | 536 | if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || |
529 | fprintf(stderr, | 537 | (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { |
530 | "No channels are enabled, enabling all channels\n"); | 538 | fprintf(stderr, "Enabling all channels\n"); |
531 | 539 | ||
532 | ret = enable_disable_all_channels(dev_dir_name, 1); | 540 | ret = enable_disable_all_channels(dev_dir_name, 1); |
533 | if (ret) { | 541 | if (ret) { |
diff --git a/tools/include/asm/bug.h b/tools/include/asm/bug.h index 9e5f4846967f..beda1a884b50 100644 --- a/tools/include/asm/bug.h +++ b/tools/include/asm/bug.h | |||
@@ -12,6 +12,17 @@ | |||
12 | unlikely(__ret_warn_on); \ | 12 | unlikely(__ret_warn_on); \ |
13 | }) | 13 | }) |
14 | 14 | ||
15 | #define WARN_ON_ONCE(condition) ({ \ | ||
16 | static int __warned; \ | ||
17 | int __ret_warn_once = !!(condition); \ | ||
18 | \ | ||
19 | if (unlikely(__ret_warn_once && !__warned)) { \ | ||
20 | __warned = true; \ | ||
21 | WARN_ON(1); \ | ||
22 | } \ | ||
23 | unlikely(__ret_warn_once); \ | ||
24 | }) | ||
25 | |||
15 | #define WARN_ONCE(condition, format...) ({ \ | 26 | #define WARN_ONCE(condition, format...) ({ \ |
16 | static int __warned; \ | 27 | static int __warned; \ |
17 | int __ret_warn_once = !!(condition); \ | 28 | int __ret_warn_once = !!(condition); \ |
diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h index 43c1c5021e4b..eef41d500e9e 100644 --- a/tools/include/linux/bitmap.h +++ b/tools/include/linux/bitmap.h | |||
@@ -35,6 +35,32 @@ static inline void bitmap_zero(unsigned long *dst, int nbits) | |||
35 | } | 35 | } |
36 | } | 36 | } |
37 | 37 | ||
38 | static inline void bitmap_fill(unsigned long *dst, unsigned int nbits) | ||
39 | { | ||
40 | unsigned int nlongs = BITS_TO_LONGS(nbits); | ||
41 | if (!small_const_nbits(nbits)) { | ||
42 | unsigned int len = (nlongs - 1) * sizeof(unsigned long); | ||
43 | memset(dst, 0xff, len); | ||
44 | } | ||
45 | dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); | ||
46 | } | ||
47 | |||
48 | static inline int bitmap_empty(const unsigned long *src, unsigned nbits) | ||
49 | { | ||
50 | if (small_const_nbits(nbits)) | ||
51 | return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); | ||
52 | |||
53 | return find_first_bit(src, nbits) == nbits; | ||
54 | } | ||
55 | |||
56 | static inline int bitmap_full(const unsigned long *src, unsigned int nbits) | ||
57 | { | ||
58 | if (small_const_nbits(nbits)) | ||
59 | return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); | ||
60 | |||
61 | return find_first_zero_bit(src, nbits) == nbits; | ||
62 | } | ||
63 | |||
38 | static inline int bitmap_weight(const unsigned long *src, int nbits) | 64 | static inline int bitmap_weight(const unsigned long *src, int nbits) |
39 | { | 65 | { |
40 | if (small_const_nbits(nbits)) | 66 | if (small_const_nbits(nbits)) |
diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h index 8ebf6278b2ef..c24b3e3ae296 100644 --- a/tools/include/linux/types.h +++ b/tools/include/linux/types.h | |||
@@ -42,11 +42,7 @@ typedef __s8 s8; | |||
42 | #else | 42 | #else |
43 | #define __bitwise__ | 43 | #define __bitwise__ |
44 | #endif | 44 | #endif |
45 | #ifdef __CHECK_ENDIAN__ | ||
46 | #define __bitwise __bitwise__ | 45 | #define __bitwise __bitwise__ |
47 | #else | ||
48 | #define __bitwise | ||
49 | #endif | ||
50 | 46 | ||
51 | #define __force | 47 | #define __force |
52 | #define __user | 48 | #define __user |
diff --git a/tools/include/uapi/linux/hw_breakpoint.h b/tools/include/uapi/linux/hw_breakpoint.h index b04000a2296a..2b65efd19a46 100644 --- a/tools/include/uapi/linux/hw_breakpoint.h +++ b/tools/include/uapi/linux/hw_breakpoint.h | |||
@@ -4,7 +4,11 @@ | |||
4 | enum { | 4 | enum { |
5 | HW_BREAKPOINT_LEN_1 = 1, | 5 | HW_BREAKPOINT_LEN_1 = 1, |
6 | HW_BREAKPOINT_LEN_2 = 2, | 6 | HW_BREAKPOINT_LEN_2 = 2, |
7 | HW_BREAKPOINT_LEN_3 = 3, | ||
7 | HW_BREAKPOINT_LEN_4 = 4, | 8 | HW_BREAKPOINT_LEN_4 = 4, |
9 | HW_BREAKPOINT_LEN_5 = 5, | ||
10 | HW_BREAKPOINT_LEN_6 = 6, | ||
11 | HW_BREAKPOINT_LEN_7 = 7, | ||
8 | HW_BREAKPOINT_LEN_8 = 8, | 12 | HW_BREAKPOINT_LEN_8 = 8, |
9 | }; | 13 | }; |
10 | 14 | ||
diff --git a/tools/leds/.gitignore b/tools/leds/.gitignore new file mode 100644 index 000000000000..ac96d9f53dfc --- /dev/null +++ b/tools/leds/.gitignore | |||
@@ -0,0 +1 @@ | |||
uledmon | |||
diff --git a/tools/leds/Makefile b/tools/leds/Makefile new file mode 100644 index 000000000000..c03a79ebf9c8 --- /dev/null +++ b/tools/leds/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # Makefile for LEDs tools | ||
2 | |||
3 | CC = $(CROSS_COMPILE)gcc | ||
4 | CFLAGS = -Wall -Wextra -g -I../../include/uapi | ||
5 | |||
6 | all: uledmon | ||
7 | %: %.c | ||
8 | $(CC) $(CFLAGS) -o $@ $^ | ||
9 | |||
10 | clean: | ||
11 | $(RM) uledmon | ||
12 | |||
13 | .PHONY: all clean | ||
diff --git a/tools/leds/uledmon.c b/tools/leds/uledmon.c new file mode 100644 index 000000000000..25cbc7acf50a --- /dev/null +++ b/tools/leds/uledmon.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * uledmon.c | ||
3 | * | ||
4 | * This program creates a new userspace LED class device and monitors it. A | ||
5 | * timestamp and brightness value is printed each time the brightness changes. | ||
6 | * | ||
7 | * Usage: uledmon <device-name> | ||
8 | * | ||
9 | * <device-name> is the name of the LED class device to be created. Pressing | ||
10 | * CTRL+C will exit. | ||
11 | */ | ||
12 | |||
13 | #include <fcntl.h> | ||
14 | #include <stdio.h> | ||
15 | #include <string.h> | ||
16 | #include <time.h> | ||
17 | #include <unistd.h> | ||
18 | |||
19 | #include <linux/uleds.h> | ||
20 | |||
21 | int main(int argc, char const *argv[]) | ||
22 | { | ||
23 | struct uleds_user_dev uleds_dev; | ||
24 | int fd, ret; | ||
25 | int brightness; | ||
26 | struct timespec ts; | ||
27 | |||
28 | if (argc != 2) { | ||
29 | fprintf(stderr, "Requires <device-name> argument\n"); | ||
30 | return 1; | ||
31 | } | ||
32 | |||
33 | strncpy(uleds_dev.name, argv[1], LED_MAX_NAME_SIZE); | ||
34 | uleds_dev.max_brightness = 100; | ||
35 | |||
36 | fd = open("/dev/uleds", O_RDWR); | ||
37 | if (fd == -1) { | ||
38 | perror("Failed to open /dev/uleds"); | ||
39 | return 1; | ||
40 | } | ||
41 | |||
42 | ret = write(fd, &uleds_dev, sizeof(uleds_dev)); | ||
43 | if (ret == -1) { | ||
44 | perror("Failed to write to /dev/uleds"); | ||
45 | close(fd); | ||
46 | return 1; | ||
47 | } | ||
48 | |||
49 | while (1) { | ||
50 | ret = read(fd, &brightness, sizeof(brightness)); | ||
51 | if (ret == -1) { | ||
52 | perror("Failed to read from /dev/uleds"); | ||
53 | close(fd); | ||
54 | return 1; | ||
55 | } | ||
56 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
57 | printf("[%ld.%09ld] %u\n", ts.tv_sec, ts.tv_nsec, brightness); | ||
58 | } | ||
59 | |||
60 | close(fd); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index 0a6fda9837f7..adba83b325d5 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile | |||
@@ -2,7 +2,7 @@ include ../../scripts/Makefile.include | |||
2 | include ../../scripts/utilities.mak # QUIET_CLEAN | 2 | include ../../scripts/utilities.mak # QUIET_CLEAN |
3 | 3 | ||
4 | ifeq ($(srctree),) | 4 | ifeq ($(srctree),) |
5 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 5 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
6 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 6 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
7 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 7 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
8 | #$(info Determined 'srctree' to be $(srctree)) | 8 | #$(info Determined 'srctree' to be $(srctree)) |
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 62d89d50fcbd..e2efddf10231 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile | |||
@@ -7,7 +7,7 @@ BPF_EXTRAVERSION = 1 | |||
7 | MAKEFLAGS += --no-print-directory | 7 | MAKEFLAGS += --no-print-directory |
8 | 8 | ||
9 | ifeq ($(srctree),) | 9 | ifeq ($(srctree),) |
10 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 10 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
11 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 11 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
12 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 12 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
13 | #$(info Determined 'srctree' to be $(srctree)) | 13 | #$(info Determined 'srctree' to be $(srctree)) |
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index 1d57af56814b..3bc0ef9f8923 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile | |||
@@ -50,7 +50,7 @@ ifndef VERBOSE | |||
50 | endif | 50 | endif |
51 | 51 | ||
52 | ifeq ($(srctree),) | 52 | ifeq ($(srctree),) |
53 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 53 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
54 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 54 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
55 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 55 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
56 | #$(info Determined 'srctree' to be $(srctree)) | 56 | #$(info Determined 'srctree' to be $(srctree)) |
diff --git a/tools/lib/subcmd/Makefile b/tools/lib/subcmd/Makefile index ce4b7e527566..3f8cc44a0dbd 100644 --- a/tools/lib/subcmd/Makefile +++ b/tools/lib/subcmd/Makefile | |||
@@ -2,7 +2,7 @@ include ../../scripts/Makefile.include | |||
2 | include ../../scripts/utilities.mak # QUIET_CLEAN | 2 | include ../../scripts/utilities.mak # QUIET_CLEAN |
3 | 3 | ||
4 | ifeq ($(srctree),) | 4 | ifeq ($(srctree),) |
5 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 5 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
6 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 6 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
7 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 7 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
8 | #$(info Determined 'srctree' to be $(srctree)) | 8 | #$(info Determined 'srctree' to be $(srctree)) |
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index c76012ebdb9c..2616c66e10c1 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
@@ -86,7 +86,7 @@ ifndef VERBOSE | |||
86 | endif | 86 | endif |
87 | 87 | ||
88 | ifeq ($(srctree),) | 88 | ifeq ($(srctree),) |
89 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 89 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
90 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 90 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
91 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 91 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
92 | #$(info Determined 'srctree' to be $(srctree)) | 92 | #$(info Determined 'srctree' to be $(srctree)) |
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 041b493ad3ab..27e019c09bd2 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile | |||
@@ -11,12 +11,12 @@ LD = ld | |||
11 | AR = ar | 11 | AR = ar |
12 | 12 | ||
13 | ifeq ($(srctree),) | 13 | ifeq ($(srctree),) |
14 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 14 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
15 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 15 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
16 | endif | 16 | endif |
17 | 17 | ||
18 | SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/ | 18 | SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/ |
19 | LIBSUBCMD_OUTPUT = $(if $(OUTPUT),$(OUTPUT),$(PWD)/) | 19 | LIBSUBCMD_OUTPUT = $(if $(OUTPUT),$(OUTPUT),$(CURDIR)/) |
20 | LIBSUBCMD = $(LIBSUBCMD_OUTPUT)libsubcmd.a | 20 | LIBSUBCMD = $(LIBSUBCMD_OUTPUT)libsubcmd.a |
21 | 21 | ||
22 | OBJTOOL := $(OUTPUT)objtool | 22 | OBJTOOL := $(OUTPUT)objtool |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 8f1c258b151a..e5af38eede17 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -100,7 +100,7 @@ LC_NUMERIC=C | |||
100 | export LC_COLLATE LC_NUMERIC | 100 | export LC_COLLATE LC_NUMERIC |
101 | 101 | ||
102 | ifeq ($(srctree),) | 102 | ifeq ($(srctree),) |
103 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 103 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
104 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 104 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
105 | #$(info Determined 'srctree' to be $(srctree)) | 105 | #$(info Determined 'srctree' to be $(srctree)) |
106 | endif | 106 | endif |
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 0784748f1670..e46723568516 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -42,7 +42,7 @@ LC_NUMERIC=C | |||
42 | export LC_COLLATE LC_NUMERIC | 42 | export LC_COLLATE LC_NUMERIC |
43 | 43 | ||
44 | ifeq ($(srctree),) | 44 | ifeq ($(srctree),) |
45 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 45 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) |
46 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 46 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
47 | #$(info Determined 'srctree' to be $(srctree)) | 47 | #$(info Determined 'srctree' to be $(srctree)) |
48 | endif | 48 | endif |
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c index 8d8003c919d4..10648aaf6164 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixxf.c +++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c | |||
@@ -646,8 +646,12 @@ acpi_os_create_semaphore(u32 max_units, | |||
646 | } | 646 | } |
647 | #ifdef __APPLE__ | 647 | #ifdef __APPLE__ |
648 | { | 648 | { |
649 | char *semaphore_name = tmpnam(NULL); | 649 | static int semaphore_count = 0; |
650 | char semaphore_name[32]; | ||
650 | 651 | ||
652 | snprintf(semaphore_name, sizeof(semaphore_name), "acpi_sem_%d", | ||
653 | semaphore_count++); | ||
654 | printf("%s\n", semaphore_name); | ||
651 | sem = | 655 | sem = |
652 | sem_open(semaphore_name, O_EXCL | O_CREAT, 0755, | 656 | sem_open(semaphore_name, O_EXCL | O_CREAT, 0755, |
653 | initial_units); | 657 | initial_units); |
@@ -692,10 +696,15 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle) | |||
692 | if (!sem) { | 696 | if (!sem) { |
693 | return (AE_BAD_PARAMETER); | 697 | return (AE_BAD_PARAMETER); |
694 | } | 698 | } |
695 | 699 | #ifdef __APPLE__ | |
700 | if (sem_close(sem) == -1) { | ||
701 | return (AE_BAD_PARAMETER); | ||
702 | } | ||
703 | #else | ||
696 | if (sem_destroy(sem) == -1) { | 704 | if (sem_destroy(sem) == -1) { |
697 | return (AE_BAD_PARAMETER); | 705 | return (AE_BAD_PARAMETER); |
698 | } | 706 | } |
707 | #endif | ||
699 | 708 | ||
700 | return (AE_OK); | 709 | return (AE_OK); |
701 | } | 710 | } |
diff --git a/tools/power/acpi/tools/ec/ec_access.c b/tools/power/acpi/tools/ec/ec_access.c index 6b8aaed44f2c..5f50642386db 100644 --- a/tools/power/acpi/tools/ec/ec_access.c +++ b/tools/power/acpi/tools/ec/ec_access.c | |||
@@ -46,7 +46,7 @@ void usage(char progname[], int exit_status) | |||
46 | puts("\t-b offset : Read value at byte_offset (in hex)"); | 46 | puts("\t-b offset : Read value at byte_offset (in hex)"); |
47 | puts("\t-w offset -v value : Write value at byte_offset"); | 47 | puts("\t-w offset -v value : Write value at byte_offset"); |
48 | puts("\t-h : Print this help\n\n"); | 48 | puts("\t-h : Print this help\n\n"); |
49 | puts("Offsets and values are in hexadecimal number sytem."); | 49 | puts("Offsets and values are in hexadecimal number system."); |
50 | puts("The offset and value must be between 0 and 0xff."); | 50 | puts("The offset and value must be between 0 and 0xff."); |
51 | exit(exit_status); | 51 | exit(exit_status); |
52 | } | 52 | } |
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index 8358863259c5..d6e1c02ddcfe 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -108,9 +108,6 @@ MKDIR = mkdir | |||
108 | # Now we set up the build system | 108 | # Now we set up the build system |
109 | # | 109 | # |
110 | 110 | ||
111 | # set up PWD so that older versions of make will work with our build. | ||
112 | PWD = $(shell pwd) | ||
113 | |||
114 | GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; done;} | 111 | GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; done;} |
115 | 112 | ||
116 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS | 113 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS |
diff --git a/tools/power/cpupower/debug/kernel/Makefile b/tools/power/cpupower/debug/kernel/Makefile index 96b146fe6f8d..a8a6f8eec5c2 100644 --- a/tools/power/cpupower/debug/kernel/Makefile +++ b/tools/power/cpupower/debug/kernel/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | obj-m := | 1 | obj-m := |
2 | 2 | ||
3 | KDIR := /lib/modules/$(shell uname -r)/build | 3 | KDIR := /lib/modules/$(shell uname -r)/build |
4 | PWD := $(shell pwd) | ||
5 | KMISC := /lib/modules/$(shell uname -r)/cpufrequtils/ | 4 | KMISC := /lib/modules/$(shell uname -r)/cpufrequtils/ |
6 | 5 | ||
7 | ifeq ("$(CONFIG_X86_TSC)", "y") | 6 | ifeq ("$(CONFIG_X86_TSC)", "y") |
@@ -9,7 +8,7 @@ ifeq ("$(CONFIG_X86_TSC)", "y") | |||
9 | endif | 8 | endif |
10 | 9 | ||
11 | default: | 10 | default: |
12 | $(MAKE) -C $(KDIR) M=$(PWD) | 11 | $(MAKE) -C $(KDIR) M=$(CURDIR) |
13 | 12 | ||
14 | clean: | 13 | clean: |
15 | - rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c | 14 | - rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c |
diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c index f046b77cfefe..816f119c9b7b 100644 --- a/tools/spi/spidev_test.c +++ b/tools/spi/spidev_test.c | |||
@@ -315,7 +315,7 @@ static void transfer_file(int fd, char *filename) | |||
315 | pabort("can't stat input file"); | 315 | pabort("can't stat input file"); |
316 | 316 | ||
317 | tx_fd = open(filename, O_RDONLY); | 317 | tx_fd = open(filename, O_RDONLY); |
318 | if (fd < 0) | 318 | if (tx_fd < 0) |
319 | pabort("can't open input file"); | 319 | pabort("can't open input file"); |
320 | 320 | ||
321 | tx = malloc(sb.st_size); | 321 | tx = malloc(sb.st_size); |
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index d08e214ec6e7..be93ab02b490 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -719,14 +719,14 @@ sub set_value { | |||
719 | 719 | ||
720 | if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { | 720 | if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { |
721 | # Note if a test is something other than build, then we | 721 | # Note if a test is something other than build, then we |
722 | # will need other manditory options. | 722 | # will need other mandatory options. |
723 | if ($prvalue ne "install") { | 723 | if ($prvalue ne "install") { |
724 | # for bisect, we need to check BISECT_TYPE | 724 | # for bisect, we need to check BISECT_TYPE |
725 | if ($prvalue ne "bisect") { | 725 | if ($prvalue ne "bisect") { |
726 | $buildonly = 0; | 726 | $buildonly = 0; |
727 | } | 727 | } |
728 | } else { | 728 | } else { |
729 | # install still limits some manditory options. | 729 | # install still limits some mandatory options. |
730 | $buildonly = 2; | 730 | $buildonly = 2; |
731 | } | 731 | } |
732 | } | 732 | } |
@@ -735,7 +735,7 @@ sub set_value { | |||
735 | if ($prvalue ne "install") { | 735 | if ($prvalue ne "install") { |
736 | $buildonly = 0; | 736 | $buildonly = 0; |
737 | } else { | 737 | } else { |
738 | # install still limits some manditory options. | 738 | # install still limits some mandatory options. |
739 | $buildonly = 2; | 739 | $buildonly = 2; |
740 | } | 740 | } |
741 | } | 741 | } |
@@ -3989,7 +3989,7 @@ sub make_min_config { | |||
3989 | } | 3989 | } |
3990 | } | 3990 | } |
3991 | 3991 | ||
3992 | # Save off all the current mandidory configs | 3992 | # Save off all the current mandatory configs |
3993 | open (OUT, ">$temp_config") | 3993 | open (OUT, ">$temp_config") |
3994 | or die "Can't write to $temp_config"; | 3994 | or die "Can't write to $temp_config"; |
3995 | foreach my $config (keys %keep_configs) { | 3995 | foreach my $config (keys %keep_configs) { |
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile index f2e07f2fd4b4..3635e4d3eca7 100644 --- a/tools/testing/radix-tree/Makefile +++ b/tools/testing/radix-tree/Makefile | |||
@@ -1,10 +1,14 @@ | |||
1 | 1 | ||
2 | CFLAGS += -I. -g -O2 -Wall -D_LGPL_SOURCE | 2 | CFLAGS += -I. -I../../include -g -O2 -Wall -D_LGPL_SOURCE |
3 | LDFLAGS += -lpthread -lurcu | 3 | LDFLAGS += -lpthread -lurcu |
4 | TARGETS = main | 4 | TARGETS = main |
5 | OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \ | 5 | OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \ |
6 | regression1.o regression2.o regression3.o multiorder.o \ | 6 | regression1.o regression2.o regression3.o multiorder.o \ |
7 | iteration_check.o | 7 | iteration_check.o benchmark.o |
8 | |||
9 | ifdef BENCHMARK | ||
10 | CFLAGS += -DBENCHMARK=1 | ||
11 | endif | ||
8 | 12 | ||
9 | targets: $(TARGETS) | 13 | targets: $(TARGETS) |
10 | 14 | ||
@@ -14,7 +18,12 @@ main: $(OFILES) | |||
14 | clean: | 18 | clean: |
15 | $(RM) -f $(TARGETS) *.o radix-tree.c | 19 | $(RM) -f $(TARGETS) *.o radix-tree.c |
16 | 20 | ||
17 | $(OFILES): *.h */*.h ../../../include/linux/radix-tree.h ../../include/linux/*.h | 21 | find_next_bit.o: ../../lib/find_bit.c |
22 | $(CC) $(CFLAGS) -c -o $@ $< | ||
23 | |||
24 | $(OFILES): *.h */*.h \ | ||
25 | ../../include/linux/*.h \ | ||
26 | ../../../include/linux/radix-tree.h | ||
18 | 27 | ||
19 | radix-tree.c: ../../../lib/radix-tree.c | 28 | radix-tree.c: ../../../lib/radix-tree.c |
20 | sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ | 29 | sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ |
diff --git a/tools/testing/radix-tree/benchmark.c b/tools/testing/radix-tree/benchmark.c new file mode 100644 index 000000000000..215ca86c7605 --- /dev/null +++ b/tools/testing/radix-tree/benchmark.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * benchmark.c: | ||
3 | * Author: Konstantin Khlebnikov <koct9i@gmail.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * 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 WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | #include <linux/radix-tree.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <time.h> | ||
18 | #include "test.h" | ||
19 | |||
20 | #define NSEC_PER_SEC 1000000000L | ||
21 | |||
22 | static long long benchmark_iter(struct radix_tree_root *root, bool tagged) | ||
23 | { | ||
24 | volatile unsigned long sink = 0; | ||
25 | struct radix_tree_iter iter; | ||
26 | struct timespec start, finish; | ||
27 | long long nsec; | ||
28 | int l, loops = 1; | ||
29 | void **slot; | ||
30 | |||
31 | #ifdef BENCHMARK | ||
32 | again: | ||
33 | #endif | ||
34 | clock_gettime(CLOCK_MONOTONIC, &start); | ||
35 | for (l = 0; l < loops; l++) { | ||
36 | if (tagged) { | ||
37 | radix_tree_for_each_tagged(slot, root, &iter, 0, 0) | ||
38 | sink ^= (unsigned long)slot; | ||
39 | } else { | ||
40 | radix_tree_for_each_slot(slot, root, &iter, 0) | ||
41 | sink ^= (unsigned long)slot; | ||
42 | } | ||
43 | } | ||
44 | clock_gettime(CLOCK_MONOTONIC, &finish); | ||
45 | |||
46 | nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC + | ||
47 | (finish.tv_nsec - start.tv_nsec); | ||
48 | |||
49 | #ifdef BENCHMARK | ||
50 | if (loops == 1 && nsec * 5 < NSEC_PER_SEC) { | ||
51 | loops = NSEC_PER_SEC / nsec / 4 + 1; | ||
52 | goto again; | ||
53 | } | ||
54 | #endif | ||
55 | |||
56 | nsec /= loops; | ||
57 | return nsec; | ||
58 | } | ||
59 | |||
60 | static void benchmark_size(unsigned long size, unsigned long step, int order) | ||
61 | { | ||
62 | RADIX_TREE(tree, GFP_KERNEL); | ||
63 | long long normal, tagged; | ||
64 | unsigned long index; | ||
65 | |||
66 | for (index = 0 ; index < size ; index += step) { | ||
67 | item_insert_order(&tree, index, order); | ||
68 | radix_tree_tag_set(&tree, index, 0); | ||
69 | } | ||
70 | |||
71 | tagged = benchmark_iter(&tree, true); | ||
72 | normal = benchmark_iter(&tree, false); | ||
73 | |||
74 | printf("Size %ld, step %6ld, order %d tagged %10lld ns, normal %10lld ns\n", | ||
75 | size, step, order, tagged, normal); | ||
76 | |||
77 | item_kill_tree(&tree); | ||
78 | rcu_barrier(); | ||
79 | } | ||
80 | |||
81 | void benchmark(void) | ||
82 | { | ||
83 | unsigned long size[] = {1 << 10, 1 << 20, 0}; | ||
84 | unsigned long step[] = {1, 2, 7, 15, 63, 64, 65, | ||
85 | 128, 256, 512, 12345, 0}; | ||
86 | int c, s; | ||
87 | |||
88 | printf("starting benchmarks\n"); | ||
89 | printf("RADIX_TREE_MAP_SHIFT = %d\n", RADIX_TREE_MAP_SHIFT); | ||
90 | |||
91 | for (c = 0; size[c]; c++) | ||
92 | for (s = 0; step[s]; s++) | ||
93 | benchmark_size(size[c], step[s], 0); | ||
94 | |||
95 | for (c = 0; size[c]; c++) | ||
96 | for (s = 0; step[s]; s++) | ||
97 | benchmark_size(size[c], step[s] << 9, 9); | ||
98 | } | ||
diff --git a/tools/testing/radix-tree/find_next_bit.c b/tools/testing/radix-tree/find_next_bit.c deleted file mode 100644 index d1c2178bb2d4..000000000000 --- a/tools/testing/radix-tree/find_next_bit.c +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | /* find_next_bit.c: fallback find next bit implementation | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
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 | #include <linux/types.h> | ||
13 | #include <linux/bitops.h> | ||
14 | |||
15 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | ||
16 | |||
17 | /* | ||
18 | * Find the next set bit in a memory region. | ||
19 | */ | ||
20 | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, | ||
21 | unsigned long offset) | ||
22 | { | ||
23 | const unsigned long *p = addr + BITOP_WORD(offset); | ||
24 | unsigned long result = offset & ~(BITS_PER_LONG-1); | ||
25 | unsigned long tmp; | ||
26 | |||
27 | if (offset >= size) | ||
28 | return size; | ||
29 | size -= result; | ||
30 | offset %= BITS_PER_LONG; | ||
31 | if (offset) { | ||
32 | tmp = *(p++); | ||
33 | tmp &= (~0UL << offset); | ||
34 | if (size < BITS_PER_LONG) | ||
35 | goto found_first; | ||
36 | if (tmp) | ||
37 | goto found_middle; | ||
38 | size -= BITS_PER_LONG; | ||
39 | result += BITS_PER_LONG; | ||
40 | } | ||
41 | while (size & ~(BITS_PER_LONG-1)) { | ||
42 | if ((tmp = *(p++))) | ||
43 | goto found_middle; | ||
44 | result += BITS_PER_LONG; | ||
45 | size -= BITS_PER_LONG; | ||
46 | } | ||
47 | if (!size) | ||
48 | return result; | ||
49 | tmp = *p; | ||
50 | |||
51 | found_first: | ||
52 | tmp &= (~0UL >> (BITS_PER_LONG - size)); | ||
53 | if (tmp == 0UL) /* Are any bits set? */ | ||
54 | return result + size; /* Nope. */ | ||
55 | found_middle: | ||
56 | return result + __ffs(tmp); | ||
57 | } | ||
diff --git a/tools/testing/radix-tree/iteration_check.c b/tools/testing/radix-tree/iteration_check.c index 9adb8e7415a6..7572b7ed930e 100644 --- a/tools/testing/radix-tree/iteration_check.c +++ b/tools/testing/radix-tree/iteration_check.c | |||
@@ -16,35 +16,50 @@ | |||
16 | #include <pthread.h> | 16 | #include <pthread.h> |
17 | #include "test.h" | 17 | #include "test.h" |
18 | 18 | ||
19 | #define NUM_THREADS 4 | 19 | #define NUM_THREADS 5 |
20 | #define TAG 0 | 20 | #define MAX_IDX 100 |
21 | #define TAG 0 | ||
22 | #define NEW_TAG 1 | ||
23 | |||
21 | static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER; | 24 | static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER; |
22 | static pthread_t threads[NUM_THREADS]; | 25 | static pthread_t threads[NUM_THREADS]; |
23 | RADIX_TREE(tree, GFP_KERNEL); | 26 | static unsigned int seeds[3]; |
24 | bool test_complete; | 27 | static RADIX_TREE(tree, GFP_KERNEL); |
28 | static bool test_complete; | ||
29 | static int max_order; | ||
25 | 30 | ||
26 | /* relentlessly fill the tree with tagged entries */ | 31 | /* relentlessly fill the tree with tagged entries */ |
27 | static void *add_entries_fn(void *arg) | 32 | static void *add_entries_fn(void *arg) |
28 | { | 33 | { |
29 | int pgoff; | 34 | rcu_register_thread(); |
30 | 35 | ||
31 | while (!test_complete) { | 36 | while (!test_complete) { |
32 | for (pgoff = 0; pgoff < 100; pgoff++) { | 37 | unsigned long pgoff; |
38 | int order; | ||
39 | |||
40 | for (pgoff = 0; pgoff < MAX_IDX; pgoff++) { | ||
33 | pthread_mutex_lock(&tree_lock); | 41 | pthread_mutex_lock(&tree_lock); |
34 | if (item_insert(&tree, pgoff) == 0) | 42 | for (order = max_order; order >= 0; order--) { |
35 | item_tag_set(&tree, pgoff, TAG); | 43 | if (item_insert_order(&tree, pgoff, order) |
44 | == 0) { | ||
45 | item_tag_set(&tree, pgoff, TAG); | ||
46 | break; | ||
47 | } | ||
48 | } | ||
36 | pthread_mutex_unlock(&tree_lock); | 49 | pthread_mutex_unlock(&tree_lock); |
37 | } | 50 | } |
38 | } | 51 | } |
39 | 52 | ||
53 | rcu_unregister_thread(); | ||
54 | |||
40 | return NULL; | 55 | return NULL; |
41 | } | 56 | } |
42 | 57 | ||
43 | /* | 58 | /* |
44 | * Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find | 59 | * Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find |
45 | * things that have been removed and randomly resetting our iteration to the | 60 | * things that have been removed and randomly resetting our iteration to the |
46 | * next chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and | 61 | * next chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and |
47 | * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a | 62 | * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a |
48 | * NULL 'slot' variable. | 63 | * NULL 'slot' variable. |
49 | */ | 64 | */ |
50 | static void *tagged_iteration_fn(void *arg) | 65 | static void *tagged_iteration_fn(void *arg) |
@@ -52,17 +67,12 @@ static void *tagged_iteration_fn(void *arg) | |||
52 | struct radix_tree_iter iter; | 67 | struct radix_tree_iter iter; |
53 | void **slot; | 68 | void **slot; |
54 | 69 | ||
70 | rcu_register_thread(); | ||
71 | |||
55 | while (!test_complete) { | 72 | while (!test_complete) { |
56 | rcu_read_lock(); | 73 | rcu_read_lock(); |
57 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) { | 74 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) { |
58 | void *entry; | 75 | void *entry = radix_tree_deref_slot(slot); |
59 | int i; | ||
60 | |||
61 | /* busy wait to let removals happen */ | ||
62 | for (i = 0; i < 1000000; i++) | ||
63 | ; | ||
64 | |||
65 | entry = radix_tree_deref_slot(slot); | ||
66 | if (unlikely(!entry)) | 76 | if (unlikely(!entry)) |
67 | continue; | 77 | continue; |
68 | 78 | ||
@@ -71,20 +81,26 @@ static void *tagged_iteration_fn(void *arg) | |||
71 | continue; | 81 | continue; |
72 | } | 82 | } |
73 | 83 | ||
74 | if (rand() % 50 == 0) | 84 | if (rand_r(&seeds[0]) % 50 == 0) { |
75 | slot = radix_tree_iter_next(&iter); | 85 | slot = radix_tree_iter_resume(slot, &iter); |
86 | rcu_read_unlock(); | ||
87 | rcu_barrier(); | ||
88 | rcu_read_lock(); | ||
89 | } | ||
76 | } | 90 | } |
77 | rcu_read_unlock(); | 91 | rcu_read_unlock(); |
78 | } | 92 | } |
79 | 93 | ||
94 | rcu_unregister_thread(); | ||
95 | |||
80 | return NULL; | 96 | return NULL; |
81 | } | 97 | } |
82 | 98 | ||
83 | /* | 99 | /* |
84 | * Iterate over the entries, doing a radix_tree_iter_retry() as we find things | 100 | * Iterate over the entries, doing a radix_tree_iter_retry() as we find things |
85 | * that have been removed and randomly resetting our iteration to the next | 101 | * that have been removed and randomly resetting our iteration to the next |
86 | * chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and | 102 | * chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and |
87 | * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a | 103 | * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a |
88 | * NULL 'slot' variable. | 104 | * NULL 'slot' variable. |
89 | */ | 105 | */ |
90 | static void *untagged_iteration_fn(void *arg) | 106 | static void *untagged_iteration_fn(void *arg) |
@@ -92,17 +108,12 @@ static void *untagged_iteration_fn(void *arg) | |||
92 | struct radix_tree_iter iter; | 108 | struct radix_tree_iter iter; |
93 | void **slot; | 109 | void **slot; |
94 | 110 | ||
111 | rcu_register_thread(); | ||
112 | |||
95 | while (!test_complete) { | 113 | while (!test_complete) { |
96 | rcu_read_lock(); | 114 | rcu_read_lock(); |
97 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | 115 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { |
98 | void *entry; | 116 | void *entry = radix_tree_deref_slot(slot); |
99 | int i; | ||
100 | |||
101 | /* busy wait to let removals happen */ | ||
102 | for (i = 0; i < 1000000; i++) | ||
103 | ; | ||
104 | |||
105 | entry = radix_tree_deref_slot(slot); | ||
106 | if (unlikely(!entry)) | 117 | if (unlikely(!entry)) |
107 | continue; | 118 | continue; |
108 | 119 | ||
@@ -111,12 +122,18 @@ static void *untagged_iteration_fn(void *arg) | |||
111 | continue; | 122 | continue; |
112 | } | 123 | } |
113 | 124 | ||
114 | if (rand() % 50 == 0) | 125 | if (rand_r(&seeds[1]) % 50 == 0) { |
115 | slot = radix_tree_iter_next(&iter); | 126 | slot = radix_tree_iter_resume(slot, &iter); |
127 | rcu_read_unlock(); | ||
128 | rcu_barrier(); | ||
129 | rcu_read_lock(); | ||
130 | } | ||
116 | } | 131 | } |
117 | rcu_read_unlock(); | 132 | rcu_read_unlock(); |
118 | } | 133 | } |
119 | 134 | ||
135 | rcu_unregister_thread(); | ||
136 | |||
120 | return NULL; | 137 | return NULL; |
121 | } | 138 | } |
122 | 139 | ||
@@ -126,47 +143,71 @@ static void *untagged_iteration_fn(void *arg) | |||
126 | */ | 143 | */ |
127 | static void *remove_entries_fn(void *arg) | 144 | static void *remove_entries_fn(void *arg) |
128 | { | 145 | { |
146 | rcu_register_thread(); | ||
147 | |||
129 | while (!test_complete) { | 148 | while (!test_complete) { |
130 | int pgoff; | 149 | int pgoff; |
131 | 150 | ||
132 | pgoff = rand() % 100; | 151 | pgoff = rand_r(&seeds[2]) % MAX_IDX; |
133 | 152 | ||
134 | pthread_mutex_lock(&tree_lock); | 153 | pthread_mutex_lock(&tree_lock); |
135 | item_delete(&tree, pgoff); | 154 | item_delete(&tree, pgoff); |
136 | pthread_mutex_unlock(&tree_lock); | 155 | pthread_mutex_unlock(&tree_lock); |
137 | } | 156 | } |
138 | 157 | ||
158 | rcu_unregister_thread(); | ||
159 | |||
160 | return NULL; | ||
161 | } | ||
162 | |||
163 | static void *tag_entries_fn(void *arg) | ||
164 | { | ||
165 | rcu_register_thread(); | ||
166 | |||
167 | while (!test_complete) { | ||
168 | tag_tagged_items(&tree, &tree_lock, 0, MAX_IDX, 10, TAG, | ||
169 | NEW_TAG); | ||
170 | } | ||
171 | rcu_unregister_thread(); | ||
139 | return NULL; | 172 | return NULL; |
140 | } | 173 | } |
141 | 174 | ||
142 | /* This is a unit test for a bug found by the syzkaller tester */ | 175 | /* This is a unit test for a bug found by the syzkaller tester */ |
143 | void iteration_test(void) | 176 | void iteration_test(unsigned order, unsigned test_duration) |
144 | { | 177 | { |
145 | int i; | 178 | int i; |
146 | 179 | ||
147 | printf("Running iteration tests for 10 seconds\n"); | 180 | printf("Running %siteration tests for %d seconds\n", |
181 | order > 0 ? "multiorder " : "", test_duration); | ||
148 | 182 | ||
149 | srand(time(0)); | 183 | max_order = order; |
150 | test_complete = false; | 184 | test_complete = false; |
151 | 185 | ||
186 | for (i = 0; i < 3; i++) | ||
187 | seeds[i] = rand(); | ||
188 | |||
152 | if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) { | 189 | if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) { |
153 | perror("pthread_create"); | 190 | perror("create tagged iteration thread"); |
154 | exit(1); | 191 | exit(1); |
155 | } | 192 | } |
156 | if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) { | 193 | if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) { |
157 | perror("pthread_create"); | 194 | perror("create untagged iteration thread"); |
158 | exit(1); | 195 | exit(1); |
159 | } | 196 | } |
160 | if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) { | 197 | if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) { |
161 | perror("pthread_create"); | 198 | perror("create add entry thread"); |
162 | exit(1); | 199 | exit(1); |
163 | } | 200 | } |
164 | if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) { | 201 | if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) { |
165 | perror("pthread_create"); | 202 | perror("create remove entry thread"); |
203 | exit(1); | ||
204 | } | ||
205 | if (pthread_create(&threads[4], NULL, tag_entries_fn, NULL)) { | ||
206 | perror("create tag entry thread"); | ||
166 | exit(1); | 207 | exit(1); |
167 | } | 208 | } |
168 | 209 | ||
169 | sleep(10); | 210 | sleep(test_duration); |
170 | test_complete = true; | 211 | test_complete = true; |
171 | 212 | ||
172 | for (i = 0; i < NUM_THREADS; i++) { | 213 | for (i = 0; i < NUM_THREADS; i++) { |
diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c index 154823737b20..d31ea7c9abec 100644 --- a/tools/testing/radix-tree/linux.c +++ b/tools/testing/radix-tree/linux.c | |||
@@ -1,14 +1,26 @@ | |||
1 | #include <stdlib.h> | 1 | #include <stdlib.h> |
2 | #include <string.h> | 2 | #include <string.h> |
3 | #include <malloc.h> | 3 | #include <malloc.h> |
4 | #include <pthread.h> | ||
4 | #include <unistd.h> | 5 | #include <unistd.h> |
5 | #include <assert.h> | 6 | #include <assert.h> |
6 | 7 | ||
7 | #include <linux/mempool.h> | 8 | #include <linux/mempool.h> |
9 | #include <linux/poison.h> | ||
8 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
11 | #include <linux/radix-tree.h> | ||
9 | #include <urcu/uatomic.h> | 12 | #include <urcu/uatomic.h> |
10 | 13 | ||
11 | int nr_allocated; | 14 | int nr_allocated; |
15 | int preempt_count; | ||
16 | |||
17 | struct kmem_cache { | ||
18 | pthread_mutex_t lock; | ||
19 | int size; | ||
20 | int nr_objs; | ||
21 | void *objs; | ||
22 | void (*ctor)(void *); | ||
23 | }; | ||
12 | 24 | ||
13 | void *mempool_alloc(mempool_t *pool, int gfp_mask) | 25 | void *mempool_alloc(mempool_t *pool, int gfp_mask) |
14 | { | 26 | { |
@@ -33,19 +45,59 @@ mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, | |||
33 | 45 | ||
34 | void *kmem_cache_alloc(struct kmem_cache *cachep, int flags) | 46 | void *kmem_cache_alloc(struct kmem_cache *cachep, int flags) |
35 | { | 47 | { |
36 | void *ret = malloc(cachep->size); | 48 | struct radix_tree_node *node; |
37 | if (cachep->ctor) | 49 | |
38 | cachep->ctor(ret); | 50 | if (flags & __GFP_NOWARN) |
51 | return NULL; | ||
52 | |||
53 | pthread_mutex_lock(&cachep->lock); | ||
54 | if (cachep->nr_objs) { | ||
55 | cachep->nr_objs--; | ||
56 | node = cachep->objs; | ||
57 | cachep->objs = node->private_data; | ||
58 | pthread_mutex_unlock(&cachep->lock); | ||
59 | node->private_data = NULL; | ||
60 | } else { | ||
61 | pthread_mutex_unlock(&cachep->lock); | ||
62 | node = malloc(cachep->size); | ||
63 | if (cachep->ctor) | ||
64 | cachep->ctor(node); | ||
65 | } | ||
66 | |||
39 | uatomic_inc(&nr_allocated); | 67 | uatomic_inc(&nr_allocated); |
40 | return ret; | 68 | return node; |
41 | } | 69 | } |
42 | 70 | ||
43 | void kmem_cache_free(struct kmem_cache *cachep, void *objp) | 71 | void kmem_cache_free(struct kmem_cache *cachep, void *objp) |
44 | { | 72 | { |
45 | assert(objp); | 73 | assert(objp); |
46 | uatomic_dec(&nr_allocated); | 74 | uatomic_dec(&nr_allocated); |
47 | memset(objp, 0, cachep->size); | 75 | pthread_mutex_lock(&cachep->lock); |
48 | free(objp); | 76 | if (cachep->nr_objs > 10) { |
77 | memset(objp, POISON_FREE, cachep->size); | ||
78 | free(objp); | ||
79 | } else { | ||
80 | struct radix_tree_node *node = objp; | ||
81 | cachep->nr_objs++; | ||
82 | node->private_data = cachep->objs; | ||
83 | cachep->objs = node; | ||
84 | } | ||
85 | pthread_mutex_unlock(&cachep->lock); | ||
86 | } | ||
87 | |||
88 | void *kmalloc(size_t size, gfp_t gfp) | ||
89 | { | ||
90 | void *ret = malloc(size); | ||
91 | uatomic_inc(&nr_allocated); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | void kfree(void *p) | ||
96 | { | ||
97 | if (!p) | ||
98 | return; | ||
99 | uatomic_dec(&nr_allocated); | ||
100 | free(p); | ||
49 | } | 101 | } |
50 | 102 | ||
51 | struct kmem_cache * | 103 | struct kmem_cache * |
@@ -54,7 +106,10 @@ kmem_cache_create(const char *name, size_t size, size_t offset, | |||
54 | { | 106 | { |
55 | struct kmem_cache *ret = malloc(sizeof(*ret)); | 107 | struct kmem_cache *ret = malloc(sizeof(*ret)); |
56 | 108 | ||
109 | pthread_mutex_init(&ret->lock, NULL); | ||
57 | ret->size = size; | 110 | ret->size = size; |
111 | ret->nr_objs = 0; | ||
112 | ret->objs = NULL; | ||
58 | ret->ctor = ctor; | 113 | ret->ctor = ctor; |
59 | return ret; | 114 | return ret; |
60 | } | 115 | } |
diff --git a/tools/testing/radix-tree/linux/bitops.h b/tools/testing/radix-tree/linux/bitops.h index 71d58427ab60..a13e9bc76eec 100644 --- a/tools/testing/radix-tree/linux/bitops.h +++ b/tools/testing/radix-tree/linux/bitops.h | |||
@@ -2,9 +2,14 @@ | |||
2 | #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ | 2 | #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/bitops/find.h> | ||
6 | #include <linux/bitops/hweight.h> | ||
7 | #include <linux/kernel.h> | ||
5 | 8 | ||
6 | #define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) | 9 | #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) |
7 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | 10 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) |
11 | #define BITS_PER_BYTE 8 | ||
12 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) | ||
8 | 13 | ||
9 | /** | 14 | /** |
10 | * __set_bit - Set a bit in memory | 15 | * __set_bit - Set a bit in memory |
@@ -17,16 +22,16 @@ | |||
17 | */ | 22 | */ |
18 | static inline void __set_bit(int nr, volatile unsigned long *addr) | 23 | static inline void __set_bit(int nr, volatile unsigned long *addr) |
19 | { | 24 | { |
20 | unsigned long mask = BITOP_MASK(nr); | 25 | unsigned long mask = BIT_MASK(nr); |
21 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 26 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
22 | 27 | ||
23 | *p |= mask; | 28 | *p |= mask; |
24 | } | 29 | } |
25 | 30 | ||
26 | static inline void __clear_bit(int nr, volatile unsigned long *addr) | 31 | static inline void __clear_bit(int nr, volatile unsigned long *addr) |
27 | { | 32 | { |
28 | unsigned long mask = BITOP_MASK(nr); | 33 | unsigned long mask = BIT_MASK(nr); |
29 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 34 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
30 | 35 | ||
31 | *p &= ~mask; | 36 | *p &= ~mask; |
32 | } | 37 | } |
@@ -42,8 +47,8 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr) | |||
42 | */ | 47 | */ |
43 | static inline void __change_bit(int nr, volatile unsigned long *addr) | 48 | static inline void __change_bit(int nr, volatile unsigned long *addr) |
44 | { | 49 | { |
45 | unsigned long mask = BITOP_MASK(nr); | 50 | unsigned long mask = BIT_MASK(nr); |
46 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 51 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
47 | 52 | ||
48 | *p ^= mask; | 53 | *p ^= mask; |
49 | } | 54 | } |
@@ -59,8 +64,8 @@ static inline void __change_bit(int nr, volatile unsigned long *addr) | |||
59 | */ | 64 | */ |
60 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | 65 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) |
61 | { | 66 | { |
62 | unsigned long mask = BITOP_MASK(nr); | 67 | unsigned long mask = BIT_MASK(nr); |
63 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 68 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
64 | unsigned long old = *p; | 69 | unsigned long old = *p; |
65 | 70 | ||
66 | *p = old | mask; | 71 | *p = old | mask; |
@@ -78,8 +83,8 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | |||
78 | */ | 83 | */ |
79 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | 84 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) |
80 | { | 85 | { |
81 | unsigned long mask = BITOP_MASK(nr); | 86 | unsigned long mask = BIT_MASK(nr); |
82 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 87 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
83 | unsigned long old = *p; | 88 | unsigned long old = *p; |
84 | 89 | ||
85 | *p = old & ~mask; | 90 | *p = old & ~mask; |
@@ -90,8 +95,8 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | |||
90 | static inline int __test_and_change_bit(int nr, | 95 | static inline int __test_and_change_bit(int nr, |
91 | volatile unsigned long *addr) | 96 | volatile unsigned long *addr) |
92 | { | 97 | { |
93 | unsigned long mask = BITOP_MASK(nr); | 98 | unsigned long mask = BIT_MASK(nr); |
94 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 99 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
95 | unsigned long old = *p; | 100 | unsigned long old = *p; |
96 | 101 | ||
97 | *p = old ^ mask; | 102 | *p = old ^ mask; |
@@ -105,7 +110,7 @@ static inline int __test_and_change_bit(int nr, | |||
105 | */ | 110 | */ |
106 | static inline int test_bit(int nr, const volatile unsigned long *addr) | 111 | static inline int test_bit(int nr, const volatile unsigned long *addr) |
107 | { | 112 | { |
108 | return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); | 113 | return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); |
109 | } | 114 | } |
110 | 115 | ||
111 | /** | 116 | /** |
@@ -147,4 +152,9 @@ unsigned long find_next_bit(const unsigned long *addr, | |||
147 | unsigned long size, | 152 | unsigned long size, |
148 | unsigned long offset); | 153 | unsigned long offset); |
149 | 154 | ||
155 | static inline unsigned long hweight_long(unsigned long w) | ||
156 | { | ||
157 | return sizeof(w) == 4 ? hweight32(w) : hweight64(w); | ||
158 | } | ||
159 | |||
150 | #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ | 160 | #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ |
diff --git a/tools/testing/radix-tree/linux/bitops/non-atomic.h b/tools/testing/radix-tree/linux/bitops/non-atomic.h index 46a825cf2ae1..6a1bcb9d2c4a 100644 --- a/tools/testing/radix-tree/linux/bitops/non-atomic.h +++ b/tools/testing/radix-tree/linux/bitops/non-atomic.h | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | #define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) | ||
7 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | 6 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) |
8 | 7 | ||
9 | /** | 8 | /** |
@@ -17,7 +16,7 @@ | |||
17 | */ | 16 | */ |
18 | static inline void __set_bit(int nr, volatile unsigned long *addr) | 17 | static inline void __set_bit(int nr, volatile unsigned long *addr) |
19 | { | 18 | { |
20 | unsigned long mask = BITOP_MASK(nr); | 19 | unsigned long mask = BIT_MASK(nr); |
21 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 20 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
22 | 21 | ||
23 | *p |= mask; | 22 | *p |= mask; |
@@ -25,7 +24,7 @@ static inline void __set_bit(int nr, volatile unsigned long *addr) | |||
25 | 24 | ||
26 | static inline void __clear_bit(int nr, volatile unsigned long *addr) | 25 | static inline void __clear_bit(int nr, volatile unsigned long *addr) |
27 | { | 26 | { |
28 | unsigned long mask = BITOP_MASK(nr); | 27 | unsigned long mask = BIT_MASK(nr); |
29 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 28 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
30 | 29 | ||
31 | *p &= ~mask; | 30 | *p &= ~mask; |
@@ -42,7 +41,7 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr) | |||
42 | */ | 41 | */ |
43 | static inline void __change_bit(int nr, volatile unsigned long *addr) | 42 | static inline void __change_bit(int nr, volatile unsigned long *addr) |
44 | { | 43 | { |
45 | unsigned long mask = BITOP_MASK(nr); | 44 | unsigned long mask = BIT_MASK(nr); |
46 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 45 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
47 | 46 | ||
48 | *p ^= mask; | 47 | *p ^= mask; |
@@ -59,7 +58,7 @@ static inline void __change_bit(int nr, volatile unsigned long *addr) | |||
59 | */ | 58 | */ |
60 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | 59 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) |
61 | { | 60 | { |
62 | unsigned long mask = BITOP_MASK(nr); | 61 | unsigned long mask = BIT_MASK(nr); |
63 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 62 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
64 | unsigned long old = *p; | 63 | unsigned long old = *p; |
65 | 64 | ||
@@ -78,7 +77,7 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | |||
78 | */ | 77 | */ |
79 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | 78 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) |
80 | { | 79 | { |
81 | unsigned long mask = BITOP_MASK(nr); | 80 | unsigned long mask = BIT_MASK(nr); |
82 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 81 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
83 | unsigned long old = *p; | 82 | unsigned long old = *p; |
84 | 83 | ||
@@ -90,7 +89,7 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | |||
90 | static inline int __test_and_change_bit(int nr, | 89 | static inline int __test_and_change_bit(int nr, |
91 | volatile unsigned long *addr) | 90 | volatile unsigned long *addr) |
92 | { | 91 | { |
93 | unsigned long mask = BITOP_MASK(nr); | 92 | unsigned long mask = BIT_MASK(nr); |
94 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 93 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
95 | unsigned long old = *p; | 94 | unsigned long old = *p; |
96 | 95 | ||
diff --git a/tools/testing/radix-tree/linux/bug.h b/tools/testing/radix-tree/linux/bug.h index ccbe444977df..23b8ed52f8c8 100644 --- a/tools/testing/radix-tree/linux/bug.h +++ b/tools/testing/radix-tree/linux/bug.h | |||
@@ -1 +1 @@ | |||
#define WARN_ON_ONCE(x) assert(x) | #include "asm/bug.h" | ||
diff --git a/tools/testing/radix-tree/linux/cpu.h b/tools/testing/radix-tree/linux/cpu.h index 7cf412103205..a45530d78107 100644 --- a/tools/testing/radix-tree/linux/cpu.h +++ b/tools/testing/radix-tree/linux/cpu.h | |||
@@ -1,21 +1 @@ | |||
1 | #define cpuhp_setup_state_nocalls(a, b, c, d) (0) | ||
2 | #define hotcpu_notifier(a, b) | ||
3 | |||
4 | #define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ | ||
5 | #define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */ | ||
6 | #define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */ | ||
7 | #define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ | ||
8 | #define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ | ||
9 | #define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ | ||
10 | #define CPU_POST_DEAD 0x0009 /* CPU (unsigned)v dead, cpu_hotplug | ||
11 | * lock is dropped */ | ||
12 | #define CPU_BROKEN 0x000C /* CPU (unsigned)v did not die properly, | ||
13 | * perhaps due to preemption. */ | ||
14 | #define CPU_TASKS_FROZEN 0x0010 | ||
15 | |||
16 | #define CPU_ONLINE_FROZEN (CPU_ONLINE | CPU_TASKS_FROZEN) | ||
17 | #define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN) | ||
18 | #define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN) | ||
19 | #define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN) | ||
20 | #define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN) | ||
21 | #define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN) | ||
diff --git a/tools/testing/radix-tree/linux/gfp.h b/tools/testing/radix-tree/linux/gfp.h index 5201b915f631..5b09b2ce6c33 100644 --- a/tools/testing/radix-tree/linux/gfp.h +++ b/tools/testing/radix-tree/linux/gfp.h | |||
@@ -3,8 +3,24 @@ | |||
3 | 3 | ||
4 | #define __GFP_BITS_SHIFT 26 | 4 | #define __GFP_BITS_SHIFT 26 |
5 | #define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) | 5 | #define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) |
6 | #define __GFP_WAIT 1 | 6 | |
7 | #define __GFP_ACCOUNT 0 | 7 | #define __GFP_HIGH 0x20u |
8 | #define __GFP_NOWARN 0 | 8 | #define __GFP_IO 0x40u |
9 | #define __GFP_FS 0x80u | ||
10 | #define __GFP_NOWARN 0x200u | ||
11 | #define __GFP_ATOMIC 0x80000u | ||
12 | #define __GFP_ACCOUNT 0x100000u | ||
13 | #define __GFP_DIRECT_RECLAIM 0x400000u | ||
14 | #define __GFP_KSWAPD_RECLAIM 0x2000000u | ||
15 | |||
16 | #define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM|__GFP_KSWAPD_RECLAIM) | ||
17 | |||
18 | #define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) | ||
19 | #define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) | ||
20 | |||
21 | static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags) | ||
22 | { | ||
23 | return !!(gfp_flags & __GFP_DIRECT_RECLAIM); | ||
24 | } | ||
9 | 25 | ||
10 | #endif | 26 | #endif |
diff --git a/tools/testing/radix-tree/linux/kernel.h b/tools/testing/radix-tree/linux/kernel.h index be98a47b4e1b..9b43b4975d83 100644 --- a/tools/testing/radix-tree/linux/kernel.h +++ b/tools/testing/radix-tree/linux/kernel.h | |||
@@ -8,9 +8,14 @@ | |||
8 | #include <limits.h> | 8 | #include <limits.h> |
9 | 9 | ||
10 | #include "../../include/linux/compiler.h" | 10 | #include "../../include/linux/compiler.h" |
11 | #include "../../include/linux/err.h" | ||
11 | #include "../../../include/linux/kconfig.h" | 12 | #include "../../../include/linux/kconfig.h" |
12 | 13 | ||
14 | #ifdef BENCHMARK | ||
15 | #define RADIX_TREE_MAP_SHIFT 6 | ||
16 | #else | ||
13 | #define RADIX_TREE_MAP_SHIFT 3 | 17 | #define RADIX_TREE_MAP_SHIFT 3 |
18 | #endif | ||
14 | 19 | ||
15 | #ifndef NULL | 20 | #ifndef NULL |
16 | #define NULL 0 | 21 | #define NULL 0 |
@@ -43,4 +48,17 @@ static inline int in_interrupt(void) | |||
43 | { | 48 | { |
44 | return 0; | 49 | return 0; |
45 | } | 50 | } |
51 | |||
52 | /* | ||
53 | * This looks more complex than it should be. But we need to | ||
54 | * get the type for the ~ right in round_down (it needs to be | ||
55 | * as wide as the result!), and we want to evaluate the macro | ||
56 | * arguments just once each. | ||
57 | */ | ||
58 | #define __round_mask(x, y) ((__typeof__(x))((y)-1)) | ||
59 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) | ||
60 | #define round_down(x, y) ((x) & ~__round_mask(x, y)) | ||
61 | |||
62 | #define xchg(ptr, x) uatomic_xchg(ptr, x) | ||
63 | |||
46 | #endif /* _KERNEL_H */ | 64 | #endif /* _KERNEL_H */ |
diff --git a/tools/testing/radix-tree/linux/notifier.h b/tools/testing/radix-tree/linux/notifier.h deleted file mode 100644 index 70e4797d5a46..000000000000 --- a/tools/testing/radix-tree/linux/notifier.h +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | #ifndef _NOTIFIER_H | ||
2 | #define _NOTIFIER_H | ||
3 | |||
4 | struct notifier_block; | ||
5 | |||
6 | #define NOTIFY_OK 0x0001 /* Suits me */ | ||
7 | |||
8 | #endif | ||
diff --git a/tools/testing/radix-tree/linux/preempt.h b/tools/testing/radix-tree/linux/preempt.h index 6210672e3baa..65c04c226965 100644 --- a/tools/testing/radix-tree/linux/preempt.h +++ b/tools/testing/radix-tree/linux/preempt.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* */ | 1 | extern int preempt_count; |
2 | 2 | ||
3 | #define preempt_disable() do { } while (0) | 3 | #define preempt_disable() uatomic_inc(&preempt_count) |
4 | #define preempt_enable() do { } while (0) | 4 | #define preempt_enable() uatomic_dec(&preempt_count) |
diff --git a/tools/testing/radix-tree/linux/slab.h b/tools/testing/radix-tree/linux/slab.h index 6d5a34770fd4..e40337f41a38 100644 --- a/tools/testing/radix-tree/linux/slab.h +++ b/tools/testing/radix-tree/linux/slab.h | |||
@@ -7,15 +7,8 @@ | |||
7 | #define SLAB_PANIC 2 | 7 | #define SLAB_PANIC 2 |
8 | #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ | 8 | #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ |
9 | 9 | ||
10 | static inline int gfpflags_allow_blocking(gfp_t mask) | 10 | void *kmalloc(size_t size, gfp_t); |
11 | { | 11 | void kfree(void *); |
12 | return 1; | ||
13 | } | ||
14 | |||
15 | struct kmem_cache { | ||
16 | int size; | ||
17 | void (*ctor)(void *); | ||
18 | }; | ||
19 | 12 | ||
20 | void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); | 13 | void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); |
21 | void kmem_cache_free(struct kmem_cache *cachep, void *objp); | 14 | void kmem_cache_free(struct kmem_cache *cachep, void *objp); |
diff --git a/tools/testing/radix-tree/linux/types.h b/tools/testing/radix-tree/linux/types.h index faa0b6ff9ca8..8491d89873bb 100644 --- a/tools/testing/radix-tree/linux/types.h +++ b/tools/testing/radix-tree/linux/types.h | |||
@@ -6,8 +6,6 @@ | |||
6 | #define __rcu | 6 | #define __rcu |
7 | #define __read_mostly | 7 | #define __read_mostly |
8 | 8 | ||
9 | #define BITS_PER_LONG (sizeof(long) * 8) | ||
10 | |||
11 | static inline void INIT_LIST_HEAD(struct list_head *list) | 9 | static inline void INIT_LIST_HEAD(struct list_head *list) |
12 | { | 10 | { |
13 | list->next = list; | 11 | list->next = list; |
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c index daa9010693e8..f7e9801a6754 100644 --- a/tools/testing/radix-tree/main.c +++ b/tools/testing/radix-tree/main.c | |||
@@ -67,7 +67,6 @@ void big_gang_check(bool long_run) | |||
67 | 67 | ||
68 | for (i = 0; i < (long_run ? 1000 : 3); i++) { | 68 | for (i = 0; i < (long_run ? 1000 : 3); i++) { |
69 | __big_gang_check(); | 69 | __big_gang_check(); |
70 | srand(time(0)); | ||
71 | printf("%d ", i); | 70 | printf("%d ", i); |
72 | fflush(stdout); | 71 | fflush(stdout); |
73 | } | 72 | } |
@@ -206,8 +205,7 @@ void copy_tag_check(void) | |||
206 | } | 205 | } |
207 | 206 | ||
208 | // printf("\ncopying tags...\n"); | 207 | // printf("\ncopying tags...\n"); |
209 | cur = start; | 208 | tagged = tag_tagged_items(&tree, NULL, start, end, ITEMS, 0, 1); |
210 | tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, ITEMS, 0, 1); | ||
211 | 209 | ||
212 | // printf("checking copied tags\n"); | 210 | // printf("checking copied tags\n"); |
213 | assert(tagged == count); | 211 | assert(tagged == count); |
@@ -215,16 +213,13 @@ void copy_tag_check(void) | |||
215 | 213 | ||
216 | /* Copy tags in several rounds */ | 214 | /* Copy tags in several rounds */ |
217 | // printf("\ncopying tags...\n"); | 215 | // printf("\ncopying tags...\n"); |
218 | cur = start; | 216 | tmp = rand() % (count / 10 + 2); |
219 | do { | 217 | tagged = tag_tagged_items(&tree, NULL, start, end, tmp, 0, 2); |
220 | tmp = rand() % (count/10+2); | 218 | assert(tagged == count); |
221 | tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, tmp, 0, 2); | ||
222 | } while (tmp == tagged); | ||
223 | 219 | ||
224 | // printf("%lu %lu %lu\n", tagged, tmp, count); | 220 | // printf("%lu %lu %lu\n", tagged, tmp, count); |
225 | // printf("checking copied tags\n"); | 221 | // printf("checking copied tags\n"); |
226 | check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2); | 222 | check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2); |
227 | assert(tagged < tmp); | ||
228 | verify_tag_consistency(&tree, 0); | 223 | verify_tag_consistency(&tree, 0); |
229 | verify_tag_consistency(&tree, 1); | 224 | verify_tag_consistency(&tree, 1); |
230 | verify_tag_consistency(&tree, 2); | 225 | verify_tag_consistency(&tree, 2); |
@@ -240,7 +235,7 @@ static void __locate_check(struct radix_tree_root *tree, unsigned long index, | |||
240 | 235 | ||
241 | item_insert_order(tree, index, order); | 236 | item_insert_order(tree, index, order); |
242 | item = item_lookup(tree, index); | 237 | item = item_lookup(tree, index); |
243 | index2 = radix_tree_locate_item(tree, item); | 238 | index2 = find_item(tree, item); |
244 | if (index != index2) { | 239 | if (index != index2) { |
245 | printf("index %ld order %d inserted; found %ld\n", | 240 | printf("index %ld order %d inserted; found %ld\n", |
246 | index, order, index2); | 241 | index, order, index2); |
@@ -274,17 +269,17 @@ static void locate_check(void) | |||
274 | index += (1UL << order)) { | 269 | index += (1UL << order)) { |
275 | __locate_check(&tree, index + offset, order); | 270 | __locate_check(&tree, index + offset, order); |
276 | } | 271 | } |
277 | if (radix_tree_locate_item(&tree, &tree) != -1) | 272 | if (find_item(&tree, &tree) != -1) |
278 | abort(); | 273 | abort(); |
279 | 274 | ||
280 | item_kill_tree(&tree); | 275 | item_kill_tree(&tree); |
281 | } | 276 | } |
282 | } | 277 | } |
283 | 278 | ||
284 | if (radix_tree_locate_item(&tree, &tree) != -1) | 279 | if (find_item(&tree, &tree) != -1) |
285 | abort(); | 280 | abort(); |
286 | __locate_check(&tree, -1, 0); | 281 | __locate_check(&tree, -1, 0); |
287 | if (radix_tree_locate_item(&tree, &tree) != -1) | 282 | if (find_item(&tree, &tree) != -1) |
288 | abort(); | 283 | abort(); |
289 | item_kill_tree(&tree); | 284 | item_kill_tree(&tree); |
290 | } | 285 | } |
@@ -293,50 +288,80 @@ static void single_thread_tests(bool long_run) | |||
293 | { | 288 | { |
294 | int i; | 289 | int i; |
295 | 290 | ||
296 | printf("starting single_thread_tests: %d allocated\n", nr_allocated); | 291 | printf("starting single_thread_tests: %d allocated, preempt %d\n", |
292 | nr_allocated, preempt_count); | ||
297 | multiorder_checks(); | 293 | multiorder_checks(); |
298 | printf("after multiorder_check: %d allocated\n", nr_allocated); | 294 | rcu_barrier(); |
295 | printf("after multiorder_check: %d allocated, preempt %d\n", | ||
296 | nr_allocated, preempt_count); | ||
299 | locate_check(); | 297 | locate_check(); |
300 | printf("after locate_check: %d allocated\n", nr_allocated); | 298 | rcu_barrier(); |
299 | printf("after locate_check: %d allocated, preempt %d\n", | ||
300 | nr_allocated, preempt_count); | ||
301 | tag_check(); | 301 | tag_check(); |
302 | printf("after tag_check: %d allocated\n", nr_allocated); | 302 | rcu_barrier(); |
303 | printf("after tag_check: %d allocated, preempt %d\n", | ||
304 | nr_allocated, preempt_count); | ||
303 | gang_check(); | 305 | gang_check(); |
304 | printf("after gang_check: %d allocated\n", nr_allocated); | 306 | rcu_barrier(); |
307 | printf("after gang_check: %d allocated, preempt %d\n", | ||
308 | nr_allocated, preempt_count); | ||
305 | add_and_check(); | 309 | add_and_check(); |
306 | printf("after add_and_check: %d allocated\n", nr_allocated); | 310 | rcu_barrier(); |
311 | printf("after add_and_check: %d allocated, preempt %d\n", | ||
312 | nr_allocated, preempt_count); | ||
307 | dynamic_height_check(); | 313 | dynamic_height_check(); |
308 | printf("after dynamic_height_check: %d allocated\n", nr_allocated); | 314 | rcu_barrier(); |
315 | printf("after dynamic_height_check: %d allocated, preempt %d\n", | ||
316 | nr_allocated, preempt_count); | ||
309 | big_gang_check(long_run); | 317 | big_gang_check(long_run); |
310 | printf("after big_gang_check: %d allocated\n", nr_allocated); | 318 | rcu_barrier(); |
319 | printf("after big_gang_check: %d allocated, preempt %d\n", | ||
320 | nr_allocated, preempt_count); | ||
311 | for (i = 0; i < (long_run ? 2000 : 3); i++) { | 321 | for (i = 0; i < (long_run ? 2000 : 3); i++) { |
312 | copy_tag_check(); | 322 | copy_tag_check(); |
313 | printf("%d ", i); | 323 | printf("%d ", i); |
314 | fflush(stdout); | 324 | fflush(stdout); |
315 | } | 325 | } |
316 | printf("after copy_tag_check: %d allocated\n", nr_allocated); | 326 | rcu_barrier(); |
327 | printf("after copy_tag_check: %d allocated, preempt %d\n", | ||
328 | nr_allocated, preempt_count); | ||
317 | } | 329 | } |
318 | 330 | ||
319 | int main(int argc, char **argv) | 331 | int main(int argc, char **argv) |
320 | { | 332 | { |
321 | bool long_run = false; | 333 | bool long_run = false; |
322 | int opt; | 334 | int opt; |
335 | unsigned int seed = time(NULL); | ||
323 | 336 | ||
324 | while ((opt = getopt(argc, argv, "l")) != -1) { | 337 | while ((opt = getopt(argc, argv, "ls:")) != -1) { |
325 | if (opt == 'l') | 338 | if (opt == 'l') |
326 | long_run = true; | 339 | long_run = true; |
340 | else if (opt == 's') | ||
341 | seed = strtoul(optarg, NULL, 0); | ||
327 | } | 342 | } |
328 | 343 | ||
344 | printf("random seed %u\n", seed); | ||
345 | srand(seed); | ||
346 | |||
329 | rcu_register_thread(); | 347 | rcu_register_thread(); |
330 | radix_tree_init(); | 348 | radix_tree_init(); |
331 | 349 | ||
332 | regression1_test(); | 350 | regression1_test(); |
333 | regression2_test(); | 351 | regression2_test(); |
334 | regression3_test(); | 352 | regression3_test(); |
335 | iteration_test(); | 353 | iteration_test(0, 10); |
354 | iteration_test(7, 20); | ||
336 | single_thread_tests(long_run); | 355 | single_thread_tests(long_run); |
337 | 356 | ||
338 | sleep(1); | 357 | /* Free any remaining preallocated nodes */ |
339 | printf("after sleep(1): %d allocated\n", nr_allocated); | 358 | radix_tree_cpu_dead(0); |
359 | |||
360 | benchmark(); | ||
361 | |||
362 | rcu_barrier(); | ||
363 | printf("after rcu_barrier: %d allocated, preempt %d\n", | ||
364 | nr_allocated, preempt_count); | ||
340 | rcu_unregister_thread(); | 365 | rcu_unregister_thread(); |
341 | 366 | ||
342 | exit(0); | 367 | exit(0); |
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c index 05d7bc488971..f79812a5e070 100644 --- a/tools/testing/radix-tree/multiorder.c +++ b/tools/testing/radix-tree/multiorder.c | |||
@@ -26,7 +26,6 @@ static void __multiorder_tag_test(int index, int order) | |||
26 | { | 26 | { |
27 | RADIX_TREE(tree, GFP_KERNEL); | 27 | RADIX_TREE(tree, GFP_KERNEL); |
28 | int base, err, i; | 28 | int base, err, i; |
29 | unsigned long first = 0; | ||
30 | 29 | ||
31 | /* our canonical entry */ | 30 | /* our canonical entry */ |
32 | base = index & ~((1 << order) - 1); | 31 | base = index & ~((1 << order) - 1); |
@@ -60,7 +59,7 @@ static void __multiorder_tag_test(int index, int order) | |||
60 | assert(!radix_tree_tag_get(&tree, i, 1)); | 59 | assert(!radix_tree_tag_get(&tree, i, 1)); |
61 | } | 60 | } |
62 | 61 | ||
63 | assert(radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, 10, 0, 1) == 1); | 62 | assert(tag_tagged_items(&tree, NULL, 0, ~0UL, 10, 0, 1) == 1); |
64 | assert(radix_tree_tag_clear(&tree, index, 0)); | 63 | assert(radix_tree_tag_clear(&tree, index, 0)); |
65 | 64 | ||
66 | for_each_index(i, base, order) { | 65 | for_each_index(i, base, order) { |
@@ -76,8 +75,27 @@ static void __multiorder_tag_test(int index, int order) | |||
76 | item_kill_tree(&tree); | 75 | item_kill_tree(&tree); |
77 | } | 76 | } |
78 | 77 | ||
78 | static void __multiorder_tag_test2(unsigned order, unsigned long index2) | ||
79 | { | ||
80 | RADIX_TREE(tree, GFP_KERNEL); | ||
81 | unsigned long index = (1 << order); | ||
82 | index2 += index; | ||
83 | |||
84 | assert(item_insert_order(&tree, 0, order) == 0); | ||
85 | assert(item_insert(&tree, index2) == 0); | ||
86 | |||
87 | assert(radix_tree_tag_set(&tree, 0, 0)); | ||
88 | assert(radix_tree_tag_set(&tree, index2, 0)); | ||
89 | |||
90 | assert(tag_tagged_items(&tree, NULL, 0, ~0UL, 10, 0, 1) == 2); | ||
91 | |||
92 | item_kill_tree(&tree); | ||
93 | } | ||
94 | |||
79 | static void multiorder_tag_tests(void) | 95 | static void multiorder_tag_tests(void) |
80 | { | 96 | { |
97 | int i, j; | ||
98 | |||
81 | /* test multi-order entry for indices 0-7 with no sibling pointers */ | 99 | /* test multi-order entry for indices 0-7 with no sibling pointers */ |
82 | __multiorder_tag_test(0, 3); | 100 | __multiorder_tag_test(0, 3); |
83 | __multiorder_tag_test(5, 3); | 101 | __multiorder_tag_test(5, 3); |
@@ -117,6 +135,10 @@ static void multiorder_tag_tests(void) | |||
117 | __multiorder_tag_test(300, 8); | 135 | __multiorder_tag_test(300, 8); |
118 | 136 | ||
119 | __multiorder_tag_test(0x12345678UL, 8); | 137 | __multiorder_tag_test(0x12345678UL, 8); |
138 | |||
139 | for (i = 1; i < 10; i++) | ||
140 | for (j = 0; j < (10 << i); j++) | ||
141 | __multiorder_tag_test2(i, j); | ||
120 | } | 142 | } |
121 | 143 | ||
122 | static void multiorder_check(unsigned long index, int order) | 144 | static void multiorder_check(unsigned long index, int order) |
@@ -125,7 +147,7 @@ static void multiorder_check(unsigned long index, int order) | |||
125 | unsigned long min = index & ~((1UL << order) - 1); | 147 | unsigned long min = index & ~((1UL << order) - 1); |
126 | unsigned long max = min + (1UL << order); | 148 | unsigned long max = min + (1UL << order); |
127 | void **slot; | 149 | void **slot; |
128 | struct item *item2 = item_create(min); | 150 | struct item *item2 = item_create(min, order); |
129 | RADIX_TREE(tree, GFP_KERNEL); | 151 | RADIX_TREE(tree, GFP_KERNEL); |
130 | 152 | ||
131 | printf("Multiorder index %ld, order %d\n", index, order); | 153 | printf("Multiorder index %ld, order %d\n", index, order); |
@@ -146,7 +168,7 @@ static void multiorder_check(unsigned long index, int order) | |||
146 | 168 | ||
147 | slot = radix_tree_lookup_slot(&tree, index); | 169 | slot = radix_tree_lookup_slot(&tree, index); |
148 | free(*slot); | 170 | free(*slot); |
149 | radix_tree_replace_slot(slot, item2); | 171 | radix_tree_replace_slot(&tree, slot, item2); |
150 | for (i = min; i < max; i++) { | 172 | for (i = min; i < max; i++) { |
151 | struct item *item = item_lookup(&tree, i); | 173 | struct item *item = item_lookup(&tree, i); |
152 | assert(item != 0); | 174 | assert(item != 0); |
@@ -231,11 +253,14 @@ void multiorder_iteration(void) | |||
231 | radix_tree_for_each_slot(slot, &tree, &iter, j) { | 253 | radix_tree_for_each_slot(slot, &tree, &iter, j) { |
232 | int height = order[i] / RADIX_TREE_MAP_SHIFT; | 254 | int height = order[i] / RADIX_TREE_MAP_SHIFT; |
233 | int shift = height * RADIX_TREE_MAP_SHIFT; | 255 | int shift = height * RADIX_TREE_MAP_SHIFT; |
234 | int mask = (1 << order[i]) - 1; | 256 | unsigned long mask = (1UL << order[i]) - 1; |
257 | struct item *item = *slot; | ||
235 | 258 | ||
236 | assert(iter.index >= (index[i] &~ mask)); | 259 | assert((iter.index | mask) == (index[i] | mask)); |
237 | assert(iter.index <= (index[i] | mask)); | ||
238 | assert(iter.shift == shift); | 260 | assert(iter.shift == shift); |
261 | assert(!radix_tree_is_internal_node(item)); | ||
262 | assert((item->index | mask) == (index[i] | mask)); | ||
263 | assert(item->order == order[i]); | ||
239 | i++; | 264 | i++; |
240 | } | 265 | } |
241 | } | 266 | } |
@@ -248,7 +273,6 @@ void multiorder_tagged_iteration(void) | |||
248 | RADIX_TREE(tree, GFP_KERNEL); | 273 | RADIX_TREE(tree, GFP_KERNEL); |
249 | struct radix_tree_iter iter; | 274 | struct radix_tree_iter iter; |
250 | void **slot; | 275 | void **slot; |
251 | unsigned long first = 0; | ||
252 | int i, j; | 276 | int i, j; |
253 | 277 | ||
254 | printf("Multiorder tagged iteration test\n"); | 278 | printf("Multiorder tagged iteration test\n"); |
@@ -269,7 +293,7 @@ void multiorder_tagged_iteration(void) | |||
269 | assert(radix_tree_tag_set(&tree, tag_index[i], 1)); | 293 | assert(radix_tree_tag_set(&tree, tag_index[i], 1)); |
270 | 294 | ||
271 | for (j = 0; j < 256; j++) { | 295 | for (j = 0; j < 256; j++) { |
272 | int mask, k; | 296 | int k; |
273 | 297 | ||
274 | for (i = 0; i < TAG_ENTRIES; i++) { | 298 | for (i = 0; i < TAG_ENTRIES; i++) { |
275 | for (k = i; index[k] < tag_index[i]; k++) | 299 | for (k = i; index[k] < tag_index[i]; k++) |
@@ -279,18 +303,22 @@ void multiorder_tagged_iteration(void) | |||
279 | } | 303 | } |
280 | 304 | ||
281 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) { | 305 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) { |
306 | unsigned long mask; | ||
307 | struct item *item = *slot; | ||
282 | for (k = i; index[k] < tag_index[i]; k++) | 308 | for (k = i; index[k] < tag_index[i]; k++) |
283 | ; | 309 | ; |
284 | mask = (1 << order[k]) - 1; | 310 | mask = (1UL << order[k]) - 1; |
285 | 311 | ||
286 | assert(iter.index >= (tag_index[i] &~ mask)); | 312 | assert((iter.index | mask) == (tag_index[i] | mask)); |
287 | assert(iter.index <= (tag_index[i] | mask)); | 313 | assert(!radix_tree_is_internal_node(item)); |
314 | assert((item->index | mask) == (tag_index[i] | mask)); | ||
315 | assert(item->order == order[k]); | ||
288 | i++; | 316 | i++; |
289 | } | 317 | } |
290 | } | 318 | } |
291 | 319 | ||
292 | radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, | 320 | assert(tag_tagged_items(&tree, NULL, 0, ~0UL, TAG_ENTRIES, 1, 2) == |
293 | MT_NUM_ENTRIES, 1, 2); | 321 | TAG_ENTRIES); |
294 | 322 | ||
295 | for (j = 0; j < 256; j++) { | 323 | for (j = 0; j < 256; j++) { |
296 | int mask, k; | 324 | int mask, k; |
@@ -303,19 +331,21 @@ void multiorder_tagged_iteration(void) | |||
303 | } | 331 | } |
304 | 332 | ||
305 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) { | 333 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) { |
334 | struct item *item = *slot; | ||
306 | for (k = i; index[k] < tag_index[i]; k++) | 335 | for (k = i; index[k] < tag_index[i]; k++) |
307 | ; | 336 | ; |
308 | mask = (1 << order[k]) - 1; | 337 | mask = (1 << order[k]) - 1; |
309 | 338 | ||
310 | assert(iter.index >= (tag_index[i] &~ mask)); | 339 | assert((iter.index | mask) == (tag_index[i] | mask)); |
311 | assert(iter.index <= (tag_index[i] | mask)); | 340 | assert(!radix_tree_is_internal_node(item)); |
341 | assert((item->index | mask) == (tag_index[i] | mask)); | ||
342 | assert(item->order == order[k]); | ||
312 | i++; | 343 | i++; |
313 | } | 344 | } |
314 | } | 345 | } |
315 | 346 | ||
316 | first = 1; | 347 | assert(tag_tagged_items(&tree, NULL, 1, ~0UL, MT_NUM_ENTRIES * 2, 1, 0) |
317 | radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, | 348 | == TAG_ENTRIES); |
318 | MT_NUM_ENTRIES, 1, 0); | ||
319 | i = 0; | 349 | i = 0; |
320 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) { | 350 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) { |
321 | assert(iter.index == tag_index[i]); | 351 | assert(iter.index == tag_index[i]); |
@@ -325,6 +355,261 @@ void multiorder_tagged_iteration(void) | |||
325 | item_kill_tree(&tree); | 355 | item_kill_tree(&tree); |
326 | } | 356 | } |
327 | 357 | ||
358 | static void multiorder_join1(unsigned long index, | ||
359 | unsigned order1, unsigned order2) | ||
360 | { | ||
361 | unsigned long loc; | ||
362 | void *item, *item2 = item_create(index + 1, order1); | ||
363 | RADIX_TREE(tree, GFP_KERNEL); | ||
364 | |||
365 | item_insert_order(&tree, index, order2); | ||
366 | item = radix_tree_lookup(&tree, index); | ||
367 | radix_tree_join(&tree, index + 1, order1, item2); | ||
368 | loc = find_item(&tree, item); | ||
369 | if (loc == -1) | ||
370 | free(item); | ||
371 | item = radix_tree_lookup(&tree, index + 1); | ||
372 | assert(item == item2); | ||
373 | item_kill_tree(&tree); | ||
374 | } | ||
375 | |||
376 | static void multiorder_join2(unsigned order1, unsigned order2) | ||
377 | { | ||
378 | RADIX_TREE(tree, GFP_KERNEL); | ||
379 | struct radix_tree_node *node; | ||
380 | void *item1 = item_create(0, order1); | ||
381 | void *item2; | ||
382 | |||
383 | item_insert_order(&tree, 0, order2); | ||
384 | radix_tree_insert(&tree, 1 << order2, (void *)0x12UL); | ||
385 | item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL); | ||
386 | assert(item2 == (void *)0x12UL); | ||
387 | assert(node->exceptional == 1); | ||
388 | |||
389 | radix_tree_join(&tree, 0, order1, item1); | ||
390 | item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL); | ||
391 | assert(item2 == item1); | ||
392 | assert(node->exceptional == 0); | ||
393 | item_kill_tree(&tree); | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * This test revealed an accounting bug for exceptional entries at one point. | ||
398 | * Nodes were being freed back into the pool with an elevated exception count | ||
399 | * by radix_tree_join() and then radix_tree_split() was failing to zero the | ||
400 | * count of exceptional entries. | ||
401 | */ | ||
402 | static void multiorder_join3(unsigned int order) | ||
403 | { | ||
404 | RADIX_TREE(tree, GFP_KERNEL); | ||
405 | struct radix_tree_node *node; | ||
406 | void **slot; | ||
407 | struct radix_tree_iter iter; | ||
408 | unsigned long i; | ||
409 | |||
410 | for (i = 0; i < (1 << order); i++) { | ||
411 | radix_tree_insert(&tree, i, (void *)0x12UL); | ||
412 | } | ||
413 | |||
414 | radix_tree_join(&tree, 0, order, (void *)0x16UL); | ||
415 | rcu_barrier(); | ||
416 | |||
417 | radix_tree_split(&tree, 0, 0); | ||
418 | |||
419 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
420 | radix_tree_iter_replace(&tree, &iter, slot, (void *)0x12UL); | ||
421 | } | ||
422 | |||
423 | __radix_tree_lookup(&tree, 0, &node, NULL); | ||
424 | assert(node->exceptional == node->count); | ||
425 | |||
426 | item_kill_tree(&tree); | ||
427 | } | ||
428 | |||
429 | static void multiorder_join(void) | ||
430 | { | ||
431 | int i, j, idx; | ||
432 | |||
433 | for (idx = 0; idx < 1024; idx = idx * 2 + 3) { | ||
434 | for (i = 1; i < 15; i++) { | ||
435 | for (j = 0; j < i; j++) { | ||
436 | multiorder_join1(idx, i, j); | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | |||
441 | for (i = 1; i < 15; i++) { | ||
442 | for (j = 0; j < i; j++) { | ||
443 | multiorder_join2(i, j); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | for (i = 3; i < 10; i++) { | ||
448 | multiorder_join3(i); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | static void check_mem(unsigned old_order, unsigned new_order, unsigned alloc) | ||
453 | { | ||
454 | struct radix_tree_preload *rtp = &radix_tree_preloads; | ||
455 | if (rtp->nr != 0) | ||
456 | printf("split(%u %u) remaining %u\n", old_order, new_order, | ||
457 | rtp->nr); | ||
458 | /* | ||
459 | * Can't check for equality here as some nodes may have been | ||
460 | * RCU-freed while we ran. But we should never finish with more | ||
461 | * nodes allocated since they should have all been preloaded. | ||
462 | */ | ||
463 | if (nr_allocated > alloc) | ||
464 | printf("split(%u %u) allocated %u %u\n", old_order, new_order, | ||
465 | alloc, nr_allocated); | ||
466 | } | ||
467 | |||
468 | static void __multiorder_split(int old_order, int new_order) | ||
469 | { | ||
470 | RADIX_TREE(tree, GFP_ATOMIC); | ||
471 | void **slot; | ||
472 | struct radix_tree_iter iter; | ||
473 | unsigned alloc; | ||
474 | |||
475 | radix_tree_preload(GFP_KERNEL); | ||
476 | assert(item_insert_order(&tree, 0, old_order) == 0); | ||
477 | radix_tree_preload_end(); | ||
478 | |||
479 | /* Wipe out the preloaded cache or it'll confuse check_mem() */ | ||
480 | radix_tree_cpu_dead(0); | ||
481 | |||
482 | radix_tree_tag_set(&tree, 0, 2); | ||
483 | |||
484 | radix_tree_split_preload(old_order, new_order, GFP_KERNEL); | ||
485 | alloc = nr_allocated; | ||
486 | radix_tree_split(&tree, 0, new_order); | ||
487 | check_mem(old_order, new_order, alloc); | ||
488 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
489 | radix_tree_iter_replace(&tree, &iter, slot, | ||
490 | item_create(iter.index, new_order)); | ||
491 | } | ||
492 | radix_tree_preload_end(); | ||
493 | |||
494 | item_kill_tree(&tree); | ||
495 | } | ||
496 | |||
497 | static void __multiorder_split2(int old_order, int new_order) | ||
498 | { | ||
499 | RADIX_TREE(tree, GFP_KERNEL); | ||
500 | void **slot; | ||
501 | struct radix_tree_iter iter; | ||
502 | struct radix_tree_node *node; | ||
503 | void *item; | ||
504 | |||
505 | __radix_tree_insert(&tree, 0, old_order, (void *)0x12); | ||
506 | |||
507 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
508 | assert(item == (void *)0x12); | ||
509 | assert(node->exceptional > 0); | ||
510 | |||
511 | radix_tree_split(&tree, 0, new_order); | ||
512 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
513 | radix_tree_iter_replace(&tree, &iter, slot, | ||
514 | item_create(iter.index, new_order)); | ||
515 | } | ||
516 | |||
517 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
518 | assert(item != (void *)0x12); | ||
519 | assert(node->exceptional == 0); | ||
520 | |||
521 | item_kill_tree(&tree); | ||
522 | } | ||
523 | |||
524 | static void __multiorder_split3(int old_order, int new_order) | ||
525 | { | ||
526 | RADIX_TREE(tree, GFP_KERNEL); | ||
527 | void **slot; | ||
528 | struct radix_tree_iter iter; | ||
529 | struct radix_tree_node *node; | ||
530 | void *item; | ||
531 | |||
532 | __radix_tree_insert(&tree, 0, old_order, (void *)0x12); | ||
533 | |||
534 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
535 | assert(item == (void *)0x12); | ||
536 | assert(node->exceptional > 0); | ||
537 | |||
538 | radix_tree_split(&tree, 0, new_order); | ||
539 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
540 | radix_tree_iter_replace(&tree, &iter, slot, (void *)0x16); | ||
541 | } | ||
542 | |||
543 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
544 | assert(item == (void *)0x16); | ||
545 | assert(node->exceptional > 0); | ||
546 | |||
547 | item_kill_tree(&tree); | ||
548 | |||
549 | __radix_tree_insert(&tree, 0, old_order, (void *)0x12); | ||
550 | |||
551 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
552 | assert(item == (void *)0x12); | ||
553 | assert(node->exceptional > 0); | ||
554 | |||
555 | radix_tree_split(&tree, 0, new_order); | ||
556 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
557 | if (iter.index == (1 << new_order)) | ||
558 | radix_tree_iter_replace(&tree, &iter, slot, | ||
559 | (void *)0x16); | ||
560 | else | ||
561 | radix_tree_iter_replace(&tree, &iter, slot, NULL); | ||
562 | } | ||
563 | |||
564 | item = __radix_tree_lookup(&tree, 1 << new_order, &node, NULL); | ||
565 | assert(item == (void *)0x16); | ||
566 | assert(node->count == node->exceptional); | ||
567 | do { | ||
568 | node = node->parent; | ||
569 | if (!node) | ||
570 | break; | ||
571 | assert(node->count == 1); | ||
572 | assert(node->exceptional == 0); | ||
573 | } while (1); | ||
574 | |||
575 | item_kill_tree(&tree); | ||
576 | } | ||
577 | |||
578 | static void multiorder_split(void) | ||
579 | { | ||
580 | int i, j; | ||
581 | |||
582 | for (i = 3; i < 11; i++) | ||
583 | for (j = 0; j < i; j++) { | ||
584 | __multiorder_split(i, j); | ||
585 | __multiorder_split2(i, j); | ||
586 | __multiorder_split3(i, j); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | static void multiorder_account(void) | ||
591 | { | ||
592 | RADIX_TREE(tree, GFP_KERNEL); | ||
593 | struct radix_tree_node *node; | ||
594 | void **slot; | ||
595 | |||
596 | item_insert_order(&tree, 0, 5); | ||
597 | |||
598 | __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12); | ||
599 | __radix_tree_lookup(&tree, 0, &node, NULL); | ||
600 | assert(node->count == node->exceptional * 2); | ||
601 | radix_tree_delete(&tree, 1 << 5); | ||
602 | assert(node->exceptional == 0); | ||
603 | |||
604 | __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12); | ||
605 | __radix_tree_lookup(&tree, 1 << 5, &node, &slot); | ||
606 | assert(node->count == node->exceptional * 2); | ||
607 | __radix_tree_replace(&tree, node, slot, NULL, NULL, NULL); | ||
608 | assert(node->exceptional == 0); | ||
609 | |||
610 | item_kill_tree(&tree); | ||
611 | } | ||
612 | |||
328 | void multiorder_checks(void) | 613 | void multiorder_checks(void) |
329 | { | 614 | { |
330 | int i; | 615 | int i; |
@@ -342,4 +627,9 @@ void multiorder_checks(void) | |||
342 | multiorder_tag_tests(); | 627 | multiorder_tag_tests(); |
343 | multiorder_iteration(); | 628 | multiorder_iteration(); |
344 | multiorder_tagged_iteration(); | 629 | multiorder_tagged_iteration(); |
630 | multiorder_join(); | ||
631 | multiorder_split(); | ||
632 | multiorder_account(); | ||
633 | |||
634 | radix_tree_cpu_dead(0); | ||
345 | } | 635 | } |
diff --git a/tools/testing/radix-tree/rcupdate.c b/tools/testing/radix-tree/rcupdate.c deleted file mode 100644 index 31a2d14225d6..000000000000 --- a/tools/testing/radix-tree/rcupdate.c +++ /dev/null | |||
@@ -1,86 +0,0 @@ | |||
1 | #include <linux/rcupdate.h> | ||
2 | #include <pthread.h> | ||
3 | #include <stdio.h> | ||
4 | #include <assert.h> | ||
5 | |||
6 | static pthread_mutex_t rculock = PTHREAD_MUTEX_INITIALIZER; | ||
7 | static struct rcu_head *rcuhead_global = NULL; | ||
8 | static __thread int nr_rcuhead = 0; | ||
9 | static __thread struct rcu_head *rcuhead = NULL; | ||
10 | static __thread struct rcu_head *rcutail = NULL; | ||
11 | |||
12 | static pthread_cond_t rcu_worker_cond = PTHREAD_COND_INITIALIZER; | ||
13 | |||
14 | /* switch to urcu implementation when it is merged. */ | ||
15 | void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *head)) | ||
16 | { | ||
17 | head->func = func; | ||
18 | head->next = rcuhead; | ||
19 | rcuhead = head; | ||
20 | if (!rcutail) | ||
21 | rcutail = head; | ||
22 | nr_rcuhead++; | ||
23 | if (nr_rcuhead >= 1000) { | ||
24 | int signal = 0; | ||
25 | |||
26 | pthread_mutex_lock(&rculock); | ||
27 | if (!rcuhead_global) | ||
28 | signal = 1; | ||
29 | rcutail->next = rcuhead_global; | ||
30 | rcuhead_global = head; | ||
31 | pthread_mutex_unlock(&rculock); | ||
32 | |||
33 | nr_rcuhead = 0; | ||
34 | rcuhead = NULL; | ||
35 | rcutail = NULL; | ||
36 | |||
37 | if (signal) { | ||
38 | pthread_cond_signal(&rcu_worker_cond); | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void *rcu_worker(void *arg) | ||
44 | { | ||
45 | struct rcu_head *r; | ||
46 | |||
47 | rcupdate_thread_init(); | ||
48 | |||
49 | while (1) { | ||
50 | pthread_mutex_lock(&rculock); | ||
51 | while (!rcuhead_global) { | ||
52 | pthread_cond_wait(&rcu_worker_cond, &rculock); | ||
53 | } | ||
54 | r = rcuhead_global; | ||
55 | rcuhead_global = NULL; | ||
56 | |||
57 | pthread_mutex_unlock(&rculock); | ||
58 | |||
59 | synchronize_rcu(); | ||
60 | |||
61 | while (r) { | ||
62 | struct rcu_head *tmp = r->next; | ||
63 | r->func(r); | ||
64 | r = tmp; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | rcupdate_thread_exit(); | ||
69 | |||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | static pthread_t worker_thread; | ||
74 | void rcupdate_init(void) | ||
75 | { | ||
76 | pthread_create(&worker_thread, NULL, rcu_worker, NULL); | ||
77 | } | ||
78 | |||
79 | void rcupdate_thread_init(void) | ||
80 | { | ||
81 | rcu_register_thread(); | ||
82 | } | ||
83 | void rcupdate_thread_exit(void) | ||
84 | { | ||
85 | rcu_unregister_thread(); | ||
86 | } | ||
diff --git a/tools/testing/radix-tree/regression2.c b/tools/testing/radix-tree/regression2.c index 63bf347aaf33..a41325d7a170 100644 --- a/tools/testing/radix-tree/regression2.c +++ b/tools/testing/radix-tree/regression2.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <stdio.h> | 50 | #include <stdio.h> |
51 | 51 | ||
52 | #include "regression.h" | 52 | #include "regression.h" |
53 | #include "test.h" | ||
53 | 54 | ||
54 | #define PAGECACHE_TAG_DIRTY 0 | 55 | #define PAGECACHE_TAG_DIRTY 0 |
55 | #define PAGECACHE_TAG_WRITEBACK 1 | 56 | #define PAGECACHE_TAG_WRITEBACK 1 |
@@ -90,7 +91,7 @@ void regression2_test(void) | |||
90 | /* 1. */ | 91 | /* 1. */ |
91 | start = 0; | 92 | start = 0; |
92 | end = max_slots - 2; | 93 | end = max_slots - 2; |
93 | radix_tree_range_tag_if_tagged(&mt_tree, &start, end, 1, | 94 | tag_tagged_items(&mt_tree, NULL, start, end, 1, |
94 | PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE); | 95 | PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE); |
95 | 96 | ||
96 | /* 2. */ | 97 | /* 2. */ |
diff --git a/tools/testing/radix-tree/regression3.c b/tools/testing/radix-tree/regression3.c index 1f06ed73d0a8..b594841fae85 100644 --- a/tools/testing/radix-tree/regression3.c +++ b/tools/testing/radix-tree/regression3.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * In following radix_tree_next_slot current chunk size becomes zero. | 5 | * In following radix_tree_next_slot current chunk size becomes zero. |
6 | * This isn't checked and it tries to dereference null pointer in slot. | 6 | * This isn't checked and it tries to dereference null pointer in slot. |
7 | * | 7 | * |
8 | * Helper radix_tree_iter_next reset slot to NULL and next_index to index + 1, | 8 | * Helper radix_tree_iter_resume reset slot to NULL and next_index to index + 1, |
9 | * for tagger iteraction it also must reset cached tags in iterator to abort | 9 | * for tagger iteraction it also must reset cached tags in iterator to abort |
10 | * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk. | 10 | * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk. |
11 | * | 11 | * |
@@ -88,7 +88,7 @@ void regression3_test(void) | |||
88 | printf("slot %ld %p\n", iter.index, *slot); | 88 | printf("slot %ld %p\n", iter.index, *slot); |
89 | if (!iter.index) { | 89 | if (!iter.index) { |
90 | printf("next at %ld\n", iter.index); | 90 | printf("next at %ld\n", iter.index); |
91 | slot = radix_tree_iter_next(&iter); | 91 | slot = radix_tree_iter_resume(slot, &iter); |
92 | } | 92 | } |
93 | } | 93 | } |
94 | 94 | ||
@@ -96,7 +96,7 @@ void regression3_test(void) | |||
96 | printf("contig %ld %p\n", iter.index, *slot); | 96 | printf("contig %ld %p\n", iter.index, *slot); |
97 | if (!iter.index) { | 97 | if (!iter.index) { |
98 | printf("next at %ld\n", iter.index); | 98 | printf("next at %ld\n", iter.index); |
99 | slot = radix_tree_iter_next(&iter); | 99 | slot = radix_tree_iter_resume(slot, &iter); |
100 | } | 100 | } |
101 | } | 101 | } |
102 | 102 | ||
@@ -106,7 +106,7 @@ void regression3_test(void) | |||
106 | printf("tagged %ld %p\n", iter.index, *slot); | 106 | printf("tagged %ld %p\n", iter.index, *slot); |
107 | if (!iter.index) { | 107 | if (!iter.index) { |
108 | printf("next at %ld\n", iter.index); | 108 | printf("next at %ld\n", iter.index); |
109 | slot = radix_tree_iter_next(&iter); | 109 | slot = radix_tree_iter_resume(slot, &iter); |
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c index b0ac05741750..fd98c132207a 100644 --- a/tools/testing/radix-tree/tag_check.c +++ b/tools/testing/radix-tree/tag_check.c | |||
@@ -23,7 +23,7 @@ __simple_checks(struct radix_tree_root *tree, unsigned long index, int tag) | |||
23 | item_tag_set(tree, index, tag); | 23 | item_tag_set(tree, index, tag); |
24 | ret = item_tag_get(tree, index, tag); | 24 | ret = item_tag_get(tree, index, tag); |
25 | assert(ret != 0); | 25 | assert(ret != 0); |
26 | ret = radix_tree_range_tag_if_tagged(tree, &first, ~0UL, 10, tag, !tag); | 26 | ret = tag_tagged_items(tree, NULL, first, ~0UL, 10, tag, !tag); |
27 | assert(ret == 1); | 27 | assert(ret == 1); |
28 | ret = item_tag_get(tree, index, !tag); | 28 | ret = item_tag_get(tree, index, !tag); |
29 | assert(ret != 0); | 29 | assert(ret != 0); |
@@ -51,6 +51,7 @@ void simple_checks(void) | |||
51 | verify_tag_consistency(&tree, 1); | 51 | verify_tag_consistency(&tree, 1); |
52 | printf("before item_kill_tree: %d allocated\n", nr_allocated); | 52 | printf("before item_kill_tree: %d allocated\n", nr_allocated); |
53 | item_kill_tree(&tree); | 53 | item_kill_tree(&tree); |
54 | rcu_barrier(); | ||
54 | printf("after item_kill_tree: %d allocated\n", nr_allocated); | 55 | printf("after item_kill_tree: %d allocated\n", nr_allocated); |
55 | } | 56 | } |
56 | 57 | ||
@@ -319,10 +320,13 @@ static void single_check(void) | |||
319 | assert(ret == 0); | 320 | assert(ret == 0); |
320 | verify_tag_consistency(&tree, 0); | 321 | verify_tag_consistency(&tree, 0); |
321 | verify_tag_consistency(&tree, 1); | 322 | verify_tag_consistency(&tree, 1); |
322 | ret = radix_tree_range_tag_if_tagged(&tree, &first, 10, 10, 0, 1); | 323 | ret = tag_tagged_items(&tree, NULL, first, 10, 10, 0, 1); |
323 | assert(ret == 1); | 324 | assert(ret == 1); |
324 | ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1); | 325 | ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1); |
325 | assert(ret == 1); | 326 | assert(ret == 1); |
327 | item_tag_clear(&tree, 0, 0); | ||
328 | ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 0); | ||
329 | assert(ret == 0); | ||
326 | item_kill_tree(&tree); | 330 | item_kill_tree(&tree); |
327 | } | 331 | } |
328 | 332 | ||
@@ -331,12 +335,16 @@ void tag_check(void) | |||
331 | single_check(); | 335 | single_check(); |
332 | extend_checks(); | 336 | extend_checks(); |
333 | contract_checks(); | 337 | contract_checks(); |
338 | rcu_barrier(); | ||
334 | printf("after extend_checks: %d allocated\n", nr_allocated); | 339 | printf("after extend_checks: %d allocated\n", nr_allocated); |
335 | __leak_check(); | 340 | __leak_check(); |
336 | leak_check(); | 341 | leak_check(); |
342 | rcu_barrier(); | ||
337 | printf("after leak_check: %d allocated\n", nr_allocated); | 343 | printf("after leak_check: %d allocated\n", nr_allocated); |
338 | simple_checks(); | 344 | simple_checks(); |
345 | rcu_barrier(); | ||
339 | printf("after simple_checks: %d allocated\n", nr_allocated); | 346 | printf("after simple_checks: %d allocated\n", nr_allocated); |
340 | thrash_tags(); | 347 | thrash_tags(); |
348 | rcu_barrier(); | ||
341 | printf("after thrash_tags: %d allocated\n", nr_allocated); | 349 | printf("after thrash_tags: %d allocated\n", nr_allocated); |
342 | } | 350 | } |
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c index a6e8099eaf4f..e5726e373646 100644 --- a/tools/testing/radix-tree/test.c +++ b/tools/testing/radix-tree/test.c | |||
@@ -24,21 +24,29 @@ int item_tag_get(struct radix_tree_root *root, unsigned long index, int tag) | |||
24 | return radix_tree_tag_get(root, index, tag); | 24 | return radix_tree_tag_get(root, index, tag); |
25 | } | 25 | } |
26 | 26 | ||
27 | int __item_insert(struct radix_tree_root *root, struct item *item, | 27 | int __item_insert(struct radix_tree_root *root, struct item *item) |
28 | unsigned order) | ||
29 | { | 28 | { |
30 | return __radix_tree_insert(root, item->index, order, item); | 29 | return __radix_tree_insert(root, item->index, item->order, item); |
31 | } | 30 | } |
32 | 31 | ||
33 | int item_insert(struct radix_tree_root *root, unsigned long index) | 32 | int item_insert(struct radix_tree_root *root, unsigned long index) |
34 | { | 33 | { |
35 | return __item_insert(root, item_create(index), 0); | 34 | return __item_insert(root, item_create(index, 0)); |
36 | } | 35 | } |
37 | 36 | ||
38 | int item_insert_order(struct radix_tree_root *root, unsigned long index, | 37 | int item_insert_order(struct radix_tree_root *root, unsigned long index, |
39 | unsigned order) | 38 | unsigned order) |
40 | { | 39 | { |
41 | return __item_insert(root, item_create(index), order); | 40 | return __item_insert(root, item_create(index, order)); |
41 | } | ||
42 | |||
43 | void item_sanity(struct item *item, unsigned long index) | ||
44 | { | ||
45 | unsigned long mask; | ||
46 | assert(!radix_tree_is_internal_node(item)); | ||
47 | assert(item->order < BITS_PER_LONG); | ||
48 | mask = (1UL << item->order) - 1; | ||
49 | assert((item->index | mask) == (index | mask)); | ||
42 | } | 50 | } |
43 | 51 | ||
44 | int item_delete(struct radix_tree_root *root, unsigned long index) | 52 | int item_delete(struct radix_tree_root *root, unsigned long index) |
@@ -46,18 +54,19 @@ int item_delete(struct radix_tree_root *root, unsigned long index) | |||
46 | struct item *item = radix_tree_delete(root, index); | 54 | struct item *item = radix_tree_delete(root, index); |
47 | 55 | ||
48 | if (item) { | 56 | if (item) { |
49 | assert(item->index == index); | 57 | item_sanity(item, index); |
50 | free(item); | 58 | free(item); |
51 | return 1; | 59 | return 1; |
52 | } | 60 | } |
53 | return 0; | 61 | return 0; |
54 | } | 62 | } |
55 | 63 | ||
56 | struct item *item_create(unsigned long index) | 64 | struct item *item_create(unsigned long index, unsigned int order) |
57 | { | 65 | { |
58 | struct item *ret = malloc(sizeof(*ret)); | 66 | struct item *ret = malloc(sizeof(*ret)); |
59 | 67 | ||
60 | ret->index = index; | 68 | ret->index = index; |
69 | ret->order = order; | ||
61 | return ret; | 70 | return ret; |
62 | } | 71 | } |
63 | 72 | ||
@@ -66,8 +75,8 @@ void item_check_present(struct radix_tree_root *root, unsigned long index) | |||
66 | struct item *item; | 75 | struct item *item; |
67 | 76 | ||
68 | item = radix_tree_lookup(root, index); | 77 | item = radix_tree_lookup(root, index); |
69 | assert(item != 0); | 78 | assert(item != NULL); |
70 | assert(item->index == index); | 79 | item_sanity(item, index); |
71 | } | 80 | } |
72 | 81 | ||
73 | struct item *item_lookup(struct radix_tree_root *root, unsigned long index) | 82 | struct item *item_lookup(struct radix_tree_root *root, unsigned long index) |
@@ -80,7 +89,7 @@ void item_check_absent(struct radix_tree_root *root, unsigned long index) | |||
80 | struct item *item; | 89 | struct item *item; |
81 | 90 | ||
82 | item = radix_tree_lookup(root, index); | 91 | item = radix_tree_lookup(root, index); |
83 | assert(item == 0); | 92 | assert(item == NULL); |
84 | } | 93 | } |
85 | 94 | ||
86 | /* | 95 | /* |
@@ -142,6 +151,62 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start, | |||
142 | assert(nfound == 0); | 151 | assert(nfound == 0); |
143 | } | 152 | } |
144 | 153 | ||
154 | /* Use the same pattern as tag_pages_for_writeback() in mm/page-writeback.c */ | ||
155 | int tag_tagged_items(struct radix_tree_root *root, pthread_mutex_t *lock, | ||
156 | unsigned long start, unsigned long end, unsigned batch, | ||
157 | unsigned iftag, unsigned thentag) | ||
158 | { | ||
159 | unsigned long tagged = 0; | ||
160 | struct radix_tree_iter iter; | ||
161 | void **slot; | ||
162 | |||
163 | if (batch == 0) | ||
164 | batch = 1; | ||
165 | |||
166 | if (lock) | ||
167 | pthread_mutex_lock(lock); | ||
168 | radix_tree_for_each_tagged(slot, root, &iter, start, iftag) { | ||
169 | if (iter.index > end) | ||
170 | break; | ||
171 | radix_tree_iter_tag_set(root, &iter, thentag); | ||
172 | tagged++; | ||
173 | if ((tagged % batch) != 0) | ||
174 | continue; | ||
175 | slot = radix_tree_iter_resume(slot, &iter); | ||
176 | if (lock) { | ||
177 | pthread_mutex_unlock(lock); | ||
178 | rcu_barrier(); | ||
179 | pthread_mutex_lock(lock); | ||
180 | } | ||
181 | } | ||
182 | if (lock) | ||
183 | pthread_mutex_unlock(lock); | ||
184 | |||
185 | return tagged; | ||
186 | } | ||
187 | |||
188 | /* Use the same pattern as find_swap_entry() in mm/shmem.c */ | ||
189 | unsigned long find_item(struct radix_tree_root *root, void *item) | ||
190 | { | ||
191 | struct radix_tree_iter iter; | ||
192 | void **slot; | ||
193 | unsigned long found = -1; | ||
194 | unsigned long checked = 0; | ||
195 | |||
196 | radix_tree_for_each_slot(slot, root, &iter, 0) { | ||
197 | if (*slot == item) { | ||
198 | found = iter.index; | ||
199 | break; | ||
200 | } | ||
201 | checked++; | ||
202 | if ((checked % 4) != 0) | ||
203 | continue; | ||
204 | slot = radix_tree_iter_resume(slot, &iter); | ||
205 | } | ||
206 | |||
207 | return found; | ||
208 | } | ||
209 | |||
145 | static int verify_node(struct radix_tree_node *slot, unsigned int tag, | 210 | static int verify_node(struct radix_tree_node *slot, unsigned int tag, |
146 | int tagged) | 211 | int tagged) |
147 | { | 212 | { |
@@ -200,9 +265,16 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag) | |||
200 | 265 | ||
201 | void item_kill_tree(struct radix_tree_root *root) | 266 | void item_kill_tree(struct radix_tree_root *root) |
202 | { | 267 | { |
268 | struct radix_tree_iter iter; | ||
269 | void **slot; | ||
203 | struct item *items[32]; | 270 | struct item *items[32]; |
204 | int nfound; | 271 | int nfound; |
205 | 272 | ||
273 | radix_tree_for_each_slot(slot, root, &iter, 0) { | ||
274 | if (radix_tree_exceptional_entry(*slot)) | ||
275 | radix_tree_delete(root, iter.index); | ||
276 | } | ||
277 | |||
206 | while ((nfound = radix_tree_gang_lookup(root, (void **)items, 0, 32))) { | 278 | while ((nfound = radix_tree_gang_lookup(root, (void **)items, 0, 32))) { |
207 | int i; | 279 | int i; |
208 | 280 | ||
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h index 217fb2403f09..056a23b56467 100644 --- a/tools/testing/radix-tree/test.h +++ b/tools/testing/radix-tree/test.h | |||
@@ -5,11 +5,11 @@ | |||
5 | 5 | ||
6 | struct item { | 6 | struct item { |
7 | unsigned long index; | 7 | unsigned long index; |
8 | unsigned int order; | ||
8 | }; | 9 | }; |
9 | 10 | ||
10 | struct item *item_create(unsigned long index); | 11 | struct item *item_create(unsigned long index, unsigned int order); |
11 | int __item_insert(struct radix_tree_root *root, struct item *item, | 12 | int __item_insert(struct radix_tree_root *root, struct item *item); |
12 | unsigned order); | ||
13 | int item_insert(struct radix_tree_root *root, unsigned long index); | 13 | int item_insert(struct radix_tree_root *root, unsigned long index); |
14 | int item_insert_order(struct radix_tree_root *root, unsigned long index, | 14 | int item_insert_order(struct radix_tree_root *root, unsigned long index, |
15 | unsigned order); | 15 | unsigned order); |
@@ -25,9 +25,15 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start, | |||
25 | unsigned long nr, int chunk); | 25 | unsigned long nr, int chunk); |
26 | void item_kill_tree(struct radix_tree_root *root); | 26 | void item_kill_tree(struct radix_tree_root *root); |
27 | 27 | ||
28 | int tag_tagged_items(struct radix_tree_root *, pthread_mutex_t *, | ||
29 | unsigned long start, unsigned long end, unsigned batch, | ||
30 | unsigned iftag, unsigned thentag); | ||
31 | unsigned long find_item(struct radix_tree_root *, void *item); | ||
32 | |||
28 | void tag_check(void); | 33 | void tag_check(void); |
29 | void multiorder_checks(void); | 34 | void multiorder_checks(void); |
30 | void iteration_test(void); | 35 | void iteration_test(unsigned order, unsigned duration); |
36 | void benchmark(void); | ||
31 | 37 | ||
32 | struct item * | 38 | struct item * |
33 | item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); | 39 | item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); |
@@ -40,7 +46,14 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag); | |||
40 | extern int nr_allocated; | 46 | extern int nr_allocated; |
41 | 47 | ||
42 | /* Normally private parts of lib/radix-tree.c */ | 48 | /* Normally private parts of lib/radix-tree.c */ |
49 | struct radix_tree_node *entry_to_node(void *ptr); | ||
43 | void radix_tree_dump(struct radix_tree_root *root); | 50 | void radix_tree_dump(struct radix_tree_root *root); |
44 | int root_tag_get(struct radix_tree_root *root, unsigned int tag); | 51 | int root_tag_get(struct radix_tree_root *root, unsigned int tag); |
45 | unsigned long node_maxindex(struct radix_tree_node *); | 52 | unsigned long node_maxindex(struct radix_tree_node *); |
46 | unsigned long shift_maxindex(unsigned int shift); | 53 | unsigned long shift_maxindex(unsigned int shift); |
54 | int radix_tree_cpu_dead(unsigned int cpu); | ||
55 | struct radix_tree_preload { | ||
56 | unsigned nr; | ||
57 | struct radix_tree_node *nodes; | ||
58 | }; | ||
59 | extern struct radix_tree_preload radix_tree_preloads; | ||
diff --git a/tools/testing/selftests/.gitignore b/tools/testing/selftests/.gitignore new file mode 100644 index 000000000000..f0600d20ce7d --- /dev/null +++ b/tools/testing/selftests/.gitignore | |||
@@ -0,0 +1 @@ | |||
kselftest | |||
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index a3144a3de3a8..71b05891a6a1 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -7,6 +7,7 @@ TARGETS += exec | |||
7 | TARGETS += firmware | 7 | TARGETS += firmware |
8 | TARGETS += ftrace | 8 | TARGETS += ftrace |
9 | TARGETS += futex | 9 | TARGETS += futex |
10 | TARGETS += gpio | ||
10 | TARGETS += ipc | 11 | TARGETS += ipc |
11 | TARGETS += kcmp | 12 | TARGETS += kcmp |
12 | TARGETS += lib | 13 | TARGETS += lib |
@@ -24,6 +25,7 @@ TARGETS += seccomp | |||
24 | TARGETS += sigaltstack | 25 | TARGETS += sigaltstack |
25 | TARGETS += size | 26 | TARGETS += size |
26 | TARGETS += static_keys | 27 | TARGETS += static_keys |
28 | TARGETS += sync | ||
27 | TARGETS += sysctl | 29 | TARGETS += sysctl |
28 | ifneq (1, $(quicktest)) | 30 | ifneq (1, $(quicktest)) |
29 | TARGETS += timers | 31 | TARGETS += timers |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 0103bf2e0c0d..853d7e43434a 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -1059,7 +1059,7 @@ static struct bpf_test tests[] = { | |||
1059 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1059 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1060 | BPF_EXIT_INSN(), | 1060 | BPF_EXIT_INSN(), |
1061 | }, | 1061 | }, |
1062 | .errstr_unpriv = "unknown func 6", | 1062 | .errstr_unpriv = "unknown func bpf_trace_printk#6", |
1063 | .result_unpriv = REJECT, | 1063 | .result_unpriv = REJECT, |
1064 | .result = ACCEPT, | 1064 | .result = ACCEPT, |
1065 | }, | 1065 | }, |
@@ -2661,6 +2661,34 @@ static struct bpf_test tests[] = { | |||
2661 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 2661 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
2662 | }, | 2662 | }, |
2663 | { | 2663 | { |
2664 | "multiple registers share map_lookup_elem bad reg type", | ||
2665 | .insns = { | ||
2666 | BPF_MOV64_IMM(BPF_REG_1, 10), | ||
2667 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | ||
2668 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
2669 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
2670 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
2671 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
2672 | BPF_FUNC_map_lookup_elem), | ||
2673 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | ||
2674 | BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), | ||
2675 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
2676 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_0), | ||
2677 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
2678 | BPF_MOV64_IMM(BPF_REG_1, 1), | ||
2679 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
2680 | BPF_MOV64_IMM(BPF_REG_1, 2), | ||
2681 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_3, 0, 1), | ||
2682 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 0), | ||
2683 | BPF_MOV64_IMM(BPF_REG_1, 3), | ||
2684 | BPF_EXIT_INSN(), | ||
2685 | }, | ||
2686 | .fixup_map1 = { 4 }, | ||
2687 | .result = REJECT, | ||
2688 | .errstr = "R3 invalid mem access 'inv'", | ||
2689 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | ||
2690 | }, | ||
2691 | { | ||
2664 | "invalid map access from else condition", | 2692 | "invalid map access from else condition", |
2665 | .insns = { | 2693 | .insns = { |
2666 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 2694 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile index 74e533fd4bc5..61b79e8df1f4 100644 --- a/tools/testing/selftests/breakpoints/Makefile +++ b/tools/testing/selftests/breakpoints/Makefile | |||
@@ -5,6 +5,9 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) | |||
5 | ifeq ($(ARCH),x86) | 5 | ifeq ($(ARCH),x86) |
6 | TEST_PROGS := breakpoint_test | 6 | TEST_PROGS := breakpoint_test |
7 | endif | 7 | endif |
8 | ifeq ($(ARCH),aarch64) | ||
9 | TEST_PROGS := breakpoint_test_arm64 | ||
10 | endif | ||
8 | 11 | ||
9 | TEST_PROGS += step_after_suspend_test | 12 | TEST_PROGS += step_after_suspend_test |
10 | 13 | ||
@@ -13,4 +16,4 @@ all: $(TEST_PROGS) | |||
13 | include ../lib.mk | 16 | include ../lib.mk |
14 | 17 | ||
15 | clean: | 18 | clean: |
16 | rm -fr breakpoint_test step_after_suspend_test | 19 | rm -fr breakpoint_test breakpoint_test_arm64 step_after_suspend_test |
diff --git a/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c b/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c new file mode 100644 index 000000000000..3897e996541e --- /dev/null +++ b/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Google, Inc. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * Original Code by Pavel Labath <labath@google.com> | ||
14 | * | ||
15 | * Code modified by Pratyush Anand <panand@redhat.com> | ||
16 | * for testing different byte select for each access size. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #define _GNU_SOURCE | ||
21 | |||
22 | #include <sys/types.h> | ||
23 | #include <sys/wait.h> | ||
24 | #include <sys/ptrace.h> | ||
25 | #include <sys/param.h> | ||
26 | #include <sys/uio.h> | ||
27 | #include <stdint.h> | ||
28 | #include <stdbool.h> | ||
29 | #include <stddef.h> | ||
30 | #include <string.h> | ||
31 | #include <stdio.h> | ||
32 | #include <unistd.h> | ||
33 | #include <elf.h> | ||
34 | #include <errno.h> | ||
35 | #include <signal.h> | ||
36 | |||
37 | #include "../kselftest.h" | ||
38 | |||
39 | static volatile uint8_t var[96] __attribute__((__aligned__(32))); | ||
40 | |||
41 | static void child(int size, int wr) | ||
42 | { | ||
43 | volatile uint8_t *addr = &var[32 + wr]; | ||
44 | |||
45 | if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) { | ||
46 | perror("ptrace(PTRACE_TRACEME) failed"); | ||
47 | _exit(1); | ||
48 | } | ||
49 | |||
50 | if (raise(SIGSTOP) != 0) { | ||
51 | perror("raise(SIGSTOP) failed"); | ||
52 | _exit(1); | ||
53 | } | ||
54 | |||
55 | if ((uintptr_t) addr % size) { | ||
56 | perror("Wrong address write for the given size\n"); | ||
57 | _exit(1); | ||
58 | } | ||
59 | switch (size) { | ||
60 | case 1: | ||
61 | *addr = 47; | ||
62 | break; | ||
63 | case 2: | ||
64 | *(uint16_t *)addr = 47; | ||
65 | break; | ||
66 | case 4: | ||
67 | *(uint32_t *)addr = 47; | ||
68 | break; | ||
69 | case 8: | ||
70 | *(uint64_t *)addr = 47; | ||
71 | break; | ||
72 | case 16: | ||
73 | __asm__ volatile ("stp x29, x30, %0" : "=m" (addr[0])); | ||
74 | break; | ||
75 | case 32: | ||
76 | __asm__ volatile ("stp q29, q30, %0" : "=m" (addr[0])); | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | _exit(0); | ||
81 | } | ||
82 | |||
83 | static bool set_watchpoint(pid_t pid, int size, int wp) | ||
84 | { | ||
85 | const volatile uint8_t *addr = &var[32 + wp]; | ||
86 | const int offset = (uintptr_t)addr % 8; | ||
87 | const unsigned int byte_mask = ((1 << size) - 1) << offset; | ||
88 | const unsigned int type = 2; /* Write */ | ||
89 | const unsigned int enable = 1; | ||
90 | const unsigned int control = byte_mask << 5 | type << 3 | enable; | ||
91 | struct user_hwdebug_state dreg_state; | ||
92 | struct iovec iov; | ||
93 | |||
94 | memset(&dreg_state, 0, sizeof(dreg_state)); | ||
95 | dreg_state.dbg_regs[0].addr = (uintptr_t)(addr - offset); | ||
96 | dreg_state.dbg_regs[0].ctrl = control; | ||
97 | iov.iov_base = &dreg_state; | ||
98 | iov.iov_len = offsetof(struct user_hwdebug_state, dbg_regs) + | ||
99 | sizeof(dreg_state.dbg_regs[0]); | ||
100 | if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &iov) == 0) | ||
101 | return true; | ||
102 | |||
103 | if (errno == EIO) { | ||
104 | printf("ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) " | ||
105 | "not supported on this hardware\n"); | ||
106 | ksft_exit_skip(); | ||
107 | } | ||
108 | perror("ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) failed"); | ||
109 | return false; | ||
110 | } | ||
111 | |||
112 | static bool run_test(int wr_size, int wp_size, int wr, int wp) | ||
113 | { | ||
114 | int status; | ||
115 | siginfo_t siginfo; | ||
116 | pid_t pid = fork(); | ||
117 | pid_t wpid; | ||
118 | |||
119 | if (pid < 0) { | ||
120 | perror("fork() failed"); | ||
121 | return false; | ||
122 | } | ||
123 | if (pid == 0) | ||
124 | child(wr_size, wr); | ||
125 | |||
126 | wpid = waitpid(pid, &status, __WALL); | ||
127 | if (wpid != pid) { | ||
128 | perror("waitpid() failed"); | ||
129 | return false; | ||
130 | } | ||
131 | if (!WIFSTOPPED(status)) { | ||
132 | printf("child did not stop\n"); | ||
133 | return false; | ||
134 | } | ||
135 | if (WSTOPSIG(status) != SIGSTOP) { | ||
136 | printf("child did not stop with SIGSTOP\n"); | ||
137 | return false; | ||
138 | } | ||
139 | |||
140 | if (!set_watchpoint(pid, wp_size, wp)) | ||
141 | return false; | ||
142 | |||
143 | if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { | ||
144 | perror("ptrace(PTRACE_SINGLESTEP) failed"); | ||
145 | return false; | ||
146 | } | ||
147 | |||
148 | alarm(3); | ||
149 | wpid = waitpid(pid, &status, __WALL); | ||
150 | if (wpid != pid) { | ||
151 | perror("waitpid() failed"); | ||
152 | return false; | ||
153 | } | ||
154 | alarm(0); | ||
155 | if (WIFEXITED(status)) { | ||
156 | printf("child did not single-step\t"); | ||
157 | return false; | ||
158 | } | ||
159 | if (!WIFSTOPPED(status)) { | ||
160 | printf("child did not stop\n"); | ||
161 | return false; | ||
162 | } | ||
163 | if (WSTOPSIG(status) != SIGTRAP) { | ||
164 | printf("child did not stop with SIGTRAP\n"); | ||
165 | return false; | ||
166 | } | ||
167 | if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0) { | ||
168 | perror("ptrace(PTRACE_GETSIGINFO)"); | ||
169 | return false; | ||
170 | } | ||
171 | if (siginfo.si_code != TRAP_HWBKPT) { | ||
172 | printf("Unexpected si_code %d\n", siginfo.si_code); | ||
173 | return false; | ||
174 | } | ||
175 | |||
176 | kill(pid, SIGKILL); | ||
177 | wpid = waitpid(pid, &status, 0); | ||
178 | if (wpid != pid) { | ||
179 | perror("waitpid() failed"); | ||
180 | return false; | ||
181 | } | ||
182 | return true; | ||
183 | } | ||
184 | |||
185 | static void sigalrm(int sig) | ||
186 | { | ||
187 | } | ||
188 | |||
189 | int main(int argc, char **argv) | ||
190 | { | ||
191 | int opt; | ||
192 | bool succeeded = true; | ||
193 | struct sigaction act; | ||
194 | int wr, wp, size; | ||
195 | bool result; | ||
196 | |||
197 | act.sa_handler = sigalrm; | ||
198 | sigemptyset(&act.sa_mask); | ||
199 | act.sa_flags = 0; | ||
200 | sigaction(SIGALRM, &act, NULL); | ||
201 | for (size = 1; size <= 32; size = size*2) { | ||
202 | for (wr = 0; wr <= 32; wr = wr + size) { | ||
203 | for (wp = wr - size; wp <= wr + size; wp = wp + size) { | ||
204 | printf("Test size = %d write offset = %d watchpoint offset = %d\t", size, wr, wp); | ||
205 | result = run_test(size, MIN(size, 8), wr, wp); | ||
206 | if ((result && wr == wp) || (!result && wr != wp)) { | ||
207 | printf("[OK]\n"); | ||
208 | ksft_inc_pass_cnt(); | ||
209 | } else { | ||
210 | printf("[FAILED]\n"); | ||
211 | ksft_inc_fail_cnt(); | ||
212 | succeeded = false; | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | |||
218 | for (size = 1; size <= 32; size = size*2) { | ||
219 | printf("Test size = %d write offset = %d watchpoint offset = -8\t", size, -size); | ||
220 | |||
221 | if (run_test(size, 8, -size, -8)) { | ||
222 | printf("[OK]\n"); | ||
223 | ksft_inc_pass_cnt(); | ||
224 | } else { | ||
225 | printf("[FAILED]\n"); | ||
226 | ksft_inc_fail_cnt(); | ||
227 | succeeded = false; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | ksft_print_cnts(); | ||
232 | if (succeeded) | ||
233 | ksft_exit_pass(); | ||
234 | else | ||
235 | ksft_exit_fail(); | ||
236 | } | ||
diff --git a/tools/testing/selftests/drivers/gpu/i915.sh b/tools/testing/selftests/drivers/gpu/i915.sh new file mode 100755 index 000000000000..d407f0fa1e3a --- /dev/null +++ b/tools/testing/selftests/drivers/gpu/i915.sh | |||
@@ -0,0 +1,14 @@ | |||
1 | #!/bin/sh | ||
2 | # Runs hardware independent tests for i915 (drivers/gpu/drm/i915) | ||
3 | |||
4 | if ! /sbin/modprobe -q -r i915; then | ||
5 | echo "drivers/gpu/i915: [SKIP]" | ||
6 | exit 77 | ||
7 | fi | ||
8 | |||
9 | if /sbin/modprobe -q i915 mock_selftests=-1; then | ||
10 | echo "drivers/gpu/i915: ok" | ||
11 | else | ||
12 | echo "drivers/gpu/i915: [FAIL]" | ||
13 | exit 1 | ||
14 | fi | ||
diff --git a/tools/testing/selftests/ftrace/.gitignore b/tools/testing/selftests/ftrace/.gitignore new file mode 100644 index 000000000000..98d8a5a63049 --- /dev/null +++ b/tools/testing/selftests/ftrace/.gitignore | |||
@@ -0,0 +1 @@ | |||
logs | |||
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest index 4c6a0bf8ba79..52e3c4df28d6 100755 --- a/tools/testing/selftests/ftrace/ftracetest +++ b/tools/testing/selftests/ftrace/ftracetest | |||
@@ -13,7 +13,8 @@ echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]" | |||
13 | echo " Options:" | 13 | echo " Options:" |
14 | echo " -h|--help Show help message" | 14 | echo " -h|--help Show help message" |
15 | echo " -k|--keep Keep passed test logs" | 15 | echo " -k|--keep Keep passed test logs" |
16 | echo " -v|--verbose Show all stdout messages in testcases" | 16 | echo " -v|--verbose Increase verbosity of test messages" |
17 | echo " -vv Alias of -v -v (Show all results in stdout)" | ||
17 | echo " -d|--debug Debug mode (trace all shell commands)" | 18 | echo " -d|--debug Debug mode (trace all shell commands)" |
18 | exit $1 | 19 | exit $1 |
19 | } | 20 | } |
@@ -54,8 +55,9 @@ parse_opts() { # opts | |||
54 | KEEP_LOG=1 | 55 | KEEP_LOG=1 |
55 | shift 1 | 56 | shift 1 |
56 | ;; | 57 | ;; |
57 | --verbose|-v) | 58 | --verbose|-v|-vv) |
58 | VERBOSE=1 | 59 | VERBOSE=$((VERBOSE + 1)) |
60 | [ $1 == '-vv' ] && VERBOSE=$((VERBOSE + 1)) | ||
59 | shift 1 | 61 | shift 1 |
60 | ;; | 62 | ;; |
61 | --debug|-d) | 63 | --debug|-d) |
@@ -228,7 +230,7 @@ trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL | |||
228 | 230 | ||
229 | __run_test() { # testfile | 231 | __run_test() { # testfile |
230 | # setup PID and PPID, $$ is not updated. | 232 | # setup PID and PPID, $$ is not updated. |
231 | (cd $TRACING_DIR; read PID _ < /proc/self/stat ; set -e; set -x; . $1) | 233 | (cd $TRACING_DIR; read PID _ < /proc/self/stat; set -e; set -x; initialize_ftrace; . $1) |
232 | [ $? -ne 0 ] && kill -s $SIG_FAIL $SIG_PID | 234 | [ $? -ne 0 ] && kill -s $SIG_FAIL $SIG_PID |
233 | } | 235 | } |
234 | 236 | ||
@@ -236,10 +238,11 @@ __run_test() { # testfile | |||
236 | run_test() { # testfile | 238 | run_test() { # testfile |
237 | local testname=`basename $1` | 239 | local testname=`basename $1` |
238 | local testlog=`mktemp $LOG_DIR/${testname}-log.XXXXXX` | 240 | local testlog=`mktemp $LOG_DIR/${testname}-log.XXXXXX` |
241 | export TMPDIR=`mktemp -d /tmp/ftracetest-dir.XXXXXX` | ||
239 | testcase $1 | 242 | testcase $1 |
240 | echo "execute: "$1 > $testlog | 243 | echo "execute: "$1 > $testlog |
241 | SIG_RESULT=0 | 244 | SIG_RESULT=0 |
242 | if [ $VERBOSE -ne 0 ]; then | 245 | if [ $VERBOSE -ge 2 ]; then |
243 | __run_test $1 2>> $testlog | tee -a $testlog | 246 | __run_test $1 2>> $testlog | tee -a $testlog |
244 | else | 247 | else |
245 | __run_test $1 >> $testlog 2>&1 | 248 | __run_test $1 >> $testlog 2>&1 |
@@ -249,9 +252,10 @@ run_test() { # testfile | |||
249 | # Remove test log if the test was done as it was expected. | 252 | # Remove test log if the test was done as it was expected. |
250 | [ $KEEP_LOG -eq 0 ] && rm $testlog | 253 | [ $KEEP_LOG -eq 0 ] && rm $testlog |
251 | else | 254 | else |
252 | catlog $testlog | 255 | [ $VERBOSE -ge 1 ] && catlog $testlog |
253 | TOTAL_RESULT=1 | 256 | TOTAL_RESULT=1 |
254 | fi | 257 | fi |
258 | rm -rf $TMPDIR | ||
255 | } | 259 | } |
256 | 260 | ||
257 | # load in the helper functions | 261 | # load in the helper functions |
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-glob.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-glob.tc new file mode 100644 index 000000000000..9dcd0ca1f49c --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-glob.tc | |||
@@ -0,0 +1,49 @@ | |||
1 | #!/bin/sh | ||
2 | # description: ftrace - function glob filters | ||
3 | |||
4 | # Make sure that function glob matching filter works. | ||
5 | |||
6 | if ! grep -q function available_tracers; then | ||
7 | echo "no function tracer configured" | ||
8 | exit_unsupported | ||
9 | fi | ||
10 | |||
11 | disable_tracing | ||
12 | clear_trace | ||
13 | |||
14 | # filter by ?, schedule is always good | ||
15 | if ! echo "sch?dule" > set_ftrace_filter; then | ||
16 | # test for powerpc 64 | ||
17 | if ! echo ".sch?dule" > set_ftrace_filter; then | ||
18 | fail "can not enable schedule filter" | ||
19 | fi | ||
20 | cat set_ftrace_filter | grep '^.schedule$' | ||
21 | else | ||
22 | cat set_ftrace_filter | grep '^schedule$' | ||
23 | fi | ||
24 | |||
25 | ftrace_filter_check() { # glob grep | ||
26 | echo "$1" > set_ftrace_filter | ||
27 | cut -f1 -d" " set_ftrace_filter > $TMPDIR/actual | ||
28 | cut -f1 -d" " available_filter_functions | grep "$2" > $TMPDIR/expected | ||
29 | DIFF=`diff $TMPDIR/actual $TMPDIR/expected` | ||
30 | test -z "$DIFF" | ||
31 | } | ||
32 | |||
33 | # filter by *, front match | ||
34 | ftrace_filter_check '*schedule' '^.*schedule$' | ||
35 | |||
36 | # filter by *, middle match | ||
37 | ftrace_filter_check '*schedule*' '^.*schedule.*$' | ||
38 | |||
39 | # filter by *, end match | ||
40 | ftrace_filter_check 'schedule*' '^schedule.*$' | ||
41 | |||
42 | # filter by *, both side match | ||
43 | ftrace_filter_check 'sch*ule' '^sch.*ule$' | ||
44 | |||
45 | # filter by char class. | ||
46 | ftrace_filter_check '[Ss]y[Ss]_*' '^[Ss]y[Ss]_.*$' | ||
47 | |||
48 | echo > set_ftrace_filter | ||
49 | enable_tracing | ||
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions index c37262f6c269..91de1a8e4f19 100644 --- a/tools/testing/selftests/ftrace/test.d/functions +++ b/tools/testing/selftests/ftrace/test.d/functions | |||
@@ -23,3 +23,31 @@ reset_trigger() { # reset all current setting triggers | |||
23 | done | 23 | done |
24 | } | 24 | } |
25 | 25 | ||
26 | reset_events_filter() { # reset all current setting filters | ||
27 | grep -v ^none events/*/*/filter | | ||
28 | while read line; do | ||
29 | echo 0 > `echo $line | cut -f1 -d:` | ||
30 | done | ||
31 | } | ||
32 | |||
33 | disable_events() { | ||
34 | echo 0 > events/enable | ||
35 | } | ||
36 | |||
37 | initialize_ftrace() { # Reset ftrace to initial-state | ||
38 | # As the initial state, ftrace will be set to nop tracer, | ||
39 | # no events, no triggers, no filters, no function filters, | ||
40 | # no probes, and tracing on. | ||
41 | disable_tracing | ||
42 | reset_tracer | ||
43 | reset_trigger | ||
44 | reset_events_filter | ||
45 | disable_events | ||
46 | echo > set_event_pid # event tracer is always on | ||
47 | [ -f set_ftrace_filter ] && echo | tee set_ftrace_* | ||
48 | [ -f set_graph_function ] && echo | tee set_graph_* | ||
49 | [ -f stack_trace_filter ] && echo > stack_trace_filter | ||
50 | [ -f kprobe_events ] && echo > kprobe_events | ||
51 | [ -f uprobe_events ] && echo > uprobe_events | ||
52 | enable_tracing | ||
53 | } | ||
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc new file mode 100644 index 000000000000..0a78705b43b2 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc | |||
@@ -0,0 +1,37 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Kprobes event arguments with types | ||
3 | |||
4 | [ -f kprobe_events ] || exit_unsupported # this is configurable | ||
5 | |||
6 | grep "x8/16/32/64" README > /dev/null || exit_unsupported # version issue | ||
7 | |||
8 | echo 0 > events/enable | ||
9 | echo > kprobe_events | ||
10 | enable_tracing | ||
11 | |||
12 | echo 'p:testprobe _do_fork $stack0:s32 $stack0:u32 $stack0:x32 $stack0:b8@4/32' > kprobe_events | ||
13 | grep testprobe kprobe_events | ||
14 | test -d events/kprobes/testprobe | ||
15 | |||
16 | echo 1 > events/kprobes/testprobe/enable | ||
17 | ( echo "forked") | ||
18 | echo 0 > events/kprobes/testprobe/enable | ||
19 | ARGS=`tail -n 1 trace | sed -e 's/.* arg1=\(.*\) arg2=\(.*\) arg3=\(.*\) arg4=\(.*\)/\1 \2 \3 \4/'` | ||
20 | |||
21 | check_types() { | ||
22 | X1=`printf "%x" $1 | tail -c 8` | ||
23 | X2=`printf "%x" $2` | ||
24 | X3=`printf "%x" $3` | ||
25 | test $X1 = $X2 | ||
26 | test $X2 = $X3 | ||
27 | test 0x$X3 = $3 | ||
28 | |||
29 | B4=`printf "%x" $4` | ||
30 | B3=`echo -n $X3 | tail -c 3 | head -c 2` | ||
31 | test $B3 = $B4 | ||
32 | } | ||
33 | check_types $ARGS | ||
34 | |||
35 | echo "-:testprobe" >> kprobe_events | ||
36 | clear_trace | ||
37 | test -d events/kprobes/testprobe && exit 1 || exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc index 0bf5085281f3..400e98b64948 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc | |||
@@ -56,7 +56,7 @@ echo "Test histogram with syscall modifier" | |||
56 | 56 | ||
57 | echo 'hist:keys=id.syscall' > events/raw_syscalls/sys_exit/trigger | 57 | echo 'hist:keys=id.syscall' > events/raw_syscalls/sys_exit/trigger |
58 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | 58 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done |
59 | grep "id: sys_" events/raw_syscalls/sys_exit/hist > /dev/null || \ | 59 | grep "id: \(unknown_\|sys_\)" events/raw_syscalls/sys_exit/hist > /dev/null || \ |
60 | fail "syscall modifier on raw_syscalls/sys_exit did not work" | 60 | fail "syscall modifier on raw_syscalls/sys_exit did not work" |
61 | 61 | ||
62 | 62 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc index f84b80d551a2..ed94f0c4e0e4 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc | |||
@@ -23,6 +23,11 @@ if [ ! -f events/sched/sched_process_fork/trigger ]; then | |||
23 | exit_unsupported | 23 | exit_unsupported |
24 | fi | 24 | fi |
25 | 25 | ||
26 | if [ ! -f snapshot ]; then | ||
27 | echo "snapshot is not supported" | ||
28 | exit_unsupported | ||
29 | fi | ||
30 | |||
26 | reset_tracer | 31 | reset_tracer |
27 | do_reset | 32 | do_reset |
28 | 33 | ||
diff --git a/tools/testing/selftests/futex/README b/tools/testing/selftests/futex/README index 0558bb9ce0a6..f3926c33ed4c 100644 --- a/tools/testing/selftests/futex/README +++ b/tools/testing/selftests/futex/README | |||
@@ -59,4 +59,4 @@ o FIXME: decide on a sane test naming scheme. Currently the tests are named | |||
59 | Coding Style | 59 | Coding Style |
60 | ------------ | 60 | ------------ |
61 | o The Futex Test project adheres to the coding standards set forth by Linux | 61 | o The Futex Test project adheres to the coding standards set forth by Linux |
62 | kernel as defined in the Linux source Documentation/CodingStyle. | 62 | kernel as defined in the Linux source Documentation/process/coding-style.rst. |
diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile new file mode 100644 index 000000000000..205e4d10e085 --- /dev/null +++ b/tools/testing/selftests/gpio/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | |||
2 | TEST_PROGS := gpio-mockup.sh | ||
3 | TEST_FILES := gpio-mockup-sysfs.sh $(BINARIES) | ||
4 | BINARIES := gpio-mockup-chardev | ||
5 | |||
6 | include ../lib.mk | ||
7 | |||
8 | all: $(BINARIES) | ||
9 | |||
10 | clean: | ||
11 | $(RM) $(BINARIES) | ||
12 | |||
13 | CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/ | ||
14 | LDLIBS += -lmount -I/usr/include/libmount | ||
15 | |||
16 | $(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h | ||
17 | |||
18 | ../../../gpio/gpio-utils.o: | ||
19 | make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio | ||
20 | |||
21 | ../../../../usr/include/linux/gpio.h: | ||
22 | make -C ../../../.. headers_install INSTALL_HDR_PATH=$(shell pwd)/../../../../usr/ | ||
23 | |||
diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c new file mode 100644 index 000000000000..667e916fa7cc --- /dev/null +++ b/tools/testing/selftests/gpio/gpio-mockup-chardev.c | |||
@@ -0,0 +1,324 @@ | |||
1 | /* | ||
2 | * GPIO chardev test helper | ||
3 | * | ||
4 | * Copyright (C) 2016 Bamvor Jian Zhang | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #define _GNU_SOURCE | ||
12 | #include <unistd.h> | ||
13 | #include <stdio.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <stdio.h> | ||
16 | #include <errno.h> | ||
17 | #include <string.h> | ||
18 | #include <fcntl.h> | ||
19 | #include <getopt.h> | ||
20 | #include <sys/ioctl.h> | ||
21 | #include <libmount.h> | ||
22 | #include <err.h> | ||
23 | #include <dirent.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include "../../../gpio/gpio-utils.h" | ||
26 | |||
27 | #define CONSUMER "gpio-selftest" | ||
28 | #define GC_NUM 10 | ||
29 | enum direction { | ||
30 | OUT, | ||
31 | IN | ||
32 | }; | ||
33 | |||
34 | static int get_debugfs(char **path) | ||
35 | { | ||
36 | struct libmnt_context *cxt; | ||
37 | struct libmnt_table *tb; | ||
38 | struct libmnt_iter *itr = NULL; | ||
39 | struct libmnt_fs *fs; | ||
40 | int found = 0; | ||
41 | |||
42 | cxt = mnt_new_context(); | ||
43 | if (!cxt) | ||
44 | err(EXIT_FAILURE, "libmount context allocation failed"); | ||
45 | |||
46 | itr = mnt_new_iter(MNT_ITER_FORWARD); | ||
47 | if (!itr) | ||
48 | err(EXIT_FAILURE, "failed to initialize libmount iterator"); | ||
49 | |||
50 | if (mnt_context_get_mtab(cxt, &tb)) | ||
51 | err(EXIT_FAILURE, "failed to read mtab"); | ||
52 | |||
53 | while (mnt_table_next_fs(tb, itr, &fs) == 0) { | ||
54 | const char *type = mnt_fs_get_fstype(fs); | ||
55 | |||
56 | if (!strcmp(type, "debugfs")) { | ||
57 | found = 1; | ||
58 | break; | ||
59 | } | ||
60 | } | ||
61 | if (found) | ||
62 | asprintf(path, "%s/gpio", mnt_fs_get_target(fs)); | ||
63 | |||
64 | mnt_free_iter(itr); | ||
65 | mnt_free_context(cxt); | ||
66 | |||
67 | if (!found) | ||
68 | return -1; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int gpio_debugfs_get(const char *consumer, int *dir, int *value) | ||
74 | { | ||
75 | char *debugfs; | ||
76 | FILE *f; | ||
77 | char *line = NULL; | ||
78 | size_t len = 0; | ||
79 | char *cur; | ||
80 | int found = 0; | ||
81 | |||
82 | if (get_debugfs(&debugfs) != 0) | ||
83 | err(EXIT_FAILURE, "debugfs is not mounted"); | ||
84 | |||
85 | f = fopen(debugfs, "r"); | ||
86 | if (!f) | ||
87 | err(EXIT_FAILURE, "read from gpio debugfs failed"); | ||
88 | |||
89 | /* | ||
90 | * gpio-2 ( |gpio-selftest ) in lo | ||
91 | */ | ||
92 | while (getline(&line, &len, f) != -1) { | ||
93 | cur = strstr(line, consumer); | ||
94 | if (cur == NULL) | ||
95 | continue; | ||
96 | |||
97 | cur = strchr(line, ')'); | ||
98 | if (!cur) | ||
99 | continue; | ||
100 | |||
101 | cur += 2; | ||
102 | if (!strncmp(cur, "out", 3)) { | ||
103 | *dir = OUT; | ||
104 | cur += 4; | ||
105 | } else if (!strncmp(cur, "in", 2)) { | ||
106 | *dir = IN; | ||
107 | cur += 4; | ||
108 | } | ||
109 | |||
110 | if (!strncmp(cur, "hi", 2)) | ||
111 | *value = 1; | ||
112 | else if (!strncmp(cur, "lo", 2)) | ||
113 | *value = 0; | ||
114 | |||
115 | found = 1; | ||
116 | break; | ||
117 | } | ||
118 | free(debugfs); | ||
119 | fclose(f); | ||
120 | free(line); | ||
121 | |||
122 | if (!found) | ||
123 | return -1; | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret) | ||
129 | { | ||
130 | struct gpiochip_info *cinfo; | ||
131 | struct gpiochip_info *current; | ||
132 | const struct dirent *ent; | ||
133 | DIR *dp; | ||
134 | char *chrdev_name; | ||
135 | int fd; | ||
136 | int i = 0; | ||
137 | |||
138 | cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1); | ||
139 | if (!cinfo) | ||
140 | err(EXIT_FAILURE, "gpiochip_info allocation failed"); | ||
141 | |||
142 | current = cinfo; | ||
143 | dp = opendir("/dev"); | ||
144 | if (!dp) { | ||
145 | *ret = -errno; | ||
146 | goto error_out; | ||
147 | } else { | ||
148 | *ret = 0; | ||
149 | } | ||
150 | |||
151 | while (ent = readdir(dp), ent) { | ||
152 | if (check_prefix(ent->d_name, "gpiochip")) { | ||
153 | *ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name); | ||
154 | if (*ret < 0) | ||
155 | goto error_out; | ||
156 | |||
157 | fd = open(chrdev_name, 0); | ||
158 | if (fd == -1) { | ||
159 | *ret = -errno; | ||
160 | fprintf(stderr, "Failed to open %s\n", | ||
161 | chrdev_name); | ||
162 | goto error_close_dir; | ||
163 | } | ||
164 | *ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current); | ||
165 | if (*ret == -1) { | ||
166 | perror("Failed to issue CHIPINFO IOCTL\n"); | ||
167 | goto error_close_dir; | ||
168 | } | ||
169 | close(fd); | ||
170 | if (strcmp(current->label, gpiochip_name) == 0 | ||
171 | || check_prefix(current->label, gpiochip_name)) { | ||
172 | *ret = 0; | ||
173 | current++; | ||
174 | i++; | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | if ((!*ret && i == 0) || *ret < 0) { | ||
180 | free(cinfo); | ||
181 | cinfo = NULL; | ||
182 | } | ||
183 | if (!*ret && i > 0) { | ||
184 | cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i); | ||
185 | *ret = i; | ||
186 | } | ||
187 | |||
188 | error_close_dir: | ||
189 | closedir(dp); | ||
190 | error_out: | ||
191 | if (*ret < 0) | ||
192 | err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret)); | ||
193 | |||
194 | return cinfo; | ||
195 | } | ||
196 | |||
197 | int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value) | ||
198 | { | ||
199 | struct gpiohandle_data data; | ||
200 | unsigned int lines[] = {line}; | ||
201 | int fd; | ||
202 | int debugfs_dir = IN; | ||
203 | int debugfs_value = 0; | ||
204 | int ret; | ||
205 | |||
206 | data.values[0] = value; | ||
207 | ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data, | ||
208 | CONSUMER); | ||
209 | if (ret < 0) | ||
210 | goto fail_out; | ||
211 | else | ||
212 | fd = ret; | ||
213 | |||
214 | ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value); | ||
215 | if (ret) { | ||
216 | ret = -EINVAL; | ||
217 | goto fail_out; | ||
218 | } | ||
219 | if (flag & GPIOHANDLE_REQUEST_INPUT) { | ||
220 | if (debugfs_dir != IN) { | ||
221 | errno = -EINVAL; | ||
222 | ret = -errno; | ||
223 | } | ||
224 | } else if (flag & GPIOHANDLE_REQUEST_OUTPUT) { | ||
225 | if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW) | ||
226 | debugfs_value = !debugfs_value; | ||
227 | |||
228 | if (!(debugfs_dir == OUT && value == debugfs_value)) | ||
229 | errno = -EINVAL; | ||
230 | ret = -errno; | ||
231 | |||
232 | } | ||
233 | gpiotools_release_linehandle(fd); | ||
234 | |||
235 | fail_out: | ||
236 | if (ret) | ||
237 | err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>", | ||
238 | cinfo->name, line, flag, value); | ||
239 | |||
240 | return ret; | ||
241 | } | ||
242 | |||
243 | void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line) | ||
244 | { | ||
245 | printf("line<%d>", line); | ||
246 | gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0); | ||
247 | printf("."); | ||
248 | gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1); | ||
249 | printf("."); | ||
250 | gpio_pin_test(cinfo, line, | ||
251 | GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW, | ||
252 | 0); | ||
253 | printf("."); | ||
254 | gpio_pin_test(cinfo, line, | ||
255 | GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW, | ||
256 | 1); | ||
257 | printf("."); | ||
258 | gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0); | ||
259 | printf("."); | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip | ||
264 | * Return 0 if successful or exit with EXIT_FAILURE if test failed. | ||
265 | * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g. | ||
266 | * gpio-mockup | ||
267 | * is_valid_gpio_chip: Whether the gpio_chip is valid. 1 means valid, | ||
268 | * 0 means invalid which could not be found by | ||
269 | * list_gpiochip. | ||
270 | */ | ||
271 | int main(int argc, char *argv[]) | ||
272 | { | ||
273 | char *prefix; | ||
274 | int valid; | ||
275 | struct gpiochip_info *cinfo; | ||
276 | struct gpiochip_info *current; | ||
277 | int i; | ||
278 | int ret; | ||
279 | |||
280 | if (argc < 3) { | ||
281 | printf("Usage: %s prefix is_valid", argv[0]); | ||
282 | exit(EXIT_FAILURE); | ||
283 | } | ||
284 | |||
285 | prefix = argv[1]; | ||
286 | valid = strcmp(argv[2], "true") == 0 ? 1 : 0; | ||
287 | |||
288 | printf("Test gpiochip %s: ", prefix); | ||
289 | cinfo = list_gpiochip(prefix, &ret); | ||
290 | if (!cinfo) { | ||
291 | if (!valid && ret == 0) { | ||
292 | printf("Invalid test successful\n"); | ||
293 | ret = 0; | ||
294 | goto out; | ||
295 | } else { | ||
296 | ret = -EINVAL; | ||
297 | goto out; | ||
298 | } | ||
299 | } else if (cinfo && !valid) { | ||
300 | ret = -EINVAL; | ||
301 | goto out; | ||
302 | } | ||
303 | current = cinfo; | ||
304 | for (i = 0; i < ret; i++) { | ||
305 | gpio_pin_tests(current, 0); | ||
306 | gpio_pin_tests(current, current->lines - 1); | ||
307 | gpio_pin_tests(current, random() % current->lines); | ||
308 | current++; | ||
309 | } | ||
310 | ret = 0; | ||
311 | printf("successful\n"); | ||
312 | |||
313 | out: | ||
314 | if (ret) | ||
315 | fprintf(stderr, "gpio<%s> test failed\n", prefix); | ||
316 | |||
317 | if (cinfo) | ||
318 | free(cinfo); | ||
319 | |||
320 | if (ret) | ||
321 | exit(EXIT_FAILURE); | ||
322 | |||
323 | return ret; | ||
324 | } | ||
diff --git a/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh new file mode 100755 index 000000000000..085d7a39899c --- /dev/null +++ b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh | |||
@@ -0,0 +1,134 @@ | |||
1 | |||
2 | is_consistent() | ||
3 | { | ||
4 | val= | ||
5 | |||
6 | active_low_sysfs=`cat $GPIO_SYSFS/gpio$nr/active_low` | ||
7 | val_sysfs=`cat $GPIO_SYSFS/gpio$nr/value` | ||
8 | dir_sysfs=`cat $GPIO_SYSFS/gpio$nr/direction` | ||
9 | |||
10 | gpio_this_debugfs=`cat $GPIO_DEBUGFS |grep "gpio-$nr" | sed "s/(.*)//g"` | ||
11 | dir_debugfs=`echo $gpio_this_debugfs | awk '{print $2}'` | ||
12 | val_debugfs=`echo $gpio_this_debugfs | awk '{print $3}'` | ||
13 | if [ $val_debugfs = "lo" ]; then | ||
14 | val=0 | ||
15 | elif [ $val_debugfs = "hi" ]; then | ||
16 | val=1 | ||
17 | fi | ||
18 | |||
19 | if [ $active_low_sysfs = "1" ]; then | ||
20 | if [ $val = "0" ]; then | ||
21 | val="1" | ||
22 | else | ||
23 | val="0" | ||
24 | fi | ||
25 | fi | ||
26 | |||
27 | if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then | ||
28 | echo -n "." | ||
29 | else | ||
30 | echo "test fail, exit" | ||
31 | die | ||
32 | fi | ||
33 | } | ||
34 | |||
35 | test_pin_logic() | ||
36 | { | ||
37 | nr=$1 | ||
38 | direction=$2 | ||
39 | active_low=$3 | ||
40 | value=$4 | ||
41 | |||
42 | echo $direction > $GPIO_SYSFS/gpio$nr/direction | ||
43 | echo $active_low > $GPIO_SYSFS/gpio$nr/active_low | ||
44 | if [ $direction = "out" ]; then | ||
45 | echo $value > $GPIO_SYSFS/gpio$nr/value | ||
46 | fi | ||
47 | is_consistent $nr | ||
48 | } | ||
49 | |||
50 | test_one_pin() | ||
51 | { | ||
52 | nr=$1 | ||
53 | |||
54 | echo -n "test pin<$nr>" | ||
55 | |||
56 | echo $nr > $GPIO_SYSFS/export 2>/dev/null | ||
57 | |||
58 | if [ X$? != X0 ]; then | ||
59 | echo "test GPIO pin $nr failed" | ||
60 | die | ||
61 | fi | ||
62 | |||
63 | #"Checking if the sysfs is consistent with debugfs: " | ||
64 | is_consistent $nr | ||
65 | |||
66 | #"Checking the logic of active_low: " | ||
67 | test_pin_logic $nr out 1 1 | ||
68 | test_pin_logic $nr out 1 0 | ||
69 | test_pin_logic $nr out 0 1 | ||
70 | test_pin_logic $nr out 0 0 | ||
71 | |||
72 | #"Checking the logic of direction: " | ||
73 | test_pin_logic $nr in 1 1 | ||
74 | test_pin_logic $nr out 1 0 | ||
75 | test_pin_logic $nr low 0 1 | ||
76 | test_pin_logic $nr high 0 0 | ||
77 | |||
78 | echo $nr > $GPIO_SYSFS/unexport | ||
79 | |||
80 | echo "successful" | ||
81 | } | ||
82 | |||
83 | test_one_pin_fail() | ||
84 | { | ||
85 | nr=$1 | ||
86 | |||
87 | echo $nr > $GPIO_SYSFS/export 2>/dev/null | ||
88 | |||
89 | if [ X$? != X0 ]; then | ||
90 | echo "test invalid pin $nr successful" | ||
91 | else | ||
92 | echo "test invalid pin $nr failed" | ||
93 | echo $nr > $GPIO_SYSFS/unexport 2>/dev/null | ||
94 | die | ||
95 | fi | ||
96 | } | ||
97 | |||
98 | list_chip() | ||
99 | { | ||
100 | echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null` | ||
101 | } | ||
102 | |||
103 | test_chip() | ||
104 | { | ||
105 | chip=$1 | ||
106 | name=`basename $chip` | ||
107 | base=`cat $chip/base` | ||
108 | ngpio=`cat $chip/ngpio` | ||
109 | printf "%-10s %-5s %-5s\n" $name $base $ngpio | ||
110 | if [ $ngpio = "0" ]; then | ||
111 | echo "number of gpio is zero is not allowed". | ||
112 | fi | ||
113 | test_one_pin $base | ||
114 | test_one_pin $(($base + $ngpio - 1)) | ||
115 | test_one_pin $((( RANDOM % $ngpio ) + $base )) | ||
116 | } | ||
117 | |||
118 | test_chips_sysfs() | ||
119 | { | ||
120 | gpiochip=`list_chip $module` | ||
121 | if [ X"$gpiochip" = X ]; then | ||
122 | if [ X"$valid" = Xfalse ]; then | ||
123 | echo "successful" | ||
124 | else | ||
125 | echo "fail" | ||
126 | die | ||
127 | fi | ||
128 | else | ||
129 | for chip in $gpiochip; do | ||
130 | test_chip $chip | ||
131 | done | ||
132 | fi | ||
133 | } | ||
134 | |||
diff --git a/tools/testing/selftests/gpio/gpio-mockup.sh b/tools/testing/selftests/gpio/gpio-mockup.sh new file mode 100755 index 000000000000..b183439e058e --- /dev/null +++ b/tools/testing/selftests/gpio/gpio-mockup.sh | |||
@@ -0,0 +1,201 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | #exit status | ||
4 | #1: run as non-root user | ||
5 | #2: sysfs/debugfs not mount | ||
6 | #3: insert module fail when gpio-mockup is a module. | ||
7 | #4: other reason. | ||
8 | |||
9 | SYSFS= | ||
10 | GPIO_SYSFS= | ||
11 | GPIO_DRV_SYSFS= | ||
12 | DEBUGFS= | ||
13 | GPIO_DEBUGFS= | ||
14 | dev_type= | ||
15 | module= | ||
16 | |||
17 | usage() | ||
18 | { | ||
19 | echo "Usage:" | ||
20 | echo "$0 [-f] [-m name] [-t type]" | ||
21 | echo "-f: full test. It maybe conflict with existence gpio device." | ||
22 | echo "-m: module name, default name is gpio-mockup. It could also test" | ||
23 | echo " other gpio device." | ||
24 | echo "-t: interface type: chardev(char device) and sysfs(being" | ||
25 | echo " deprecated). The first one is default" | ||
26 | echo "" | ||
27 | echo "$0 -h" | ||
28 | echo "This usage" | ||
29 | } | ||
30 | |||
31 | prerequisite() | ||
32 | { | ||
33 | msg="skip all tests:" | ||
34 | if [ $UID != 0 ]; then | ||
35 | echo $msg must be run as root >&2 | ||
36 | exit 1 | ||
37 | fi | ||
38 | SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'` | ||
39 | if [ ! -d "$SYSFS" ]; then | ||
40 | echo $msg sysfs is not mounted >&2 | ||
41 | exit 2 | ||
42 | fi | ||
43 | GPIO_SYSFS=`echo $SYSFS/class/gpio` | ||
44 | GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio` | ||
45 | DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'` | ||
46 | if [ ! -d "$DEBUGFS" ]; then | ||
47 | echo $msg debugfs is not mounted >&2 | ||
48 | exit 2 | ||
49 | fi | ||
50 | GPIO_DEBUGFS=`echo $DEBUGFS/gpio` | ||
51 | source gpio-mockup-sysfs.sh | ||
52 | } | ||
53 | |||
54 | try_insert_module() | ||
55 | { | ||
56 | if [ -d "$GPIO_DRV_SYSFS" ]; then | ||
57 | echo "$GPIO_DRV_SYSFS exist. Skip insert module" | ||
58 | else | ||
59 | modprobe -q $module $1 | ||
60 | if [ X$? != X0 ]; then | ||
61 | echo $msg insmod $module failed >&2 | ||
62 | exit 3 | ||
63 | fi | ||
64 | fi | ||
65 | } | ||
66 | |||
67 | remove_module() | ||
68 | { | ||
69 | modprobe -r -q $module | ||
70 | } | ||
71 | |||
72 | die() | ||
73 | { | ||
74 | remove_module | ||
75 | exit 4 | ||
76 | } | ||
77 | |||
78 | test_chips() | ||
79 | { | ||
80 | if [ X$dev_type = Xsysfs ]; then | ||
81 | echo "WARNING: sysfs ABI of gpio is going to deprecated." | ||
82 | test_chips_sysfs $* | ||
83 | else | ||
84 | $BASE/gpio-mockup-chardev $* | ||
85 | fi | ||
86 | } | ||
87 | |||
88 | gpio_test() | ||
89 | { | ||
90 | param=$1 | ||
91 | valid=$2 | ||
92 | |||
93 | if [ X"$param" = X ]; then | ||
94 | die | ||
95 | fi | ||
96 | try_insert_module "gpio_mockup_ranges=$param" | ||
97 | echo -n "GPIO $module test with ranges: <" | ||
98 | echo "$param>: " | ||
99 | printf "%-10s %s\n" $param | ||
100 | test_chips $module $valid | ||
101 | remove_module | ||
102 | } | ||
103 | |||
104 | BASE=`dirname $0` | ||
105 | |||
106 | dev_type= | ||
107 | TEMP=`getopt -o fhm:t: -n '$0' -- "$@"` | ||
108 | |||
109 | if [ "$?" != "0" ]; then | ||
110 | echo "Parameter process failed, Terminating..." >&2 | ||
111 | exit 1 | ||
112 | fi | ||
113 | |||
114 | # Note the quotes around `$TEMP': they are essential! | ||
115 | eval set -- "$TEMP" | ||
116 | |||
117 | while true; do | ||
118 | case $1 in | ||
119 | -f) | ||
120 | full_test=true | ||
121 | shift | ||
122 | ;; | ||
123 | -h) | ||
124 | usage | ||
125 | exit | ||
126 | ;; | ||
127 | -m) | ||
128 | module=$2 | ||
129 | shift 2 | ||
130 | ;; | ||
131 | -t) | ||
132 | dev_type=$2 | ||
133 | shift 2 | ||
134 | ;; | ||
135 | --) | ||
136 | shift | ||
137 | break | ||
138 | ;; | ||
139 | *) | ||
140 | echo "Internal error!" | ||
141 | exit 1 | ||
142 | ;; | ||
143 | esac | ||
144 | done | ||
145 | |||
146 | if [ X"$module" = X ]; then | ||
147 | module="gpio-mockup" | ||
148 | fi | ||
149 | |||
150 | if [ X$dev_type != Xsysfs ]; then | ||
151 | dev_type="chardev" | ||
152 | fi | ||
153 | |||
154 | prerequisite | ||
155 | |||
156 | echo "1. Test dynamic allocation of gpio successful means insert gpiochip and" | ||
157 | echo " manipulate gpio pin successful" | ||
158 | gpio_test "-1,32" true | ||
159 | gpio_test "-1,32,-1,32" true | ||
160 | gpio_test "-1,32,-1,32,-1,32" true | ||
161 | if [ X$full_test = Xtrue ]; then | ||
162 | gpio_test "-1,32,32,64" true | ||
163 | gpio_test "-1,32,40,64,-1,5" true | ||
164 | gpio_test "-1,32,32,64,-1,32" true | ||
165 | gpio_test "0,32,32,64,-1,32,-1,32" true | ||
166 | gpio_test "-1,32,-1,32,0,32,32,64" true | ||
167 | echo "2. Do basic test: successful means insert gpiochip and" | ||
168 | echo " manipulate gpio pin successful" | ||
169 | gpio_test "0,32" true | ||
170 | gpio_test "0,32,32,64" true | ||
171 | gpio_test "0,32,40,64,64,96" true | ||
172 | fi | ||
173 | echo "3. Error test: successful means insert gpiochip failed" | ||
174 | echo "3.1 Test number of gpio overflow" | ||
175 | #Currently: The max number of gpio(1024) is defined in arm architecture. | ||
176 | gpio_test "-1,32,-1,1024" false | ||
177 | if [ X$full_test = Xtrue ]; then | ||
178 | echo "3.2 Test zero line of gpio" | ||
179 | gpio_test "0,0" false | ||
180 | echo "3.3 Test range overlap" | ||
181 | echo "3.3.1 Test corner case" | ||
182 | gpio_test "0,32,0,1" false | ||
183 | gpio_test "0,32,32,64,32,40" false | ||
184 | gpio_test "0,32,35,64,35,45" false | ||
185 | gpio_test "0,32,31,32" false | ||
186 | gpio_test "0,32,32,64,36,37" false | ||
187 | gpio_test "0,32,35,64,34,36" false | ||
188 | echo "3.3.2 Test inserting invalid second gpiochip" | ||
189 | gpio_test "0,32,30,35" false | ||
190 | gpio_test "0,32,1,5" false | ||
191 | gpio_test "10,32,9,14" false | ||
192 | gpio_test "10,32,30,35" false | ||
193 | echo "3.3.3 Test others" | ||
194 | gpio_test "0,32,40,56,39,45" false | ||
195 | gpio_test "0,32,40,56,30,33" false | ||
196 | gpio_test "0,32,40,56,30,41" false | ||
197 | gpio_test "0,32,40,56,20,21" false | ||
198 | fi | ||
199 | |||
200 | echo GPIO test PASS | ||
201 | |||
diff --git a/tools/testing/selftests/nsfs/.gitignore b/tools/testing/selftests/nsfs/.gitignore new file mode 100644 index 000000000000..2ab2c824ce86 --- /dev/null +++ b/tools/testing/selftests/nsfs/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | owner | ||
2 | pidns | ||
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index db54a33f850f..c2c4211ba58b 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile | |||
@@ -8,7 +8,7 @@ ifeq ($(ARCH),powerpc) | |||
8 | 8 | ||
9 | GIT_VERSION = $(shell git describe --always --long --dirty || echo "unknown") | 9 | GIT_VERSION = $(shell git describe --always --long --dirty || echo "unknown") |
10 | 10 | ||
11 | CFLAGS := -std=gnu99 -Wall -O2 -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CURDIR) $(CFLAGS) | 11 | CFLAGS := -std=gnu99 -Wall -O2 -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CURDIR)/include $(CFLAGS) |
12 | 12 | ||
13 | export CFLAGS | 13 | export CFLAGS |
14 | 14 | ||
@@ -26,7 +26,8 @@ SUB_DIRS = alignment \ | |||
26 | syscalls \ | 26 | syscalls \ |
27 | tm \ | 27 | tm \ |
28 | vphn \ | 28 | vphn \ |
29 | math | 29 | math \ |
30 | ptrace | ||
30 | 31 | ||
31 | endif | 32 | endif |
32 | 33 | ||
diff --git a/tools/testing/selftests/powerpc/benchmarks/.gitignore b/tools/testing/selftests/powerpc/benchmarks/.gitignore index bce49ebd869e..04dc1e6ef2ce 100644 --- a/tools/testing/selftests/powerpc/benchmarks/.gitignore +++ b/tools/testing/selftests/powerpc/benchmarks/.gitignore | |||
@@ -1,4 +1,5 @@ | |||
1 | gettimeofday | 1 | gettimeofday |
2 | context_switch | 2 | context_switch |
3 | mmap_bench | 3 | mmap_bench |
4 | futex_bench \ No newline at end of file | 4 | futex_bench |
5 | null_syscall | ||
diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile index a9adfb7de78f..545077f98f72 100644 --- a/tools/testing/selftests/powerpc/benchmarks/Makefile +++ b/tools/testing/selftests/powerpc/benchmarks/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | TEST_PROGS := gettimeofday context_switch mmap_bench futex_bench | 1 | TEST_PROGS := gettimeofday context_switch mmap_bench futex_bench null_syscall |
2 | 2 | ||
3 | CFLAGS += -O2 | 3 | CFLAGS += -O2 |
4 | 4 | ||
diff --git a/tools/testing/selftests/powerpc/benchmarks/context_switch.c b/tools/testing/selftests/powerpc/benchmarks/context_switch.c index a36883ad48a4..778f5fbfd784 100644 --- a/tools/testing/selftests/powerpc/benchmarks/context_switch.c +++ b/tools/testing/selftests/powerpc/benchmarks/context_switch.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #ifdef __powerpc__ | 28 | #ifdef __powerpc__ |
29 | #include <altivec.h> | 29 | #include <altivec.h> |
30 | #endif | 30 | #endif |
31 | #include "../utils.h" | 31 | #include "utils.h" |
32 | 32 | ||
33 | static unsigned int timeout = 30; | 33 | static unsigned int timeout = 30; |
34 | 34 | ||
diff --git a/tools/testing/selftests/powerpc/benchmarks/null_syscall.c b/tools/testing/selftests/powerpc/benchmarks/null_syscall.c new file mode 100644 index 000000000000..ecc14d68e101 --- /dev/null +++ b/tools/testing/selftests/powerpc/benchmarks/null_syscall.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * Test null syscall performance | ||
3 | * | ||
4 | * Copyright (C) 2009-2015 Anton Blanchard, 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 NR_LOOPS 10000000 | ||
13 | |||
14 | #include <string.h> | ||
15 | #include <stdio.h> | ||
16 | #include <stdlib.h> | ||
17 | #include <unistd.h> | ||
18 | #include <time.h> | ||
19 | #include <sys/types.h> | ||
20 | #include <sys/time.h> | ||
21 | #include <signal.h> | ||
22 | |||
23 | static volatile int soak_done; | ||
24 | unsigned long long clock_frequency; | ||
25 | unsigned long long timebase_frequency; | ||
26 | double timebase_multiplier; | ||
27 | |||
28 | static inline unsigned long long mftb(void) | ||
29 | { | ||
30 | unsigned long low; | ||
31 | |||
32 | asm volatile("mftb %0" : "=r" (low)); | ||
33 | |||
34 | return low; | ||
35 | } | ||
36 | |||
37 | static void sigalrm_handler(int unused) | ||
38 | { | ||
39 | soak_done = 1; | ||
40 | } | ||
41 | |||
42 | /* | ||
43 | * Use a timer instead of busy looping on clock_gettime() so we don't | ||
44 | * pollute profiles with glibc and VDSO hits. | ||
45 | */ | ||
46 | static void cpu_soak_usecs(unsigned long usecs) | ||
47 | { | ||
48 | struct itimerval val; | ||
49 | |||
50 | memset(&val, 0, sizeof(val)); | ||
51 | val.it_value.tv_usec = usecs; | ||
52 | |||
53 | signal(SIGALRM, sigalrm_handler); | ||
54 | setitimer(ITIMER_REAL, &val, NULL); | ||
55 | |||
56 | while (1) { | ||
57 | if (soak_done) | ||
58 | break; | ||
59 | } | ||
60 | |||
61 | signal(SIGALRM, SIG_DFL); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * This only works with recent kernels where cpufreq modifies | ||
66 | * /proc/cpuinfo dynamically. | ||
67 | */ | ||
68 | static void get_proc_frequency(void) | ||
69 | { | ||
70 | FILE *f; | ||
71 | char line[128]; | ||
72 | char *p, *end; | ||
73 | unsigned long v; | ||
74 | double d; | ||
75 | char *override; | ||
76 | |||
77 | /* Try to get out of low power/low frequency mode */ | ||
78 | cpu_soak_usecs(0.25 * 1000000); | ||
79 | |||
80 | f = fopen("/proc/cpuinfo", "r"); | ||
81 | if (f == NULL) | ||
82 | return; | ||
83 | |||
84 | timebase_frequency = 0; | ||
85 | |||
86 | while (fgets(line, sizeof(line), f) != NULL) { | ||
87 | if (strncmp(line, "timebase", 8) == 0) { | ||
88 | p = strchr(line, ':'); | ||
89 | if (p != NULL) { | ||
90 | v = strtoull(p + 1, &end, 0); | ||
91 | if (end != p + 1) | ||
92 | timebase_frequency = v; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | if (((strncmp(line, "clock", 5) == 0) || | ||
97 | (strncmp(line, "cpu MHz", 7) == 0))) { | ||
98 | p = strchr(line, ':'); | ||
99 | if (p != NULL) { | ||
100 | d = strtod(p + 1, &end); | ||
101 | if (end != p + 1) { | ||
102 | /* Find fastest clock frequency */ | ||
103 | if ((d * 1000000ULL) > clock_frequency) | ||
104 | clock_frequency = d * 1000000ULL; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | |||
110 | fclose(f); | ||
111 | |||
112 | override = getenv("FREQUENCY"); | ||
113 | if (override) | ||
114 | clock_frequency = strtoull(override, NULL, 10); | ||
115 | |||
116 | if (timebase_frequency) | ||
117 | timebase_multiplier = (double)clock_frequency | ||
118 | / timebase_frequency; | ||
119 | else | ||
120 | timebase_multiplier = 1; | ||
121 | } | ||
122 | |||
123 | static void do_null_syscall(unsigned long nr) | ||
124 | { | ||
125 | unsigned long i; | ||
126 | |||
127 | for (i = 0; i < nr; i++) | ||
128 | getppid(); | ||
129 | } | ||
130 | |||
131 | #define TIME(A, STR) \ | ||
132 | |||
133 | int main(void) | ||
134 | { | ||
135 | unsigned long tb_start, tb_now; | ||
136 | struct timespec tv_start, tv_now; | ||
137 | unsigned long long elapsed_ns, elapsed_tb; | ||
138 | |||
139 | get_proc_frequency(); | ||
140 | |||
141 | clock_gettime(CLOCK_MONOTONIC, &tv_start); | ||
142 | tb_start = mftb(); | ||
143 | |||
144 | do_null_syscall(NR_LOOPS); | ||
145 | |||
146 | clock_gettime(CLOCK_MONOTONIC, &tv_now); | ||
147 | tb_now = mftb(); | ||
148 | |||
149 | elapsed_ns = (tv_now.tv_sec - tv_start.tv_sec) * 1000000000ULL + | ||
150 | (tv_now.tv_nsec - tv_start.tv_nsec); | ||
151 | elapsed_tb = tb_now - tb_start; | ||
152 | |||
153 | printf("%10.2f ns %10.2f cycles\n", (float)elapsed_ns / NR_LOOPS, | ||
154 | (float)elapsed_tb * timebase_multiplier / NR_LOOPS); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h index 50ae7d2091ce..80d34a9ffff4 100644 --- a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h +++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h | |||
@@ -25,6 +25,8 @@ | |||
25 | 25 | ||
26 | #define PPC_MTOCRF(A, B) mtocrf A, B | 26 | #define PPC_MTOCRF(A, B) mtocrf A, B |
27 | 27 | ||
28 | #define EX_TABLE(x, y) | ||
29 | |||
28 | FUNC_START(enter_vmx_usercopy) | 30 | FUNC_START(enter_vmx_usercopy) |
29 | li r3,1 | 31 | li r3,1 |
30 | blr | 32 | blr |
diff --git a/tools/testing/selftests/powerpc/copyloops/validate.c b/tools/testing/selftests/powerpc/copyloops/validate.c index 1750ff57ee58..7fb436f82d16 100644 --- a/tools/testing/selftests/powerpc/copyloops/validate.c +++ b/tools/testing/selftests/powerpc/copyloops/validate.c | |||
@@ -3,7 +3,7 @@ | |||
3 | #include <stdlib.h> | 3 | #include <stdlib.h> |
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | 5 | ||
6 | #include "../utils.h" | 6 | #include "utils.h" |
7 | 7 | ||
8 | #define MAX_LEN 8192 | 8 | #define MAX_LEN 8192 |
9 | #define MAX_OFFSET 16 | 9 | #define MAX_OFFSET 16 |
diff --git a/tools/testing/selftests/powerpc/dscr/dscr.h b/tools/testing/selftests/powerpc/dscr/dscr.h index a36af1b2c2bb..18ea223bd398 100644 --- a/tools/testing/selftests/powerpc/dscr/dscr.h +++ b/tools/testing/selftests/powerpc/dscr/dscr.h | |||
@@ -28,8 +28,6 @@ | |||
28 | 28 | ||
29 | #include "utils.h" | 29 | #include "utils.h" |
30 | 30 | ||
31 | #define SPRN_DSCR 0x11 /* Privilege state SPR */ | ||
32 | #define SPRN_DSCR_USR 0x03 /* Problem state SPR */ | ||
33 | #define THREADS 100 /* Max threads */ | 31 | #define THREADS 100 /* Max threads */ |
34 | #define COUNT 100 /* Max iterations */ | 32 | #define COUNT 100 /* Max iterations */ |
35 | #define DSCR_MAX 16 /* Max DSCR value */ | 33 | #define DSCR_MAX 16 /* Max DSCR value */ |
@@ -48,14 +46,14 @@ inline unsigned long get_dscr(void) | |||
48 | { | 46 | { |
49 | unsigned long ret; | 47 | unsigned long ret; |
50 | 48 | ||
51 | asm volatile("mfspr %0,%1" : "=r" (ret): "i" (SPRN_DSCR)); | 49 | asm volatile("mfspr %0,%1" : "=r" (ret) : "i" (SPRN_DSCR_PRIV)); |
52 | 50 | ||
53 | return ret; | 51 | return ret; |
54 | } | 52 | } |
55 | 53 | ||
56 | inline void set_dscr(unsigned long val) | 54 | inline void set_dscr(unsigned long val) |
57 | { | 55 | { |
58 | asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR)); | 56 | asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR_PRIV)); |
59 | } | 57 | } |
60 | 58 | ||
61 | /* Problem state DSCR access */ | 59 | /* Problem state DSCR access */ |
@@ -63,14 +61,14 @@ inline unsigned long get_dscr_usr(void) | |||
63 | { | 61 | { |
64 | unsigned long ret; | 62 | unsigned long ret; |
65 | 63 | ||
66 | asm volatile("mfspr %0,%1" : "=r" (ret): "i" (SPRN_DSCR_USR)); | 64 | asm volatile("mfspr %0,%1" : "=r" (ret) : "i" (SPRN_DSCR)); |
67 | 65 | ||
68 | return ret; | 66 | return ret; |
69 | } | 67 | } |
70 | 68 | ||
71 | inline void set_dscr_usr(unsigned long val) | 69 | inline void set_dscr_usr(unsigned long val) |
72 | { | 70 | { |
73 | asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR_USR)); | 71 | asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR)); |
74 | } | 72 | } |
75 | 73 | ||
76 | /* Default DSCR access */ | 74 | /* Default DSCR access */ |
diff --git a/tools/testing/selftests/powerpc/basic_asm.h b/tools/testing/selftests/powerpc/include/basic_asm.h index 3349a0704d1a..12eaddf72e66 100644 --- a/tools/testing/selftests/powerpc/basic_asm.h +++ b/tools/testing/selftests/powerpc/include/basic_asm.h | |||
@@ -4,12 +4,12 @@ | |||
4 | #include <ppc-asm.h> | 4 | #include <ppc-asm.h> |
5 | #include <asm/unistd.h> | 5 | #include <asm/unistd.h> |
6 | 6 | ||
7 | #define LOAD_REG_IMMEDIATE(reg,expr) \ | 7 | #define LOAD_REG_IMMEDIATE(reg, expr) \ |
8 | lis reg,(expr)@highest; \ | 8 | lis reg, (expr)@highest; \ |
9 | ori reg,reg,(expr)@higher; \ | 9 | ori reg, reg, (expr)@higher; \ |
10 | rldicr reg,reg,32,31; \ | 10 | rldicr reg, reg, 32, 31; \ |
11 | oris reg,reg,(expr)@high; \ | 11 | oris reg, reg, (expr)@high; \ |
12 | ori reg,reg,(expr)@l; | 12 | ori reg, reg, (expr)@l; |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * Note: These macros assume that variables being stored on the stack are | 15 | * Note: These macros assume that variables being stored on the stack are |
@@ -20,7 +20,8 @@ | |||
20 | #define STACK_FRAME_MIN_SIZE 32 | 20 | #define STACK_FRAME_MIN_SIZE 32 |
21 | #define STACK_FRAME_TOC_POS 24 | 21 | #define STACK_FRAME_TOC_POS 24 |
22 | #define __STACK_FRAME_PARAM(_param) (32 + ((_param)*8)) | 22 | #define __STACK_FRAME_PARAM(_param) (32 + ((_param)*8)) |
23 | #define __STACK_FRAME_LOCAL(_num_params,_var_num) ((STACK_FRAME_PARAM(_num_params)) + ((_var_num)*8)) | 23 | #define __STACK_FRAME_LOCAL(_num_params, _var_num) \ |
24 | ((STACK_FRAME_PARAM(_num_params)) + ((_var_num)*8)) | ||
24 | #else | 25 | #else |
25 | #define STACK_FRAME_MIN_SIZE 112 | 26 | #define STACK_FRAME_MIN_SIZE 112 |
26 | #define STACK_FRAME_TOC_POS 40 | 27 | #define STACK_FRAME_TOC_POS 40 |
@@ -30,14 +31,16 @@ | |||
30 | * Caveat: if a function passed more than 8 doublewords, the caller will have | 31 | * Caveat: if a function passed more than 8 doublewords, the caller will have |
31 | * made more space... which would render the 112 incorrect. | 32 | * made more space... which would render the 112 incorrect. |
32 | */ | 33 | */ |
33 | #define __STACK_FRAME_LOCAL(_num_params,_var_num) (112 + ((_var_num)*8)) | 34 | #define __STACK_FRAME_LOCAL(_num_params, _var_num) \ |
35 | (112 + ((_var_num)*8)) | ||
34 | #endif | 36 | #endif |
35 | 37 | ||
36 | /* Parameter x saved to the stack */ | 38 | /* Parameter x saved to the stack */ |
37 | #define STACK_FRAME_PARAM(var) __STACK_FRAME_PARAM(var) | 39 | #define STACK_FRAME_PARAM(var) __STACK_FRAME_PARAM(var) |
38 | 40 | ||
39 | /* Local variable x saved to the stack after x parameters */ | 41 | /* Local variable x saved to the stack after x parameters */ |
40 | #define STACK_FRAME_LOCAL(num_params,var) __STACK_FRAME_LOCAL(num_params,var) | 42 | #define STACK_FRAME_LOCAL(num_params, var) \ |
43 | __STACK_FRAME_LOCAL(num_params, var) | ||
41 | #define STACK_FRAME_LR_POS 16 | 44 | #define STACK_FRAME_LR_POS 16 |
42 | #define STACK_FRAME_CR_POS 8 | 45 | #define STACK_FRAME_CR_POS 8 |
43 | 46 | ||
@@ -53,18 +56,18 @@ | |||
53 | */ | 56 | */ |
54 | #define PUSH_BASIC_STACK(_extra) \ | 57 | #define PUSH_BASIC_STACK(_extra) \ |
55 | mflr r0; \ | 58 | mflr r0; \ |
56 | std r0,STACK_FRAME_LR_POS(%r1); \ | 59 | std r0, STACK_FRAME_LR_POS(%r1); \ |
57 | stdu %r1,-(_extra + STACK_FRAME_MIN_SIZE)(%r1); \ | 60 | stdu %r1, -(_extra + STACK_FRAME_MIN_SIZE)(%r1); \ |
58 | mfcr r0; \ | 61 | mfcr r0; \ |
59 | stw r0,STACK_FRAME_CR_POS(%r1); \ | 62 | stw r0, STACK_FRAME_CR_POS(%r1); \ |
60 | std %r2,STACK_FRAME_TOC_POS(%r1); | 63 | std %r2, STACK_FRAME_TOC_POS(%r1); |
61 | 64 | ||
62 | #define POP_BASIC_STACK(_extra) \ | 65 | #define POP_BASIC_STACK(_extra) \ |
63 | ld %r2,STACK_FRAME_TOC_POS(%r1); \ | 66 | ld %r2, STACK_FRAME_TOC_POS(%r1); \ |
64 | lwz r0,STACK_FRAME_CR_POS(%r1); \ | 67 | lwz r0, STACK_FRAME_CR_POS(%r1); \ |
65 | mtcr r0; \ | 68 | mtcr r0; \ |
66 | addi %r1,%r1,(_extra + STACK_FRAME_MIN_SIZE); \ | 69 | addi %r1, %r1, (_extra + STACK_FRAME_MIN_SIZE); \ |
67 | ld r0,STACK_FRAME_LR_POS(%r1); \ | 70 | ld r0, STACK_FRAME_LR_POS(%r1); \ |
68 | mtlr r0; | 71 | mtlr r0; |
69 | 72 | ||
70 | #endif /* _SELFTESTS_POWERPC_BASIC_ASM_H */ | 73 | #endif /* _SELFTESTS_POWERPC_BASIC_ASM_H */ |
diff --git a/tools/testing/selftests/powerpc/fpu_asm.h b/tools/testing/selftests/powerpc/include/fpu_asm.h index 6a387d255e27..6a387d255e27 100644 --- a/tools/testing/selftests/powerpc/fpu_asm.h +++ b/tools/testing/selftests/powerpc/include/fpu_asm.h | |||
diff --git a/tools/testing/selftests/powerpc/gpr_asm.h b/tools/testing/selftests/powerpc/include/gpr_asm.h index f6f38852d3a0..f6f38852d3a0 100644 --- a/tools/testing/selftests/powerpc/gpr_asm.h +++ b/tools/testing/selftests/powerpc/include/gpr_asm.h | |||
diff --git a/tools/testing/selftests/powerpc/instructions.h b/tools/testing/selftests/powerpc/include/instructions.h index 0fb0bd3b28c9..0fb0bd3b28c9 100644 --- a/tools/testing/selftests/powerpc/instructions.h +++ b/tools/testing/selftests/powerpc/include/instructions.h | |||
diff --git a/tools/testing/selftests/powerpc/include/reg.h b/tools/testing/selftests/powerpc/include/reg.h new file mode 100644 index 000000000000..4afdebcce4cd --- /dev/null +++ b/tools/testing/selftests/powerpc/include/reg.h | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * Copyright 2014, Michael Ellerman, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | */ | ||
5 | |||
6 | #ifndef _SELFTESTS_POWERPC_REG_H | ||
7 | #define _SELFTESTS_POWERPC_REG_H | ||
8 | |||
9 | #define __stringify_1(x) #x | ||
10 | #define __stringify(x) __stringify_1(x) | ||
11 | |||
12 | #define mfspr(rn) ({unsigned long rval; \ | ||
13 | asm volatile("mfspr %0," _str(rn) \ | ||
14 | : "=r" (rval)); rval; }) | ||
15 | #define mtspr(rn, v) asm volatile("mtspr " _str(rn) ",%0" : \ | ||
16 | : "r" ((unsigned long)(v)) \ | ||
17 | : "memory") | ||
18 | |||
19 | #define mb() asm volatile("sync" : : : "memory"); | ||
20 | |||
21 | #define SPRN_MMCR2 769 | ||
22 | #define SPRN_MMCRA 770 | ||
23 | #define SPRN_MMCR0 779 | ||
24 | #define MMCR0_PMAO 0x00000080 | ||
25 | #define MMCR0_PMAE 0x04000000 | ||
26 | #define MMCR0_FC 0x80000000 | ||
27 | #define SPRN_EBBHR 804 | ||
28 | #define SPRN_EBBRR 805 | ||
29 | #define SPRN_BESCR 806 /* Branch event status & control register */ | ||
30 | #define SPRN_BESCRS 800 /* Branch event status & control set (1 bits set to 1) */ | ||
31 | #define SPRN_BESCRSU 801 /* Branch event status & control set upper */ | ||
32 | #define SPRN_BESCRR 802 /* Branch event status & control REset (1 bits set to 0) */ | ||
33 | #define SPRN_BESCRRU 803 /* Branch event status & control REset upper */ | ||
34 | |||
35 | #define BESCR_PMEO 0x1 /* PMU Event-based exception Occurred */ | ||
36 | #define BESCR_PME (0x1ul << 32) /* PMU Event-based exception Enable */ | ||
37 | |||
38 | #define SPRN_PMC1 771 | ||
39 | #define SPRN_PMC2 772 | ||
40 | #define SPRN_PMC3 773 | ||
41 | #define SPRN_PMC4 774 | ||
42 | #define SPRN_PMC5 775 | ||
43 | #define SPRN_PMC6 776 | ||
44 | |||
45 | #define SPRN_SIAR 780 | ||
46 | #define SPRN_SDAR 781 | ||
47 | #define SPRN_SIER 768 | ||
48 | |||
49 | #define SPRN_TEXASR 0x82 /* Transaction Exception and Status Register */ | ||
50 | #define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */ | ||
51 | #define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */ | ||
52 | #define SPRN_TAR 0x32f /* Target Address Register */ | ||
53 | |||
54 | #define SPRN_DSCR_PRIV 0x11 /* Privilege State DSCR */ | ||
55 | #define SPRN_DSCR 0x03 /* Data Stream Control Register */ | ||
56 | #define SPRN_PPR 896 /* Program Priority Register */ | ||
57 | |||
58 | /* TEXASR register bits */ | ||
59 | #define TEXASR_FC 0xFE00000000000000 | ||
60 | #define TEXASR_FP 0x0100000000000000 | ||
61 | #define TEXASR_DA 0x0080000000000000 | ||
62 | #define TEXASR_NO 0x0040000000000000 | ||
63 | #define TEXASR_FO 0x0020000000000000 | ||
64 | #define TEXASR_SIC 0x0010000000000000 | ||
65 | #define TEXASR_NTC 0x0008000000000000 | ||
66 | #define TEXASR_TC 0x0004000000000000 | ||
67 | #define TEXASR_TIC 0x0002000000000000 | ||
68 | #define TEXASR_IC 0x0001000000000000 | ||
69 | #define TEXASR_IFC 0x0000800000000000 | ||
70 | #define TEXASR_ABT 0x0000000100000000 | ||
71 | #define TEXASR_SPD 0x0000000080000000 | ||
72 | #define TEXASR_HV 0x0000000020000000 | ||
73 | #define TEXASR_PR 0x0000000010000000 | ||
74 | #define TEXASR_FS 0x0000000008000000 | ||
75 | #define TEXASR_TE 0x0000000004000000 | ||
76 | #define TEXASR_ROT 0x0000000002000000 | ||
77 | |||
78 | /* Vector Instructions */ | ||
79 | #define VSX_XX1(xs, ra, rb) (((xs) & 0x1f) << 21 | ((ra) << 16) | \ | ||
80 | ((rb) << 11) | (((xs) >> 5))) | ||
81 | #define STXVD2X(xs, ra, rb) .long (0x7c000798 | VSX_XX1((xs), (ra), (rb))) | ||
82 | #define LXVD2X(xs, ra, rb) .long (0x7c000698 | VSX_XX1((xs), (ra), (rb))) | ||
83 | |||
84 | #define ASM_LOAD_GPR_IMMED(_asm_symbol_name_immed) \ | ||
85 | "li 14, %[" #_asm_symbol_name_immed "];" \ | ||
86 | "li 15, %[" #_asm_symbol_name_immed "];" \ | ||
87 | "li 16, %[" #_asm_symbol_name_immed "];" \ | ||
88 | "li 17, %[" #_asm_symbol_name_immed "];" \ | ||
89 | "li 18, %[" #_asm_symbol_name_immed "];" \ | ||
90 | "li 19, %[" #_asm_symbol_name_immed "];" \ | ||
91 | "li 20, %[" #_asm_symbol_name_immed "];" \ | ||
92 | "li 21, %[" #_asm_symbol_name_immed "];" \ | ||
93 | "li 22, %[" #_asm_symbol_name_immed "];" \ | ||
94 | "li 23, %[" #_asm_symbol_name_immed "];" \ | ||
95 | "li 24, %[" #_asm_symbol_name_immed "];" \ | ||
96 | "li 25, %[" #_asm_symbol_name_immed "];" \ | ||
97 | "li 26, %[" #_asm_symbol_name_immed "];" \ | ||
98 | "li 27, %[" #_asm_symbol_name_immed "];" \ | ||
99 | "li 28, %[" #_asm_symbol_name_immed "];" \ | ||
100 | "li 29, %[" #_asm_symbol_name_immed "];" \ | ||
101 | "li 30, %[" #_asm_symbol_name_immed "];" \ | ||
102 | "li 31, %[" #_asm_symbol_name_immed "];" | ||
103 | |||
104 | #define ASM_LOAD_FPR_SINGLE_PRECISION(_asm_symbol_name_addr) \ | ||
105 | "lfs 0, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
106 | "lfs 1, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
107 | "lfs 2, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
108 | "lfs 3, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
109 | "lfs 4, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
110 | "lfs 5, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
111 | "lfs 6, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
112 | "lfs 7, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
113 | "lfs 8, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
114 | "lfs 9, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
115 | "lfs 10, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
116 | "lfs 11, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
117 | "lfs 12, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
118 | "lfs 13, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
119 | "lfs 14, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
120 | "lfs 15, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
121 | "lfs 16, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
122 | "lfs 17, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
123 | "lfs 18, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
124 | "lfs 19, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
125 | "lfs 20, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
126 | "lfs 21, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
127 | "lfs 22, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
128 | "lfs 23, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
129 | "lfs 24, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
130 | "lfs 25, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
131 | "lfs 26, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
132 | "lfs 27, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
133 | "lfs 28, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
134 | "lfs 29, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
135 | "lfs 30, 0(%[" #_asm_symbol_name_addr "]);" \ | ||
136 | "lfs 31, 0(%[" #_asm_symbol_name_addr "]);" | ||
137 | |||
138 | #ifndef __ASSEMBLER__ | ||
139 | void store_gpr(unsigned long *addr); | ||
140 | void load_gpr(unsigned long *addr); | ||
141 | void load_fpr_single_precision(float *addr); | ||
142 | void store_fpr_single_precision(float *addr); | ||
143 | #endif /* end of __ASSEMBLER__ */ | ||
144 | |||
145 | #endif /* _SELFTESTS_POWERPC_REG_H */ | ||
diff --git a/tools/testing/selftests/powerpc/subunit.h b/tools/testing/selftests/powerpc/include/subunit.h index 9c6c4e901ab6..9c6c4e901ab6 100644 --- a/tools/testing/selftests/powerpc/subunit.h +++ b/tools/testing/selftests/powerpc/include/subunit.h | |||
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/include/utils.h index 53405e8a52ab..53405e8a52ab 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/include/utils.h | |||
diff --git a/tools/testing/selftests/powerpc/vmx_asm.h b/tools/testing/selftests/powerpc/include/vmx_asm.h index 2eaaeca9cf1d..2eaaeca9cf1d 100644 --- a/tools/testing/selftests/powerpc/vmx_asm.h +++ b/tools/testing/selftests/powerpc/include/vmx_asm.h | |||
diff --git a/tools/testing/selftests/powerpc/vsx_asm.h b/tools/testing/selftests/powerpc/include/vsx_asm.h index d828bfb6ef2d..d828bfb6ef2d 100644 --- a/tools/testing/selftests/powerpc/vsx_asm.h +++ b/tools/testing/selftests/powerpc/include/vsx_asm.h | |||
diff --git a/tools/testing/selftests/powerpc/lib/reg.S b/tools/testing/selftests/powerpc/lib/reg.S new file mode 100644 index 000000000000..0dc44f0da065 --- /dev/null +++ b/tools/testing/selftests/powerpc/lib/reg.S | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * test helper assembly functions | ||
3 | * | ||
4 | * Copyright (C) 2016 Simon Guo, IBM Corporation. | ||
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 | #include <ppc-asm.h> | ||
12 | #include "reg.h" | ||
13 | |||
14 | |||
15 | /* Non volatile GPR - unsigned long buf[18] */ | ||
16 | FUNC_START(load_gpr) | ||
17 | ld 14, 0*8(3) | ||
18 | ld 15, 1*8(3) | ||
19 | ld 16, 2*8(3) | ||
20 | ld 17, 3*8(3) | ||
21 | ld 18, 4*8(3) | ||
22 | ld 19, 5*8(3) | ||
23 | ld 20, 6*8(3) | ||
24 | ld 21, 7*8(3) | ||
25 | ld 22, 8*8(3) | ||
26 | ld 23, 9*8(3) | ||
27 | ld 24, 10*8(3) | ||
28 | ld 25, 11*8(3) | ||
29 | ld 26, 12*8(3) | ||
30 | ld 27, 13*8(3) | ||
31 | ld 28, 14*8(3) | ||
32 | ld 29, 15*8(3) | ||
33 | ld 30, 16*8(3) | ||
34 | ld 31, 17*8(3) | ||
35 | blr | ||
36 | FUNC_END(load_gpr) | ||
37 | |||
38 | FUNC_START(store_gpr) | ||
39 | std 14, 0*8(3) | ||
40 | std 15, 1*8(3) | ||
41 | std 16, 2*8(3) | ||
42 | std 17, 3*8(3) | ||
43 | std 18, 4*8(3) | ||
44 | std 19, 5*8(3) | ||
45 | std 20, 6*8(3) | ||
46 | std 21, 7*8(3) | ||
47 | std 22, 8*8(3) | ||
48 | std 23, 9*8(3) | ||
49 | std 24, 10*8(3) | ||
50 | std 25, 11*8(3) | ||
51 | std 26, 12*8(3) | ||
52 | std 27, 13*8(3) | ||
53 | std 28, 14*8(3) | ||
54 | std 29, 15*8(3) | ||
55 | std 30, 16*8(3) | ||
56 | std 31, 17*8(3) | ||
57 | blr | ||
58 | FUNC_END(store_gpr) | ||
59 | |||
60 | /* Single Precision Float - float buf[32] */ | ||
61 | FUNC_START(load_fpr_single_precision) | ||
62 | lfs 0, 0*4(3) | ||
63 | lfs 1, 1*4(3) | ||
64 | lfs 2, 2*4(3) | ||
65 | lfs 3, 3*4(3) | ||
66 | lfs 4, 4*4(3) | ||
67 | lfs 5, 5*4(3) | ||
68 | lfs 6, 6*4(3) | ||
69 | lfs 7, 7*4(3) | ||
70 | lfs 8, 8*4(3) | ||
71 | lfs 9, 9*4(3) | ||
72 | lfs 10, 10*4(3) | ||
73 | lfs 11, 11*4(3) | ||
74 | lfs 12, 12*4(3) | ||
75 | lfs 13, 13*4(3) | ||
76 | lfs 14, 14*4(3) | ||
77 | lfs 15, 15*4(3) | ||
78 | lfs 16, 16*4(3) | ||
79 | lfs 17, 17*4(3) | ||
80 | lfs 18, 18*4(3) | ||
81 | lfs 19, 19*4(3) | ||
82 | lfs 20, 20*4(3) | ||
83 | lfs 21, 21*4(3) | ||
84 | lfs 22, 22*4(3) | ||
85 | lfs 23, 23*4(3) | ||
86 | lfs 24, 24*4(3) | ||
87 | lfs 25, 25*4(3) | ||
88 | lfs 26, 26*4(3) | ||
89 | lfs 27, 27*4(3) | ||
90 | lfs 28, 28*4(3) | ||
91 | lfs 29, 29*4(3) | ||
92 | lfs 30, 30*4(3) | ||
93 | lfs 31, 31*4(3) | ||
94 | blr | ||
95 | FUNC_END(load_fpr_single_precision) | ||
96 | |||
97 | /* Single Precision Float - float buf[32] */ | ||
98 | FUNC_START(store_fpr_single_precision) | ||
99 | stfs 0, 0*4(3) | ||
100 | stfs 1, 1*4(3) | ||
101 | stfs 2, 2*4(3) | ||
102 | stfs 3, 3*4(3) | ||
103 | stfs 4, 4*4(3) | ||
104 | stfs 5, 5*4(3) | ||
105 | stfs 6, 6*4(3) | ||
106 | stfs 7, 7*4(3) | ||
107 | stfs 8, 8*4(3) | ||
108 | stfs 9, 9*4(3) | ||
109 | stfs 10, 10*4(3) | ||
110 | stfs 11, 11*4(3) | ||
111 | stfs 12, 12*4(3) | ||
112 | stfs 13, 13*4(3) | ||
113 | stfs 14, 14*4(3) | ||
114 | stfs 15, 15*4(3) | ||
115 | stfs 16, 16*4(3) | ||
116 | stfs 17, 17*4(3) | ||
117 | stfs 18, 18*4(3) | ||
118 | stfs 19, 19*4(3) | ||
119 | stfs 20, 20*4(3) | ||
120 | stfs 21, 21*4(3) | ||
121 | stfs 22, 22*4(3) | ||
122 | stfs 23, 23*4(3) | ||
123 | stfs 24, 24*4(3) | ||
124 | stfs 25, 25*4(3) | ||
125 | stfs 26, 26*4(3) | ||
126 | stfs 27, 27*4(3) | ||
127 | stfs 28, 28*4(3) | ||
128 | stfs 29, 29*4(3) | ||
129 | stfs 30, 30*4(3) | ||
130 | stfs 31, 31*4(3) | ||
131 | blr | ||
132 | FUNC_END(store_fpr_single_precision) | ||
133 | |||
134 | /* VMX/VSX registers - unsigned long buf[128] */ | ||
135 | FUNC_START(loadvsx) | ||
136 | lis 4, 0 | ||
137 | LXVD2X (0,(4),(3)) | ||
138 | addi 4, 4, 16 | ||
139 | LXVD2X (1,(4),(3)) | ||
140 | addi 4, 4, 16 | ||
141 | LXVD2X (2,(4),(3)) | ||
142 | addi 4, 4, 16 | ||
143 | LXVD2X (3,(4),(3)) | ||
144 | addi 4, 4, 16 | ||
145 | LXVD2X (4,(4),(3)) | ||
146 | addi 4, 4, 16 | ||
147 | LXVD2X (5,(4),(3)) | ||
148 | addi 4, 4, 16 | ||
149 | LXVD2X (6,(4),(3)) | ||
150 | addi 4, 4, 16 | ||
151 | LXVD2X (7,(4),(3)) | ||
152 | addi 4, 4, 16 | ||
153 | LXVD2X (8,(4),(3)) | ||
154 | addi 4, 4, 16 | ||
155 | LXVD2X (9,(4),(3)) | ||
156 | addi 4, 4, 16 | ||
157 | LXVD2X (10,(4),(3)) | ||
158 | addi 4, 4, 16 | ||
159 | LXVD2X (11,(4),(3)) | ||
160 | addi 4, 4, 16 | ||
161 | LXVD2X (12,(4),(3)) | ||
162 | addi 4, 4, 16 | ||
163 | LXVD2X (13,(4),(3)) | ||
164 | addi 4, 4, 16 | ||
165 | LXVD2X (14,(4),(3)) | ||
166 | addi 4, 4, 16 | ||
167 | LXVD2X (15,(4),(3)) | ||
168 | addi 4, 4, 16 | ||
169 | LXVD2X (16,(4),(3)) | ||
170 | addi 4, 4, 16 | ||
171 | LXVD2X (17,(4),(3)) | ||
172 | addi 4, 4, 16 | ||
173 | LXVD2X (18,(4),(3)) | ||
174 | addi 4, 4, 16 | ||
175 | LXVD2X (19,(4),(3)) | ||
176 | addi 4, 4, 16 | ||
177 | LXVD2X (20,(4),(3)) | ||
178 | addi 4, 4, 16 | ||
179 | LXVD2X (21,(4),(3)) | ||
180 | addi 4, 4, 16 | ||
181 | LXVD2X (22,(4),(3)) | ||
182 | addi 4, 4, 16 | ||
183 | LXVD2X (23,(4),(3)) | ||
184 | addi 4, 4, 16 | ||
185 | LXVD2X (24,(4),(3)) | ||
186 | addi 4, 4, 16 | ||
187 | LXVD2X (25,(4),(3)) | ||
188 | addi 4, 4, 16 | ||
189 | LXVD2X (26,(4),(3)) | ||
190 | addi 4, 4, 16 | ||
191 | LXVD2X (27,(4),(3)) | ||
192 | addi 4, 4, 16 | ||
193 | LXVD2X (28,(4),(3)) | ||
194 | addi 4, 4, 16 | ||
195 | LXVD2X (29,(4),(3)) | ||
196 | addi 4, 4, 16 | ||
197 | LXVD2X (30,(4),(3)) | ||
198 | addi 4, 4, 16 | ||
199 | LXVD2X (31,(4),(3)) | ||
200 | addi 4, 4, 16 | ||
201 | LXVD2X (32,(4),(3)) | ||
202 | addi 4, 4, 16 | ||
203 | LXVD2X (33,(4),(3)) | ||
204 | addi 4, 4, 16 | ||
205 | LXVD2X (34,(4),(3)) | ||
206 | addi 4, 4, 16 | ||
207 | LXVD2X (35,(4),(3)) | ||
208 | addi 4, 4, 16 | ||
209 | LXVD2X (36,(4),(3)) | ||
210 | addi 4, 4, 16 | ||
211 | LXVD2X (37,(4),(3)) | ||
212 | addi 4, 4, 16 | ||
213 | LXVD2X (38,(4),(3)) | ||
214 | addi 4, 4, 16 | ||
215 | LXVD2X (39,(4),(3)) | ||
216 | addi 4, 4, 16 | ||
217 | LXVD2X (40,(4),(3)) | ||
218 | addi 4, 4, 16 | ||
219 | LXVD2X (41,(4),(3)) | ||
220 | addi 4, 4, 16 | ||
221 | LXVD2X (42,(4),(3)) | ||
222 | addi 4, 4, 16 | ||
223 | LXVD2X (43,(4),(3)) | ||
224 | addi 4, 4, 16 | ||
225 | LXVD2X (44,(4),(3)) | ||
226 | addi 4, 4, 16 | ||
227 | LXVD2X (45,(4),(3)) | ||
228 | addi 4, 4, 16 | ||
229 | LXVD2X (46,(4),(3)) | ||
230 | addi 4, 4, 16 | ||
231 | LXVD2X (47,(4),(3)) | ||
232 | addi 4, 4, 16 | ||
233 | LXVD2X (48,(4),(3)) | ||
234 | addi 4, 4, 16 | ||
235 | LXVD2X (49,(4),(3)) | ||
236 | addi 4, 4, 16 | ||
237 | LXVD2X (50,(4),(3)) | ||
238 | addi 4, 4, 16 | ||
239 | LXVD2X (51,(4),(3)) | ||
240 | addi 4, 4, 16 | ||
241 | LXVD2X (52,(4),(3)) | ||
242 | addi 4, 4, 16 | ||
243 | LXVD2X (53,(4),(3)) | ||
244 | addi 4, 4, 16 | ||
245 | LXVD2X (54,(4),(3)) | ||
246 | addi 4, 4, 16 | ||
247 | LXVD2X (55,(4),(3)) | ||
248 | addi 4, 4, 16 | ||
249 | LXVD2X (56,(4),(3)) | ||
250 | addi 4, 4, 16 | ||
251 | LXVD2X (57,(4),(3)) | ||
252 | addi 4, 4, 16 | ||
253 | LXVD2X (58,(4),(3)) | ||
254 | addi 4, 4, 16 | ||
255 | LXVD2X (59,(4),(3)) | ||
256 | addi 4, 4, 16 | ||
257 | LXVD2X (60,(4),(3)) | ||
258 | addi 4, 4, 16 | ||
259 | LXVD2X (61,(4),(3)) | ||
260 | addi 4, 4, 16 | ||
261 | LXVD2X (62,(4),(3)) | ||
262 | addi 4, 4, 16 | ||
263 | LXVD2X (63,(4),(3)) | ||
264 | blr | ||
265 | FUNC_END(loadvsx) | ||
266 | |||
267 | FUNC_START(storevsx) | ||
268 | lis 4, 0 | ||
269 | STXVD2X (0,(4),(3)) | ||
270 | addi 4, 4, 16 | ||
271 | STXVD2X (1,(4),(3)) | ||
272 | addi 4, 4, 16 | ||
273 | STXVD2X (2,(4),(3)) | ||
274 | addi 4, 4, 16 | ||
275 | STXVD2X (3,(4),(3)) | ||
276 | addi 4, 4, 16 | ||
277 | STXVD2X (4,(4),(3)) | ||
278 | addi 4, 4, 16 | ||
279 | STXVD2X (5,(4),(3)) | ||
280 | addi 4, 4, 16 | ||
281 | STXVD2X (6,(4),(3)) | ||
282 | addi 4, 4, 16 | ||
283 | STXVD2X (7,(4),(3)) | ||
284 | addi 4, 4, 16 | ||
285 | STXVD2X (8,(4),(3)) | ||
286 | addi 4, 4, 16 | ||
287 | STXVD2X (9,(4),(3)) | ||
288 | addi 4, 4, 16 | ||
289 | STXVD2X (10,(4),(3)) | ||
290 | addi 4, 4, 16 | ||
291 | STXVD2X (11,(4),(3)) | ||
292 | addi 4, 4, 16 | ||
293 | STXVD2X (12,(4),(3)) | ||
294 | addi 4, 4, 16 | ||
295 | STXVD2X (13,(4),(3)) | ||
296 | addi 4, 4, 16 | ||
297 | STXVD2X (14,(4),(3)) | ||
298 | addi 4, 4, 16 | ||
299 | STXVD2X (15,(4),(3)) | ||
300 | addi 4, 4, 16 | ||
301 | STXVD2X (16,(4),(3)) | ||
302 | addi 4, 4, 16 | ||
303 | STXVD2X (17,(4),(3)) | ||
304 | addi 4, 4, 16 | ||
305 | STXVD2X (18,(4),(3)) | ||
306 | addi 4, 4, 16 | ||
307 | STXVD2X (19,(4),(3)) | ||
308 | addi 4, 4, 16 | ||
309 | STXVD2X (20,(4),(3)) | ||
310 | addi 4, 4, 16 | ||
311 | STXVD2X (21,(4),(3)) | ||
312 | addi 4, 4, 16 | ||
313 | STXVD2X (22,(4),(3)) | ||
314 | addi 4, 4, 16 | ||
315 | STXVD2X (23,(4),(3)) | ||
316 | addi 4, 4, 16 | ||
317 | STXVD2X (24,(4),(3)) | ||
318 | addi 4, 4, 16 | ||
319 | STXVD2X (25,(4),(3)) | ||
320 | addi 4, 4, 16 | ||
321 | STXVD2X (26,(4),(3)) | ||
322 | addi 4, 4, 16 | ||
323 | STXVD2X (27,(4),(3)) | ||
324 | addi 4, 4, 16 | ||
325 | STXVD2X (28,(4),(3)) | ||
326 | addi 4, 4, 16 | ||
327 | STXVD2X (29,(4),(3)) | ||
328 | addi 4, 4, 16 | ||
329 | STXVD2X (30,(4),(3)) | ||
330 | addi 4, 4, 16 | ||
331 | STXVD2X (31,(4),(3)) | ||
332 | addi 4, 4, 16 | ||
333 | STXVD2X (32,(4),(3)) | ||
334 | addi 4, 4, 16 | ||
335 | STXVD2X (33,(4),(3)) | ||
336 | addi 4, 4, 16 | ||
337 | STXVD2X (34,(4),(3)) | ||
338 | addi 4, 4, 16 | ||
339 | STXVD2X (35,(4),(3)) | ||
340 | addi 4, 4, 16 | ||
341 | STXVD2X (36,(4),(3)) | ||
342 | addi 4, 4, 16 | ||
343 | STXVD2X (37,(4),(3)) | ||
344 | addi 4, 4, 16 | ||
345 | STXVD2X (38,(4),(3)) | ||
346 | addi 4, 4, 16 | ||
347 | STXVD2X (39,(4),(3)) | ||
348 | addi 4, 4, 16 | ||
349 | STXVD2X (40,(4),(3)) | ||
350 | addi 4, 4, 16 | ||
351 | STXVD2X (41,(4),(3)) | ||
352 | addi 4, 4, 16 | ||
353 | STXVD2X (42,(4),(3)) | ||
354 | addi 4, 4, 16 | ||
355 | STXVD2X (43,(4),(3)) | ||
356 | addi 4, 4, 16 | ||
357 | STXVD2X (44,(4),(3)) | ||
358 | addi 4, 4, 16 | ||
359 | STXVD2X (45,(4),(3)) | ||
360 | addi 4, 4, 16 | ||
361 | STXVD2X (46,(4),(3)) | ||
362 | addi 4, 4, 16 | ||
363 | STXVD2X (47,(4),(3)) | ||
364 | addi 4, 4, 16 | ||
365 | STXVD2X (48,(4),(3)) | ||
366 | addi 4, 4, 16 | ||
367 | STXVD2X (49,(4),(3)) | ||
368 | addi 4, 4, 16 | ||
369 | STXVD2X (50,(4),(3)) | ||
370 | addi 4, 4, 16 | ||
371 | STXVD2X (51,(4),(3)) | ||
372 | addi 4, 4, 16 | ||
373 | STXVD2X (52,(4),(3)) | ||
374 | addi 4, 4, 16 | ||
375 | STXVD2X (53,(4),(3)) | ||
376 | addi 4, 4, 16 | ||
377 | STXVD2X (54,(4),(3)) | ||
378 | addi 4, 4, 16 | ||
379 | STXVD2X (55,(4),(3)) | ||
380 | addi 4, 4, 16 | ||
381 | STXVD2X (56,(4),(3)) | ||
382 | addi 4, 4, 16 | ||
383 | STXVD2X (57,(4),(3)) | ||
384 | addi 4, 4, 16 | ||
385 | STXVD2X (58,(4),(3)) | ||
386 | addi 4, 4, 16 | ||
387 | STXVD2X (59,(4),(3)) | ||
388 | addi 4, 4, 16 | ||
389 | STXVD2X (60,(4),(3)) | ||
390 | addi 4, 4, 16 | ||
391 | STXVD2X (61,(4),(3)) | ||
392 | addi 4, 4, 16 | ||
393 | STXVD2X (62,(4),(3)) | ||
394 | addi 4, 4, 16 | ||
395 | STXVD2X (63,(4),(3)) | ||
396 | blr | ||
397 | FUNC_END(storevsx) | ||
diff --git a/tools/testing/selftests/powerpc/math/fpu_asm.S b/tools/testing/selftests/powerpc/math/fpu_asm.S index 241f067a510f..8a04bb117b69 100644 --- a/tools/testing/selftests/powerpc/math/fpu_asm.S +++ b/tools/testing/selftests/powerpc/math/fpu_asm.S | |||
@@ -7,8 +7,8 @@ | |||
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "../basic_asm.h" | 10 | #include "basic_asm.h" |
11 | #include "../fpu_asm.h" | 11 | #include "fpu_asm.h" |
12 | 12 | ||
13 | FUNC_START(check_fpu) | 13 | FUNC_START(check_fpu) |
14 | mr r4,r3 | 14 | mr r4,r3 |
diff --git a/tools/testing/selftests/powerpc/math/vmx_asm.S b/tools/testing/selftests/powerpc/math/vmx_asm.S index fd74da488625..cb1e5ae1be99 100644 --- a/tools/testing/selftests/powerpc/math/vmx_asm.S +++ b/tools/testing/selftests/powerpc/math/vmx_asm.S | |||
@@ -7,8 +7,8 @@ | |||
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "../basic_asm.h" | 10 | #include "basic_asm.h" |
11 | #include "../vmx_asm.h" | 11 | #include "vmx_asm.h" |
12 | 12 | ||
13 | # Should be safe from C, only touches r4, r5 and v0,v1,v2 | 13 | # Should be safe from C, only touches r4, r5 and v0,v1,v2 |
14 | FUNC_START(check_vmx) | 14 | FUNC_START(check_vmx) |
diff --git a/tools/testing/selftests/powerpc/math/vsx_asm.S b/tools/testing/selftests/powerpc/math/vsx_asm.S index a110dd882d5e..8f431f6abc49 100644 --- a/tools/testing/selftests/powerpc/math/vsx_asm.S +++ b/tools/testing/selftests/powerpc/math/vsx_asm.S | |||
@@ -7,8 +7,8 @@ | |||
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "../basic_asm.h" | 10 | #include "basic_asm.h" |
11 | #include "../vsx_asm.h" | 11 | #include "vsx_asm.h" |
12 | 12 | ||
13 | #long check_vsx(vector int *r3); | 13 | #long check_vsx(vector int *r3); |
14 | #This function wraps storeing VSX regs to the end of an array and a | 14 | #This function wraps storeing VSX regs to the end of an array and a |
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/.gitignore b/tools/testing/selftests/powerpc/pmu/ebb/.gitignore index 44b7df14a936..42bddbed8b64 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/.gitignore +++ b/tools/testing/selftests/powerpc/pmu/ebb/.gitignore | |||
@@ -20,5 +20,3 @@ back_to_back_ebbs_test | |||
20 | lost_exception_test | 20 | lost_exception_test |
21 | no_handler_test | 21 | no_handler_test |
22 | cycles_with_mmcr2_test | 22 | cycles_with_mmcr2_test |
23 | ebb_lmr | ||
24 | ebb_lmr_regs \ No newline at end of file | ||
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile index 6b0453e60d53..8d2279c4bb4b 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile +++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile | |||
@@ -14,7 +14,7 @@ TEST_PROGS := reg_access_test event_attributes_test cycles_test \ | |||
14 | fork_cleanup_test ebb_on_child_test \ | 14 | fork_cleanup_test ebb_on_child_test \ |
15 | ebb_on_willing_child_test back_to_back_ebbs_test \ | 15 | ebb_on_willing_child_test back_to_back_ebbs_test \ |
16 | lost_exception_test no_handler_test \ | 16 | lost_exception_test no_handler_test \ |
17 | cycles_with_mmcr2_test ebb_lmr ebb_lmr_regs | 17 | cycles_with_mmcr2_test |
18 | 18 | ||
19 | all: $(TEST_PROGS) | 19 | all: $(TEST_PROGS) |
20 | 20 | ||
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.c deleted file mode 100644 index c47ebd55ba4d..000000000000 --- a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.c +++ /dev/null | |||
@@ -1,143 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2016, Jack Miller, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <stdio.h> | ||
8 | |||
9 | #include "ebb.h" | ||
10 | #include "ebb_lmr.h" | ||
11 | |||
12 | #define SIZE (32 * 1024 * 1024) /* 32M */ | ||
13 | #define LM_SIZE 0 /* Smallest encoding, 32M */ | ||
14 | |||
15 | #define SECTIONS 64 /* 1 per bit in LMSER */ | ||
16 | #define SECTION_SIZE (SIZE / SECTIONS) | ||
17 | #define SECTION_LONGS (SECTION_SIZE / sizeof(long)) | ||
18 | |||
19 | static unsigned long *test_mem; | ||
20 | |||
21 | static int lmr_count = 0; | ||
22 | |||
23 | void ebb_lmr_handler(void) | ||
24 | { | ||
25 | lmr_count++; | ||
26 | } | ||
27 | |||
28 | void ldmx_full_section(unsigned long *mem, int section) | ||
29 | { | ||
30 | unsigned long *ptr; | ||
31 | int i; | ||
32 | |||
33 | for (i = 0; i < SECTION_LONGS; i++) { | ||
34 | ptr = &mem[(SECTION_LONGS * section) + i]; | ||
35 | ldmx((unsigned long) &ptr); | ||
36 | ebb_lmr_reset(); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | unsigned long section_masks[] = { | ||
41 | 0x8000000000000000, | ||
42 | 0xFF00000000000000, | ||
43 | 0x0000000F70000000, | ||
44 | 0x8000000000000001, | ||
45 | 0xF0F0F0F0F0F0F0F0, | ||
46 | 0x0F0F0F0F0F0F0F0F, | ||
47 | 0x0 | ||
48 | }; | ||
49 | |||
50 | int ebb_lmr_section_test(unsigned long *mem) | ||
51 | { | ||
52 | unsigned long *mask = section_masks; | ||
53 | int i; | ||
54 | |||
55 | for (; *mask; mask++) { | ||
56 | mtspr(SPRN_LMSER, *mask); | ||
57 | printf("Testing mask 0x%016lx\n", mfspr(SPRN_LMSER)); | ||
58 | |||
59 | for (i = 0; i < 64; i++) { | ||
60 | lmr_count = 0; | ||
61 | ldmx_full_section(mem, i); | ||
62 | if (*mask & (1UL << (63 - i))) | ||
63 | FAIL_IF(lmr_count != SECTION_LONGS); | ||
64 | else | ||
65 | FAIL_IF(lmr_count); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int ebb_lmr(void) | ||
73 | { | ||
74 | int i; | ||
75 | |||
76 | SKIP_IF(!lmr_is_supported()); | ||
77 | |||
78 | setup_ebb_handler(ebb_lmr_handler); | ||
79 | |||
80 | ebb_global_enable(); | ||
81 | |||
82 | FAIL_IF(posix_memalign((void **)&test_mem, SIZE, SIZE) != 0); | ||
83 | |||
84 | mtspr(SPRN_LMSER, 0); | ||
85 | |||
86 | FAIL_IF(mfspr(SPRN_LMSER) != 0); | ||
87 | |||
88 | mtspr(SPRN_LMRR, ((unsigned long)test_mem | LM_SIZE)); | ||
89 | |||
90 | FAIL_IF(mfspr(SPRN_LMRR) != ((unsigned long)test_mem | LM_SIZE)); | ||
91 | |||
92 | /* Read every single byte to ensure we get no false positives */ | ||
93 | for (i = 0; i < SECTIONS; i++) | ||
94 | ldmx_full_section(test_mem, i); | ||
95 | |||
96 | FAIL_IF(lmr_count != 0); | ||
97 | |||
98 | /* Turn on the first section */ | ||
99 | |||
100 | mtspr(SPRN_LMSER, (1UL << 63)); | ||
101 | FAIL_IF(mfspr(SPRN_LMSER) != (1UL << 63)); | ||
102 | |||
103 | /* Enable LM (BESCR) */ | ||
104 | |||
105 | mtspr(SPRN_BESCR, mfspr(SPRN_BESCR) | BESCR_LME); | ||
106 | FAIL_IF(!(mfspr(SPRN_BESCR) & BESCR_LME)); | ||
107 | |||
108 | ldmx((unsigned long)&test_mem); | ||
109 | |||
110 | FAIL_IF(lmr_count != 1); // exactly one exception | ||
111 | FAIL_IF(mfspr(SPRN_BESCR) & BESCR_LME); // LM now disabled | ||
112 | FAIL_IF(!(mfspr(SPRN_BESCR) & BESCR_LMEO)); // occurred bit set | ||
113 | |||
114 | printf("Simple LMR EBB OK\n"); | ||
115 | |||
116 | /* This shouldn't cause an EBB since it's been disabled */ | ||
117 | ldmx((unsigned long)&test_mem); | ||
118 | FAIL_IF(lmr_count != 1); | ||
119 | |||
120 | printf("LMR disable on EBB OK\n"); | ||
121 | |||
122 | ebb_lmr_reset(); | ||
123 | |||
124 | /* This should cause an EBB or reset is broken */ | ||
125 | ldmx((unsigned long)&test_mem); | ||
126 | FAIL_IF(lmr_count != 2); | ||
127 | |||
128 | printf("LMR reset EBB OK\n"); | ||
129 | |||
130 | ebb_lmr_reset(); | ||
131 | |||
132 | return ebb_lmr_section_test(test_mem); | ||
133 | } | ||
134 | |||
135 | int main(void) | ||
136 | { | ||
137 | int ret = test_harness(ebb_lmr, "ebb_lmr"); | ||
138 | |||
139 | if (test_mem) | ||
140 | free(test_mem); | ||
141 | |||
142 | return ret; | ||
143 | } | ||
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.h b/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.h deleted file mode 100644 index ef50abd557cd..000000000000 --- a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.h +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | #ifndef _SELFTESTS_POWERPC_PMU_EBB_LMR_H | ||
2 | #define _SELFTESTS_POWERPC_PMU_EBB_LMR_H | ||
3 | |||
4 | #include "reg.h" | ||
5 | |||
6 | #ifndef PPC_FEATURE2_ARCH_3_00 | ||
7 | #define PPC_FEATURE2_ARCH_3_00 0x00800000 | ||
8 | #endif | ||
9 | |||
10 | #define lmr_is_supported() have_hwcap2(PPC_FEATURE2_ARCH_3_00) | ||
11 | |||
12 | static inline void ebb_lmr_reset(void) | ||
13 | { | ||
14 | unsigned long bescr = mfspr(SPRN_BESCR); | ||
15 | bescr &= ~(BESCR_LMEO); | ||
16 | bescr |= BESCR_LME; | ||
17 | mtspr(SPRN_BESCR, bescr); | ||
18 | } | ||
19 | |||
20 | #define LDMX(t, a, b)\ | ||
21 | (0x7c00026a | \ | ||
22 | (((t) & 0x1f) << 21) | \ | ||
23 | (((a) & 0x1f) << 16) | \ | ||
24 | (((b) & 0x1f) << 11)) | ||
25 | |||
26 | static inline unsigned long ldmx(unsigned long address) | ||
27 | { | ||
28 | unsigned long ret; | ||
29 | |||
30 | asm volatile ("mr 9, %1\r\n" | ||
31 | ".long " __stringify(LDMX(9, 0, 9)) "\r\n" | ||
32 | "mr %0, 9\r\n":"=r"(ret) | ||
33 | :"r"(address) | ||
34 | :"r9"); | ||
35 | |||
36 | return ret; | ||
37 | } | ||
38 | |||
39 | #endif | ||
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr_regs.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr_regs.c deleted file mode 100644 index aff4241fd88a..000000000000 --- a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr_regs.c +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2016, Jack Miller, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <stdio.h> | ||
8 | #include <unistd.h> | ||
9 | |||
10 | #include "ebb.h" | ||
11 | #include "ebb_lmr.h" | ||
12 | |||
13 | #define CHECKS 10000 | ||
14 | |||
15 | int ebb_lmr_regs(void) | ||
16 | { | ||
17 | int i; | ||
18 | |||
19 | SKIP_IF(!lmr_is_supported()); | ||
20 | |||
21 | ebb_global_enable(); | ||
22 | |||
23 | for (i = 0; i < CHECKS; i++) { | ||
24 | mtspr(SPRN_LMRR, i << 25); // skip size and rsvd bits | ||
25 | mtspr(SPRN_LMSER, i); | ||
26 | |||
27 | FAIL_IF(mfspr(SPRN_LMRR) != (i << 25)); | ||
28 | FAIL_IF(mfspr(SPRN_LMSER) != i); | ||
29 | } | ||
30 | |||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | int main(void) | ||
35 | { | ||
36 | return test_harness(ebb_lmr_regs, "ebb_lmr_regs"); | ||
37 | } | ||
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c index 8b992fa5b478..5bf5dd40822b 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.c +++ b/tools/testing/selftests/powerpc/pmu/lib.c | |||
@@ -193,9 +193,9 @@ bool require_paranoia_below(int level) | |||
193 | long current; | 193 | long current; |
194 | char *end, buf[16]; | 194 | char *end, buf[16]; |
195 | FILE *f; | 195 | FILE *f; |
196 | int rc; | 196 | bool rc; |
197 | 197 | ||
198 | rc = -1; | 198 | rc = false; |
199 | 199 | ||
200 | f = fopen(PARANOID_PATH, "r"); | 200 | f = fopen(PARANOID_PATH, "r"); |
201 | if (!f) { | 201 | if (!f) { |
@@ -218,7 +218,7 @@ bool require_paranoia_below(int level) | |||
218 | if (current >= level) | 218 | if (current >= level) |
219 | goto out_close; | 219 | goto out_close; |
220 | 220 | ||
221 | rc = 0; | 221 | rc = true; |
222 | out_close: | 222 | out_close: |
223 | fclose(f); | 223 | fclose(f); |
224 | out: | 224 | out: |
diff --git a/tools/testing/selftests/powerpc/primitives/asm/firmware.h b/tools/testing/selftests/powerpc/primitives/asm/firmware.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/asm/firmware.h | |||
diff --git a/tools/testing/selftests/powerpc/primitives/asm/ppc_asm.h b/tools/testing/selftests/powerpc/primitives/asm/ppc_asm.h new file mode 120000 index 000000000000..66c8193224e9 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/asm/ppc_asm.h | |||
@@ -0,0 +1 @@ | |||
../../../../../../arch/powerpc/include/asm/ppc_asm.h \ No newline at end of file | |||
diff --git a/tools/testing/selftests/powerpc/primitives/asm/processor.h b/tools/testing/selftests/powerpc/primitives/asm/processor.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/asm/processor.h | |||
diff --git a/tools/testing/selftests/powerpc/primitives/linux/stringify.h b/tools/testing/selftests/powerpc/primitives/linux/stringify.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/linux/stringify.h | |||
diff --git a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c index 6cae06117b55..ed3239bbfae2 100644 --- a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c +++ b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c | |||
@@ -73,20 +73,23 @@ extern char __stop___ex_table[]; | |||
73 | #error implement UCONTEXT_NIA | 73 | #error implement UCONTEXT_NIA |
74 | #endif | 74 | #endif |
75 | 75 | ||
76 | static int segv_error; | 76 | struct extbl_entry { |
77 | int insn; | ||
78 | int fixup; | ||
79 | }; | ||
77 | 80 | ||
78 | static void segv_handler(int signr, siginfo_t *info, void *ptr) | 81 | static void segv_handler(int signr, siginfo_t *info, void *ptr) |
79 | { | 82 | { |
80 | ucontext_t *uc = (ucontext_t *)ptr; | 83 | ucontext_t *uc = (ucontext_t *)ptr; |
81 | unsigned long addr = (unsigned long)info->si_addr; | 84 | unsigned long addr = (unsigned long)info->si_addr; |
82 | unsigned long *ip = &UCONTEXT_NIA(uc); | 85 | unsigned long *ip = &UCONTEXT_NIA(uc); |
83 | unsigned long *ex_p = (unsigned long *)__start___ex_table; | 86 | struct extbl_entry *entry = (struct extbl_entry *)__start___ex_table; |
84 | 87 | ||
85 | while (ex_p < (unsigned long *)__stop___ex_table) { | 88 | while (entry < (struct extbl_entry *)__stop___ex_table) { |
86 | unsigned long insn, fixup; | 89 | unsigned long insn, fixup; |
87 | 90 | ||
88 | insn = *ex_p++; | 91 | insn = (unsigned long)&entry->insn + entry->insn; |
89 | fixup = *ex_p++; | 92 | fixup = (unsigned long)&entry->fixup + entry->fixup; |
90 | 93 | ||
91 | if (insn == *ip) { | 94 | if (insn == *ip) { |
92 | *ip = fixup; | 95 | *ip = fixup; |
@@ -95,7 +98,7 @@ static void segv_handler(int signr, siginfo_t *info, void *ptr) | |||
95 | } | 98 | } |
96 | 99 | ||
97 | printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr); | 100 | printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr); |
98 | segv_error++; | 101 | abort(); |
99 | } | 102 | } |
100 | 103 | ||
101 | static void setup_segv_handler(void) | 104 | static void setup_segv_handler(void) |
@@ -119,8 +122,10 @@ static int do_one_test(char *p, int page_offset) | |||
119 | 122 | ||
120 | got = load_unaligned_zeropad(p); | 123 | got = load_unaligned_zeropad(p); |
121 | 124 | ||
122 | if (should != got) | 125 | if (should != got) { |
123 | printf("offset %u load_unaligned_zeropad returned 0x%lx, should be 0x%lx\n", page_offset, got, should); | 126 | printf("offset %u load_unaligned_zeropad returned 0x%lx, should be 0x%lx\n", page_offset, got, should); |
127 | return 1; | ||
128 | } | ||
124 | 129 | ||
125 | return 0; | 130 | return 0; |
126 | } | 131 | } |
@@ -145,8 +150,6 @@ static int test_body(void) | |||
145 | for (i = 0; i < page_size; i++) | 150 | for (i = 0; i < page_size; i++) |
146 | FAIL_IF(do_one_test(mem_region+i, i)); | 151 | FAIL_IF(do_one_test(mem_region+i, i)); |
147 | 152 | ||
148 | FAIL_IF(segv_error); | ||
149 | |||
150 | return 0; | 153 | return 0; |
151 | } | 154 | } |
152 | 155 | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/.gitignore b/tools/testing/selftests/powerpc/ptrace/.gitignore new file mode 100644 index 000000000000..349acfafc95b --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/.gitignore | |||
@@ -0,0 +1,10 @@ | |||
1 | ptrace-gpr | ||
2 | ptrace-tm-gpr | ||
3 | ptrace-tm-spd-gpr | ||
4 | ptrace-tar | ||
5 | ptrace-tm-tar | ||
6 | ptrace-tm-spd-tar | ||
7 | ptrace-vsx | ||
8 | ptrace-tm-vsx | ||
9 | ptrace-tm-spd-vsx | ||
10 | ptrace-tm-spr | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile new file mode 100644 index 000000000000..fe6bc60dfc60 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \ | ||
2 | ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \ | ||
3 | ptrace-tm-spd-vsx ptrace-tm-spr | ||
4 | |||
5 | include ../../lib.mk | ||
6 | |||
7 | all: $(TEST_PROGS) | ||
8 | |||
9 | CFLAGS += -m64 -I../../../../../usr/include -I../tm -mhtm | ||
10 | |||
11 | $(TEST_PROGS): ../harness.c ../utils.c ../lib/reg.S ptrace.h | ||
12 | |||
13 | clean: | ||
14 | rm -f $(TEST_PROGS) *.o | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-gpr.c b/tools/testing/selftests/powerpc/ptrace/ptrace-gpr.c new file mode 100644 index 000000000000..0b4ebcc2f485 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-gpr.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Ptrace test for GPR/FPR registers | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "ptrace-gpr.h" | ||
13 | #include "reg.h" | ||
14 | |||
15 | /* Tracer and Tracee Shared Data */ | ||
16 | int shm_id; | ||
17 | int *cptr, *pptr; | ||
18 | |||
19 | float a = FPR_1; | ||
20 | float b = FPR_2; | ||
21 | float c = FPR_3; | ||
22 | |||
23 | void gpr(void) | ||
24 | { | ||
25 | unsigned long gpr_buf[18]; | ||
26 | float fpr_buf[32]; | ||
27 | |||
28 | cptr = (int *)shmat(shm_id, NULL, 0); | ||
29 | |||
30 | asm __volatile__( | ||
31 | ASM_LOAD_GPR_IMMED(gpr_1) | ||
32 | ASM_LOAD_FPR_SINGLE_PRECISION(flt_1) | ||
33 | : | ||
34 | : [gpr_1]"i"(GPR_1), [flt_1] "r" (&a) | ||
35 | : "memory", "r6", "r7", "r8", "r9", "r10", | ||
36 | "r11", "r12", "r13", "r14", "r15", "r16", "r17", | ||
37 | "r18", "r19", "r20", "r21", "r22", "r23", "r24", | ||
38 | "r25", "r26", "r27", "r28", "r29", "r30", "r31" | ||
39 | ); | ||
40 | |||
41 | cptr[1] = 1; | ||
42 | |||
43 | while (!cptr[0]) | ||
44 | asm volatile("" : : : "memory"); | ||
45 | |||
46 | shmdt((void *)cptr); | ||
47 | store_gpr(gpr_buf); | ||
48 | store_fpr_single_precision(fpr_buf); | ||
49 | |||
50 | if (validate_gpr(gpr_buf, GPR_3)) | ||
51 | exit(1); | ||
52 | |||
53 | if (validate_fpr_float(fpr_buf, c)) | ||
54 | exit(1); | ||
55 | |||
56 | exit(0); | ||
57 | } | ||
58 | |||
59 | int trace_gpr(pid_t child) | ||
60 | { | ||
61 | unsigned long gpr[18]; | ||
62 | unsigned long fpr[32]; | ||
63 | |||
64 | FAIL_IF(start_trace(child)); | ||
65 | FAIL_IF(show_gpr(child, gpr)); | ||
66 | FAIL_IF(validate_gpr(gpr, GPR_1)); | ||
67 | FAIL_IF(show_fpr(child, fpr)); | ||
68 | FAIL_IF(validate_fpr(fpr, FPR_1_REP)); | ||
69 | FAIL_IF(write_gpr(child, GPR_3)); | ||
70 | FAIL_IF(write_fpr(child, FPR_3_REP)); | ||
71 | FAIL_IF(stop_trace(child)); | ||
72 | |||
73 | return TEST_PASS; | ||
74 | } | ||
75 | |||
76 | int ptrace_gpr(void) | ||
77 | { | ||
78 | pid_t pid; | ||
79 | int ret, status; | ||
80 | |||
81 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); | ||
82 | pid = fork(); | ||
83 | if (pid < 0) { | ||
84 | perror("fork() failed"); | ||
85 | return TEST_FAIL; | ||
86 | } | ||
87 | if (pid == 0) | ||
88 | gpr(); | ||
89 | |||
90 | if (pid) { | ||
91 | pptr = (int *)shmat(shm_id, NULL, 0); | ||
92 | while (!pptr[1]) | ||
93 | asm volatile("" : : : "memory"); | ||
94 | |||
95 | ret = trace_gpr(pid); | ||
96 | if (ret) { | ||
97 | kill(pid, SIGTERM); | ||
98 | shmdt((void *)pptr); | ||
99 | shmctl(shm_id, IPC_RMID, NULL); | ||
100 | return TEST_FAIL; | ||
101 | } | ||
102 | |||
103 | pptr[0] = 1; | ||
104 | shmdt((void *)pptr); | ||
105 | |||
106 | ret = wait(&status); | ||
107 | shmctl(shm_id, IPC_RMID, NULL); | ||
108 | if (ret != pid) { | ||
109 | printf("Child's exit status not captured\n"); | ||
110 | return TEST_FAIL; | ||
111 | } | ||
112 | |||
113 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
114 | TEST_PASS; | ||
115 | } | ||
116 | |||
117 | return TEST_PASS; | ||
118 | } | ||
119 | |||
120 | int main(int argc, char *argv[]) | ||
121 | { | ||
122 | return test_harness(ptrace_gpr, "ptrace_gpr"); | ||
123 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-gpr.h b/tools/testing/selftests/powerpc/ptrace/ptrace-gpr.h new file mode 100644 index 000000000000..e30fef63824c --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-gpr.h | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #define GPR_1 1 | ||
10 | #define GPR_2 2 | ||
11 | #define GPR_3 3 | ||
12 | #define GPR_4 4 | ||
13 | |||
14 | #define FPR_1 0.001 | ||
15 | #define FPR_2 0.002 | ||
16 | #define FPR_3 0.003 | ||
17 | #define FPR_4 0.004 | ||
18 | |||
19 | #define FPR_1_REP 0x3f50624de0000000 | ||
20 | #define FPR_2_REP 0x3f60624de0000000 | ||
21 | #define FPR_3_REP 0x3f689374c0000000 | ||
22 | #define FPR_4_REP 0x3f70624de0000000 | ||
23 | |||
24 | /* Buffer must have 18 elements */ | ||
25 | int validate_gpr(unsigned long *gpr, unsigned long val) | ||
26 | { | ||
27 | int i, found = 1; | ||
28 | |||
29 | for (i = 0; i < 18; i++) { | ||
30 | if (gpr[i] != val) { | ||
31 | printf("GPR[%d]: %lx Expected: %lx\n", | ||
32 | i+14, gpr[i], val); | ||
33 | found = 0; | ||
34 | } | ||
35 | } | ||
36 | |||
37 | if (!found) | ||
38 | return TEST_FAIL; | ||
39 | return TEST_PASS; | ||
40 | } | ||
41 | |||
42 | /* Buffer must have 32 elements */ | ||
43 | int validate_fpr(unsigned long *fpr, unsigned long val) | ||
44 | { | ||
45 | int i, found = 1; | ||
46 | |||
47 | for (i = 0; i < 32; i++) { | ||
48 | if (fpr[i] != val) { | ||
49 | printf("FPR[%d]: %lx Expected: %lx\n", i, fpr[i], val); | ||
50 | found = 0; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | if (!found) | ||
55 | return TEST_FAIL; | ||
56 | return TEST_PASS; | ||
57 | } | ||
58 | |||
59 | /* Buffer must have 32 elements */ | ||
60 | int validate_fpr_float(float *fpr, float val) | ||
61 | { | ||
62 | int i, found = 1; | ||
63 | |||
64 | for (i = 0; i < 32; i++) { | ||
65 | if (fpr[i] != val) { | ||
66 | printf("FPR[%d]: %f Expected: %f\n", i, fpr[i], val); | ||
67 | found = 0; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | if (!found) | ||
72 | return TEST_FAIL; | ||
73 | return TEST_PASS; | ||
74 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c new file mode 100644 index 000000000000..f9b5069db89b --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * Ptrace test for TAR, PPR, DSCR registers | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "ptrace-tar.h" | ||
13 | |||
14 | /* Tracer and Tracee Shared Data */ | ||
15 | int shm_id; | ||
16 | int *cptr; | ||
17 | int *pptr; | ||
18 | |||
19 | void tar(void) | ||
20 | { | ||
21 | unsigned long reg[3]; | ||
22 | int ret; | ||
23 | |||
24 | cptr = (int *)shmat(shm_id, NULL, 0); | ||
25 | printf("%-30s TAR: %u PPR: %lx DSCR: %u\n", | ||
26 | user_write, TAR_1, PPR_1, DSCR_1); | ||
27 | |||
28 | mtspr(SPRN_TAR, TAR_1); | ||
29 | mtspr(SPRN_PPR, PPR_1); | ||
30 | mtspr(SPRN_DSCR, DSCR_1); | ||
31 | |||
32 | cptr[2] = 1; | ||
33 | |||
34 | /* Wait on parent */ | ||
35 | while (!cptr[0]) | ||
36 | asm volatile("" : : : "memory"); | ||
37 | |||
38 | reg[0] = mfspr(SPRN_TAR); | ||
39 | reg[1] = mfspr(SPRN_PPR); | ||
40 | reg[2] = mfspr(SPRN_DSCR); | ||
41 | |||
42 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n", | ||
43 | user_read, reg[0], reg[1], reg[2]); | ||
44 | |||
45 | /* Unblock the parent now */ | ||
46 | cptr[1] = 1; | ||
47 | shmdt((int *)cptr); | ||
48 | |||
49 | ret = validate_tar_registers(reg, TAR_2, PPR_2, DSCR_2); | ||
50 | if (ret) | ||
51 | exit(1); | ||
52 | exit(0); | ||
53 | } | ||
54 | |||
55 | int trace_tar(pid_t child) | ||
56 | { | ||
57 | unsigned long reg[3]; | ||
58 | |||
59 | FAIL_IF(start_trace(child)); | ||
60 | FAIL_IF(show_tar_registers(child, reg)); | ||
61 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n", | ||
62 | ptrace_read_running, reg[0], reg[1], reg[2]); | ||
63 | |||
64 | FAIL_IF(validate_tar_registers(reg, TAR_1, PPR_1, DSCR_1)); | ||
65 | FAIL_IF(stop_trace(child)); | ||
66 | return TEST_PASS; | ||
67 | } | ||
68 | |||
69 | int trace_tar_write(pid_t child) | ||
70 | { | ||
71 | FAIL_IF(start_trace(child)); | ||
72 | FAIL_IF(write_tar_registers(child, TAR_2, PPR_2, DSCR_2)); | ||
73 | printf("%-30s TAR: %u PPR: %lx DSCR: %u\n", | ||
74 | ptrace_write_running, TAR_2, PPR_2, DSCR_2); | ||
75 | |||
76 | FAIL_IF(stop_trace(child)); | ||
77 | return TEST_PASS; | ||
78 | } | ||
79 | |||
80 | int ptrace_tar(void) | ||
81 | { | ||
82 | pid_t pid; | ||
83 | int ret, status; | ||
84 | |||
85 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); | ||
86 | pid = fork(); | ||
87 | if (pid < 0) { | ||
88 | perror("fork() failed"); | ||
89 | return TEST_FAIL; | ||
90 | } | ||
91 | |||
92 | if (pid == 0) | ||
93 | tar(); | ||
94 | |||
95 | if (pid) { | ||
96 | pptr = (int *)shmat(shm_id, NULL, 0); | ||
97 | pptr[0] = 0; | ||
98 | pptr[1] = 0; | ||
99 | |||
100 | while (!pptr[2]) | ||
101 | asm volatile("" : : : "memory"); | ||
102 | ret = trace_tar(pid); | ||
103 | if (ret) | ||
104 | return ret; | ||
105 | |||
106 | ret = trace_tar_write(pid); | ||
107 | if (ret) | ||
108 | return ret; | ||
109 | |||
110 | /* Unblock the child now */ | ||
111 | pptr[0] = 1; | ||
112 | |||
113 | /* Wait on child */ | ||
114 | while (!pptr[1]) | ||
115 | asm volatile("" : : : "memory"); | ||
116 | |||
117 | shmdt((int *)pptr); | ||
118 | |||
119 | ret = wait(&status); | ||
120 | shmctl(shm_id, IPC_RMID, NULL); | ||
121 | if (ret != pid) { | ||
122 | printf("Child's exit status not captured\n"); | ||
123 | return TEST_PASS; | ||
124 | } | ||
125 | |||
126 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
127 | TEST_PASS; | ||
128 | } | ||
129 | return TEST_PASS; | ||
130 | } | ||
131 | |||
132 | int main(int argc, char *argv[]) | ||
133 | { | ||
134 | return test_harness(ptrace_tar, "ptrace_tar"); | ||
135 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tar.h b/tools/testing/selftests/powerpc/ptrace/ptrace-tar.h new file mode 100644 index 000000000000..aed0aac716d2 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tar.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #define TAR_1 10 | ||
10 | #define TAR_2 20 | ||
11 | #define TAR_3 30 | ||
12 | #define TAR_4 40 | ||
13 | #define TAR_5 50 | ||
14 | |||
15 | #define DSCR_1 100 | ||
16 | #define DSCR_2 200 | ||
17 | #define DSCR_3 300 | ||
18 | #define DSCR_4 400 | ||
19 | #define DSCR_5 500 | ||
20 | |||
21 | #define PPR_1 0x4000000000000 /* or 31,31,31*/ | ||
22 | #define PPR_2 0x8000000000000 /* or 1,1,1 */ | ||
23 | #define PPR_3 0xc000000000000 /* or 6,6,6 */ | ||
24 | #define PPR_4 0x10000000000000 /* or 2,2,2 */ | ||
25 | |||
26 | char *user_read = "[User Read (Running)]"; | ||
27 | char *user_write = "[User Write (Running)]"; | ||
28 | char *ptrace_read_running = "[Ptrace Read (Running)]"; | ||
29 | char *ptrace_write_running = "[Ptrace Write (Running)]"; | ||
30 | char *ptrace_read_ckpt = "[Ptrace Read (Checkpointed)]"; | ||
31 | char *ptrace_write_ckpt = "[Ptrace Write (Checkpointed)]"; | ||
32 | |||
33 | int validate_tar_registers(unsigned long *reg, unsigned long tar, | ||
34 | unsigned long ppr, unsigned long dscr) | ||
35 | { | ||
36 | int match = 1; | ||
37 | |||
38 | if (reg[0] != tar) | ||
39 | match = 0; | ||
40 | |||
41 | if (reg[1] != ppr) | ||
42 | match = 0; | ||
43 | |||
44 | if (reg[2] != dscr) | ||
45 | match = 0; | ||
46 | |||
47 | if (!match) | ||
48 | return TEST_FAIL; | ||
49 | return TEST_PASS; | ||
50 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-gpr.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-gpr.c new file mode 100644 index 000000000000..59206b96e98a --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-gpr.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Ptrace test for GPR/FPR registers in TM context | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "ptrace-gpr.h" | ||
13 | #include "tm.h" | ||
14 | |||
15 | /* Tracer and Tracee Shared Data */ | ||
16 | int shm_id; | ||
17 | unsigned long *cptr, *pptr; | ||
18 | |||
19 | float a = FPR_1; | ||
20 | float b = FPR_2; | ||
21 | float c = FPR_3; | ||
22 | |||
23 | void tm_gpr(void) | ||
24 | { | ||
25 | unsigned long gpr_buf[18]; | ||
26 | unsigned long result, texasr; | ||
27 | float fpr_buf[32]; | ||
28 | |||
29 | printf("Starting the child\n"); | ||
30 | cptr = (unsigned long *)shmat(shm_id, NULL, 0); | ||
31 | |||
32 | trans: | ||
33 | cptr[1] = 0; | ||
34 | asm __volatile__( | ||
35 | ASM_LOAD_GPR_IMMED(gpr_1) | ||
36 | ASM_LOAD_FPR_SINGLE_PRECISION(flt_1) | ||
37 | "1: ;" | ||
38 | "tbegin.;" | ||
39 | "beq 2f;" | ||
40 | ASM_LOAD_GPR_IMMED(gpr_2) | ||
41 | ASM_LOAD_FPR_SINGLE_PRECISION(flt_2) | ||
42 | "tsuspend.;" | ||
43 | "li 7, 1;" | ||
44 | "stw 7, 0(%[cptr1]);" | ||
45 | "tresume.;" | ||
46 | "b .;" | ||
47 | |||
48 | "tend.;" | ||
49 | "li 0, 0;" | ||
50 | "ori %[res], 0, 0;" | ||
51 | "b 3f;" | ||
52 | |||
53 | /* Transaction abort handler */ | ||
54 | "2: ;" | ||
55 | "li 0, 1;" | ||
56 | "ori %[res], 0, 0;" | ||
57 | "mfspr %[texasr], %[sprn_texasr];" | ||
58 | |||
59 | "3: ;" | ||
60 | : [res] "=r" (result), [texasr] "=r" (texasr) | ||
61 | : [gpr_1]"i"(GPR_1), [gpr_2]"i"(GPR_2), | ||
62 | [sprn_texasr] "i" (SPRN_TEXASR), [flt_1] "r" (&a), | ||
63 | [flt_2] "r" (&b), [cptr1] "r" (&cptr[1]) | ||
64 | : "memory", "r7", "r8", "r9", "r10", | ||
65 | "r11", "r12", "r13", "r14", "r15", "r16", | ||
66 | "r17", "r18", "r19", "r20", "r21", "r22", | ||
67 | "r23", "r24", "r25", "r26", "r27", "r28", | ||
68 | "r29", "r30", "r31" | ||
69 | ); | ||
70 | |||
71 | if (result) { | ||
72 | if (!cptr[0]) | ||
73 | goto trans; | ||
74 | |||
75 | shmdt((void *)cptr); | ||
76 | store_gpr(gpr_buf); | ||
77 | store_fpr_single_precision(fpr_buf); | ||
78 | |||
79 | if (validate_gpr(gpr_buf, GPR_3)) | ||
80 | exit(1); | ||
81 | |||
82 | if (validate_fpr_float(fpr_buf, c)) | ||
83 | exit(1); | ||
84 | |||
85 | exit(0); | ||
86 | } | ||
87 | shmdt((void *)cptr); | ||
88 | exit(1); | ||
89 | } | ||
90 | |||
91 | int trace_tm_gpr(pid_t child) | ||
92 | { | ||
93 | unsigned long gpr[18]; | ||
94 | unsigned long fpr[32]; | ||
95 | |||
96 | FAIL_IF(start_trace(child)); | ||
97 | FAIL_IF(show_gpr(child, gpr)); | ||
98 | FAIL_IF(validate_gpr(gpr, GPR_2)); | ||
99 | FAIL_IF(show_fpr(child, fpr)); | ||
100 | FAIL_IF(validate_fpr(fpr, FPR_2_REP)); | ||
101 | FAIL_IF(show_ckpt_fpr(child, fpr)); | ||
102 | FAIL_IF(validate_fpr(fpr, FPR_1_REP)); | ||
103 | FAIL_IF(show_ckpt_gpr(child, gpr)); | ||
104 | FAIL_IF(validate_gpr(gpr, GPR_1)); | ||
105 | FAIL_IF(write_ckpt_gpr(child, GPR_3)); | ||
106 | FAIL_IF(write_ckpt_fpr(child, FPR_3_REP)); | ||
107 | |||
108 | pptr[0] = 1; | ||
109 | FAIL_IF(stop_trace(child)); | ||
110 | |||
111 | return TEST_PASS; | ||
112 | } | ||
113 | |||
114 | int ptrace_tm_gpr(void) | ||
115 | { | ||
116 | pid_t pid; | ||
117 | int ret, status; | ||
118 | |||
119 | SKIP_IF(!have_htm()); | ||
120 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); | ||
121 | pid = fork(); | ||
122 | if (pid < 0) { | ||
123 | perror("fork() failed"); | ||
124 | return TEST_FAIL; | ||
125 | } | ||
126 | if (pid == 0) | ||
127 | tm_gpr(); | ||
128 | |||
129 | if (pid) { | ||
130 | pptr = (unsigned long *)shmat(shm_id, NULL, 0); | ||
131 | |||
132 | while (!pptr[1]) | ||
133 | asm volatile("" : : : "memory"); | ||
134 | ret = trace_tm_gpr(pid); | ||
135 | if (ret) { | ||
136 | kill(pid, SIGTERM); | ||
137 | return TEST_FAIL; | ||
138 | } | ||
139 | |||
140 | shmdt((void *)pptr); | ||
141 | |||
142 | ret = wait(&status); | ||
143 | shmctl(shm_id, IPC_RMID, NULL); | ||
144 | if (ret != pid) { | ||
145 | printf("Child's exit status not captured\n"); | ||
146 | return TEST_FAIL; | ||
147 | } | ||
148 | |||
149 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
150 | TEST_PASS; | ||
151 | } | ||
152 | return TEST_PASS; | ||
153 | } | ||
154 | |||
155 | int main(int argc, char *argv[]) | ||
156 | { | ||
157 | return test_harness(ptrace_tm_gpr, "ptrace_tm_gpr"); | ||
158 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-gpr.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-gpr.c new file mode 100644 index 000000000000..327fa943c7f3 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-gpr.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * Ptrace test for GPR/FPR registers in TM Suspend context | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "ptrace-gpr.h" | ||
13 | #include "tm.h" | ||
14 | |||
15 | /* Tracer and Tracee Shared Data */ | ||
16 | int shm_id; | ||
17 | int *cptr, *pptr; | ||
18 | |||
19 | float a = FPR_1; | ||
20 | float b = FPR_2; | ||
21 | float c = FPR_3; | ||
22 | float d = FPR_4; | ||
23 | |||
24 | __attribute__((used)) void wait_parent(void) | ||
25 | { | ||
26 | cptr[2] = 1; | ||
27 | while (!cptr[1]) | ||
28 | asm volatile("" : : : "memory"); | ||
29 | } | ||
30 | |||
31 | void tm_spd_gpr(void) | ||
32 | { | ||
33 | unsigned long gpr_buf[18]; | ||
34 | unsigned long result, texasr; | ||
35 | float fpr_buf[32]; | ||
36 | |||
37 | cptr = (int *)shmat(shm_id, NULL, 0); | ||
38 | |||
39 | trans: | ||
40 | cptr[2] = 0; | ||
41 | asm __volatile__( | ||
42 | ASM_LOAD_GPR_IMMED(gpr_1) | ||
43 | ASM_LOAD_FPR_SINGLE_PRECISION(flt_1) | ||
44 | |||
45 | "1: ;" | ||
46 | "tbegin.;" | ||
47 | "beq 2f;" | ||
48 | |||
49 | ASM_LOAD_GPR_IMMED(gpr_2) | ||
50 | "tsuspend.;" | ||
51 | ASM_LOAD_GPR_IMMED(gpr_4) | ||
52 | ASM_LOAD_FPR_SINGLE_PRECISION(flt_4) | ||
53 | |||
54 | "bl wait_parent;" | ||
55 | "tresume.;" | ||
56 | "tend.;" | ||
57 | "li 0, 0;" | ||
58 | "ori %[res], 0, 0;" | ||
59 | "b 3f;" | ||
60 | |||
61 | /* Transaction abort handler */ | ||
62 | "2: ;" | ||
63 | "li 0, 1;" | ||
64 | "ori %[res], 0, 0;" | ||
65 | "mfspr %[texasr], %[sprn_texasr];" | ||
66 | |||
67 | "3: ;" | ||
68 | : [res] "=r" (result), [texasr] "=r" (texasr) | ||
69 | : [gpr_1]"i"(GPR_1), [gpr_2]"i"(GPR_2), [gpr_4]"i"(GPR_4), | ||
70 | [sprn_texasr] "i" (SPRN_TEXASR), [flt_1] "r" (&a), | ||
71 | [flt_2] "r" (&b), [flt_4] "r" (&d) | ||
72 | : "memory", "r5", "r6", "r7", | ||
73 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | ||
74 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | ||
75 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" | ||
76 | ); | ||
77 | |||
78 | if (result) { | ||
79 | if (!cptr[0]) | ||
80 | goto trans; | ||
81 | |||
82 | shmdt((void *)cptr); | ||
83 | store_gpr(gpr_buf); | ||
84 | store_fpr_single_precision(fpr_buf); | ||
85 | |||
86 | if (validate_gpr(gpr_buf, GPR_3)) | ||
87 | exit(1); | ||
88 | |||
89 | if (validate_fpr_float(fpr_buf, c)) | ||
90 | exit(1); | ||
91 | exit(0); | ||
92 | } | ||
93 | shmdt((void *)cptr); | ||
94 | exit(1); | ||
95 | } | ||
96 | |||
97 | int trace_tm_spd_gpr(pid_t child) | ||
98 | { | ||
99 | unsigned long gpr[18]; | ||
100 | unsigned long fpr[32]; | ||
101 | |||
102 | FAIL_IF(start_trace(child)); | ||
103 | FAIL_IF(show_gpr(child, gpr)); | ||
104 | FAIL_IF(validate_gpr(gpr, GPR_4)); | ||
105 | FAIL_IF(show_fpr(child, fpr)); | ||
106 | FAIL_IF(validate_fpr(fpr, FPR_4_REP)); | ||
107 | FAIL_IF(show_ckpt_fpr(child, fpr)); | ||
108 | FAIL_IF(validate_fpr(fpr, FPR_1_REP)); | ||
109 | FAIL_IF(show_ckpt_gpr(child, gpr)); | ||
110 | FAIL_IF(validate_gpr(gpr, GPR_1)); | ||
111 | FAIL_IF(write_ckpt_gpr(child, GPR_3)); | ||
112 | FAIL_IF(write_ckpt_fpr(child, FPR_3_REP)); | ||
113 | |||
114 | pptr[0] = 1; | ||
115 | pptr[1] = 1; | ||
116 | FAIL_IF(stop_trace(child)); | ||
117 | return TEST_PASS; | ||
118 | } | ||
119 | |||
120 | int ptrace_tm_spd_gpr(void) | ||
121 | { | ||
122 | pid_t pid; | ||
123 | int ret, status; | ||
124 | |||
125 | SKIP_IF(!have_htm()); | ||
126 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); | ||
127 | pid = fork(); | ||
128 | if (pid < 0) { | ||
129 | perror("fork() failed"); | ||
130 | return TEST_FAIL; | ||
131 | } | ||
132 | |||
133 | if (pid == 0) | ||
134 | tm_spd_gpr(); | ||
135 | |||
136 | if (pid) { | ||
137 | pptr = (int *)shmat(shm_id, NULL, 0); | ||
138 | pptr[0] = 0; | ||
139 | pptr[1] = 0; | ||
140 | |||
141 | while (!pptr[2]) | ||
142 | asm volatile("" : : : "memory"); | ||
143 | ret = trace_tm_spd_gpr(pid); | ||
144 | if (ret) { | ||
145 | kill(pid, SIGTERM); | ||
146 | shmdt((void *)pptr); | ||
147 | shmctl(shm_id, IPC_RMID, NULL); | ||
148 | return TEST_FAIL; | ||
149 | } | ||
150 | |||
151 | shmdt((void *)pptr); | ||
152 | |||
153 | ret = wait(&status); | ||
154 | shmctl(shm_id, IPC_RMID, NULL); | ||
155 | if (ret != pid) { | ||
156 | printf("Child's exit status not captured\n"); | ||
157 | return TEST_FAIL; | ||
158 | } | ||
159 | |||
160 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
161 | TEST_PASS; | ||
162 | } | ||
163 | return TEST_PASS; | ||
164 | } | ||
165 | |||
166 | int main(int argc, char *argv[]) | ||
167 | { | ||
168 | return test_harness(ptrace_tm_spd_gpr, "ptrace_tm_spd_gpr"); | ||
169 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-tar.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-tar.c new file mode 100644 index 000000000000..b3c061dc9512 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-tar.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /* | ||
2 | * Ptrace test for TAR, PPR, DSCR registers in the TM Suspend context | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "tm.h" | ||
13 | #include "ptrace-tar.h" | ||
14 | |||
15 | int shm_id; | ||
16 | int *cptr, *pptr; | ||
17 | |||
18 | __attribute__((used)) void wait_parent(void) | ||
19 | { | ||
20 | cptr[2] = 1; | ||
21 | while (!cptr[1]) | ||
22 | asm volatile("" : : : "memory"); | ||
23 | } | ||
24 | |||
25 | void tm_spd_tar(void) | ||
26 | { | ||
27 | unsigned long result, texasr; | ||
28 | unsigned long regs[3]; | ||
29 | int ret; | ||
30 | |||
31 | cptr = (int *)shmat(shm_id, NULL, 0); | ||
32 | |||
33 | trans: | ||
34 | cptr[2] = 0; | ||
35 | asm __volatile__( | ||
36 | "li 4, %[tar_1];" | ||
37 | "mtspr %[sprn_tar], 4;" /* TAR_1 */ | ||
38 | "li 4, %[dscr_1];" | ||
39 | "mtspr %[sprn_dscr], 4;" /* DSCR_1 */ | ||
40 | "or 31,31,31;" /* PPR_1*/ | ||
41 | |||
42 | "1: ;" | ||
43 | "tbegin.;" | ||
44 | "beq 2f;" | ||
45 | |||
46 | "li 4, %[tar_2];" | ||
47 | "mtspr %[sprn_tar], 4;" /* TAR_2 */ | ||
48 | "li 4, %[dscr_2];" | ||
49 | "mtspr %[sprn_dscr], 4;" /* DSCR_2 */ | ||
50 | "or 1,1,1;" /* PPR_2 */ | ||
51 | |||
52 | "tsuspend.;" | ||
53 | "li 4, %[tar_3];" | ||
54 | "mtspr %[sprn_tar], 4;" /* TAR_3 */ | ||
55 | "li 4, %[dscr_3];" | ||
56 | "mtspr %[sprn_dscr], 4;" /* DSCR_3 */ | ||
57 | "or 6,6,6;" /* PPR_3 */ | ||
58 | "bl wait_parent;" | ||
59 | "tresume.;" | ||
60 | |||
61 | "tend.;" | ||
62 | "li 0, 0;" | ||
63 | "ori %[res], 0, 0;" | ||
64 | "b 3f;" | ||
65 | |||
66 | /* Transaction abort handler */ | ||
67 | "2: ;" | ||
68 | "li 0, 1;" | ||
69 | "ori %[res], 0, 0;" | ||
70 | "mfspr %[texasr], %[sprn_texasr];" | ||
71 | |||
72 | "3: ;" | ||
73 | |||
74 | : [res] "=r" (result), [texasr] "=r" (texasr) | ||
75 | : [val] "r" (cptr[1]), [sprn_dscr]"i"(SPRN_DSCR), | ||
76 | [sprn_tar]"i"(SPRN_TAR), [sprn_ppr]"i"(SPRN_PPR), | ||
77 | [sprn_texasr]"i"(SPRN_TEXASR), [tar_1]"i"(TAR_1), | ||
78 | [dscr_1]"i"(DSCR_1), [tar_2]"i"(TAR_2), [dscr_2]"i"(DSCR_2), | ||
79 | [tar_3]"i"(TAR_3), [dscr_3]"i"(DSCR_3) | ||
80 | : "memory", "r0", "r1", "r3", "r4", "r5", "r6" | ||
81 | ); | ||
82 | |||
83 | /* TM failed, analyse */ | ||
84 | if (result) { | ||
85 | if (!cptr[0]) | ||
86 | goto trans; | ||
87 | |||
88 | regs[0] = mfspr(SPRN_TAR); | ||
89 | regs[1] = mfspr(SPRN_PPR); | ||
90 | regs[2] = mfspr(SPRN_DSCR); | ||
91 | |||
92 | shmdt(&cptr); | ||
93 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n", | ||
94 | user_read, regs[0], regs[1], regs[2]); | ||
95 | |||
96 | ret = validate_tar_registers(regs, TAR_4, PPR_4, DSCR_4); | ||
97 | if (ret) | ||
98 | exit(1); | ||
99 | exit(0); | ||
100 | } | ||
101 | shmdt(&cptr); | ||
102 | exit(1); | ||
103 | } | ||
104 | |||
105 | int trace_tm_spd_tar(pid_t child) | ||
106 | { | ||
107 | unsigned long regs[3]; | ||
108 | |||
109 | FAIL_IF(start_trace(child)); | ||
110 | FAIL_IF(show_tar_registers(child, regs)); | ||
111 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n", | ||
112 | ptrace_read_running, regs[0], regs[1], regs[2]); | ||
113 | |||
114 | FAIL_IF(validate_tar_registers(regs, TAR_3, PPR_3, DSCR_3)); | ||
115 | FAIL_IF(show_tm_checkpointed_state(child, regs)); | ||
116 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n", | ||
117 | ptrace_read_ckpt, regs[0], regs[1], regs[2]); | ||
118 | |||
119 | FAIL_IF(validate_tar_registers(regs, TAR_1, PPR_1, DSCR_1)); | ||
120 | FAIL_IF(write_ckpt_tar_registers(child, TAR_4, PPR_4, DSCR_4)); | ||
121 | printf("%-30s TAR: %u PPR: %lx DSCR: %u\n", | ||
122 | ptrace_write_ckpt, TAR_4, PPR_4, DSCR_4); | ||
123 | |||
124 | pptr[0] = 1; | ||
125 | pptr[1] = 1; | ||
126 | FAIL_IF(stop_trace(child)); | ||
127 | return TEST_PASS; | ||
128 | } | ||
129 | |||
130 | int ptrace_tm_spd_tar(void) | ||
131 | { | ||
132 | pid_t pid; | ||
133 | int ret, status; | ||
134 | |||
135 | SKIP_IF(!have_htm()); | ||
136 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); | ||
137 | pid = fork(); | ||
138 | if (pid == 0) | ||
139 | tm_spd_tar(); | ||
140 | |||
141 | pptr = (int *)shmat(shm_id, NULL, 0); | ||
142 | pptr[0] = 0; | ||
143 | pptr[1] = 0; | ||
144 | |||
145 | if (pid) { | ||
146 | while (!pptr[2]) | ||
147 | asm volatile("" : : : "memory"); | ||
148 | ret = trace_tm_spd_tar(pid); | ||
149 | if (ret) { | ||
150 | kill(pid, SIGTERM); | ||
151 | shmdt(&pptr); | ||
152 | shmctl(shm_id, IPC_RMID, NULL); | ||
153 | return TEST_FAIL; | ||
154 | } | ||
155 | |||
156 | shmdt(&pptr); | ||
157 | |||
158 | ret = wait(&status); | ||
159 | shmctl(shm_id, IPC_RMID, NULL); | ||
160 | if (ret != pid) { | ||
161 | printf("Child's exit status not captured\n"); | ||
162 | return TEST_FAIL; | ||
163 | } | ||
164 | |||
165 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
166 | TEST_PASS; | ||
167 | } | ||
168 | return TEST_PASS; | ||
169 | } | ||
170 | |||
171 | int main(int argc, char *argv[]) | ||
172 | { | ||
173 | return test_harness(ptrace_tm_spd_tar, "ptrace_tm_spd_tar"); | ||
174 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-vsx.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-vsx.c new file mode 100644 index 000000000000..0df3c23b7888 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-vsx.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * Ptrace test for VMX/VSX registers in the TM Suspend context | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "tm.h" | ||
13 | #include "ptrace-vsx.h" | ||
14 | |||
15 | int shm_id; | ||
16 | int *cptr, *pptr; | ||
17 | |||
18 | unsigned long fp_load[VEC_MAX]; | ||
19 | unsigned long fp_load_new[VEC_MAX]; | ||
20 | unsigned long fp_store[VEC_MAX]; | ||
21 | unsigned long fp_load_ckpt[VEC_MAX]; | ||
22 | unsigned long fp_load_ckpt_new[VEC_MAX]; | ||
23 | |||
24 | __attribute__((used)) void load_vsx(void) | ||
25 | { | ||
26 | loadvsx(fp_load, 0); | ||
27 | } | ||
28 | |||
29 | __attribute__((used)) void load_vsx_new(void) | ||
30 | { | ||
31 | loadvsx(fp_load_new, 0); | ||
32 | } | ||
33 | |||
34 | __attribute__((used)) void load_vsx_ckpt(void) | ||
35 | { | ||
36 | loadvsx(fp_load_ckpt, 0); | ||
37 | } | ||
38 | |||
39 | __attribute__((used)) void wait_parent(void) | ||
40 | { | ||
41 | cptr[2] = 1; | ||
42 | while (!cptr[1]) | ||
43 | asm volatile("" : : : "memory"); | ||
44 | } | ||
45 | |||
46 | void tm_spd_vsx(void) | ||
47 | { | ||
48 | unsigned long result, texasr; | ||
49 | int ret; | ||
50 | |||
51 | cptr = (int *)shmat(shm_id, NULL, 0); | ||
52 | |||
53 | trans: | ||
54 | cptr[2] = 0; | ||
55 | asm __volatile__( | ||
56 | "bl load_vsx_ckpt;" | ||
57 | |||
58 | "1: ;" | ||
59 | "tbegin.;" | ||
60 | "beq 2f;" | ||
61 | |||
62 | "bl load_vsx_new;" | ||
63 | "tsuspend.;" | ||
64 | "bl load_vsx;" | ||
65 | "bl wait_parent;" | ||
66 | "tresume.;" | ||
67 | |||
68 | "tend.;" | ||
69 | "li 0, 0;" | ||
70 | "ori %[res], 0, 0;" | ||
71 | "b 3f;" | ||
72 | |||
73 | "2: ;" | ||
74 | "li 0, 1;" | ||
75 | "ori %[res], 0, 0;" | ||
76 | "mfspr %[texasr], %[sprn_texasr];" | ||
77 | |||
78 | "3: ;" | ||
79 | : [res] "=r" (result), [texasr] "=r" (texasr) | ||
80 | : [fp_load] "r" (fp_load), [fp_load_ckpt] "r" (fp_load_ckpt), | ||
81 | [sprn_texasr] "i" (SPRN_TEXASR) | ||
82 | : "memory", "r0", "r1", "r2", "r3", "r4", | ||
83 | "r8", "r9", "r10", "r11" | ||
84 | ); | ||
85 | |||
86 | if (result) { | ||
87 | if (!cptr[0]) | ||
88 | goto trans; | ||
89 | shmdt((void *)cptr); | ||
90 | |||
91 | storevsx(fp_store, 0); | ||
92 | ret = compare_vsx_vmx(fp_store, fp_load_ckpt_new); | ||
93 | if (ret) | ||
94 | exit(1); | ||
95 | exit(0); | ||
96 | } | ||
97 | shmdt((void *)cptr); | ||
98 | exit(1); | ||
99 | } | ||
100 | |||
101 | int trace_tm_spd_vsx(pid_t child) | ||
102 | { | ||
103 | unsigned long vsx[VSX_MAX]; | ||
104 | unsigned long vmx[VMX_MAX + 2][2]; | ||
105 | |||
106 | FAIL_IF(start_trace(child)); | ||
107 | FAIL_IF(show_vsx(child, vsx)); | ||
108 | FAIL_IF(validate_vsx(vsx, fp_load)); | ||
109 | FAIL_IF(show_vmx(child, vmx)); | ||
110 | FAIL_IF(validate_vmx(vmx, fp_load)); | ||
111 | FAIL_IF(show_vsx_ckpt(child, vsx)); | ||
112 | FAIL_IF(validate_vsx(vsx, fp_load_ckpt)); | ||
113 | FAIL_IF(show_vmx_ckpt(child, vmx)); | ||
114 | FAIL_IF(validate_vmx(vmx, fp_load_ckpt)); | ||
115 | |||
116 | memset(vsx, 0, sizeof(vsx)); | ||
117 | memset(vmx, 0, sizeof(vmx)); | ||
118 | |||
119 | load_vsx_vmx(fp_load_ckpt_new, vsx, vmx); | ||
120 | |||
121 | FAIL_IF(write_vsx_ckpt(child, vsx)); | ||
122 | FAIL_IF(write_vmx_ckpt(child, vmx)); | ||
123 | |||
124 | pptr[0] = 1; | ||
125 | pptr[1] = 1; | ||
126 | FAIL_IF(stop_trace(child)); | ||
127 | |||
128 | return TEST_PASS; | ||
129 | } | ||
130 | |||
131 | int ptrace_tm_spd_vsx(void) | ||
132 | { | ||
133 | pid_t pid; | ||
134 | int ret, status, i; | ||
135 | |||
136 | SKIP_IF(!have_htm()); | ||
137 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); | ||
138 | |||
139 | for (i = 0; i < 128; i++) { | ||
140 | fp_load[i] = 1 + rand(); | ||
141 | fp_load_new[i] = 1 + 2 * rand(); | ||
142 | fp_load_ckpt[i] = 1 + 3 * rand(); | ||
143 | fp_load_ckpt_new[i] = 1 + 4 * rand(); | ||
144 | } | ||
145 | |||
146 | pid = fork(); | ||
147 | if (pid < 0) { | ||
148 | perror("fork() failed"); | ||
149 | return TEST_FAIL; | ||
150 | } | ||
151 | |||
152 | if (pid == 0) | ||
153 | tm_spd_vsx(); | ||
154 | |||
155 | if (pid) { | ||
156 | pptr = (int *)shmat(shm_id, NULL, 0); | ||
157 | while (!pptr[2]) | ||
158 | asm volatile("" : : : "memory"); | ||
159 | |||
160 | ret = trace_tm_spd_vsx(pid); | ||
161 | if (ret) { | ||
162 | kill(pid, SIGKILL); | ||
163 | shmdt((void *)pptr); | ||
164 | shmctl(shm_id, IPC_RMID, NULL); | ||
165 | return TEST_FAIL; | ||
166 | } | ||
167 | |||
168 | shmdt((void *)pptr); | ||
169 | ret = wait(&status); | ||
170 | shmctl(shm_id, IPC_RMID, NULL); | ||
171 | if (ret != pid) { | ||
172 | printf("Child's exit status not captured\n"); | ||
173 | return TEST_FAIL; | ||
174 | } | ||
175 | |||
176 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
177 | TEST_PASS; | ||
178 | } | ||
179 | return TEST_PASS; | ||
180 | } | ||
181 | |||
182 | int main(int argc, char *argv[]) | ||
183 | { | ||
184 | return test_harness(ptrace_tm_spd_vsx, "ptrace_tm_spd_vsx"); | ||
185 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spr.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spr.c new file mode 100644 index 000000000000..94e57cb89769 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spr.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * Ptrace test TM SPR registers | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "tm.h" | ||
13 | |||
14 | /* Tracee and tracer shared data */ | ||
15 | struct shared { | ||
16 | int flag; | ||
17 | struct tm_spr_regs regs; | ||
18 | }; | ||
19 | unsigned long tfhar; | ||
20 | |||
21 | int shm_id; | ||
22 | struct shared *cptr, *pptr; | ||
23 | |||
24 | int shm_id1; | ||
25 | int *cptr1, *pptr1; | ||
26 | |||
27 | #define TM_KVM_SCHED 0xe0000001ac000001 | ||
28 | int validate_tm_spr(struct tm_spr_regs *regs) | ||
29 | { | ||
30 | FAIL_IF(regs->tm_tfhar != tfhar); | ||
31 | FAIL_IF((regs->tm_texasr == TM_KVM_SCHED) && (regs->tm_tfiar != 0)); | ||
32 | |||
33 | return TEST_PASS; | ||
34 | } | ||
35 | |||
36 | void tm_spr(void) | ||
37 | { | ||
38 | unsigned long result, texasr; | ||
39 | int ret; | ||
40 | |||
41 | cptr = (struct shared *)shmat(shm_id, NULL, 0); | ||
42 | cptr1 = (int *)shmat(shm_id1, NULL, 0); | ||
43 | |||
44 | trans: | ||
45 | cptr1[0] = 0; | ||
46 | asm __volatile__( | ||
47 | "1: ;" | ||
48 | /* TM failover handler should follow "tbegin.;" */ | ||
49 | "mflr 31;" | ||
50 | "bl 4f;" /* $ = TFHAR - 12 */ | ||
51 | "4: ;" | ||
52 | "mflr %[tfhar];" | ||
53 | "mtlr 31;" | ||
54 | |||
55 | "tbegin.;" | ||
56 | "beq 2f;" | ||
57 | |||
58 | "tsuspend.;" | ||
59 | "li 8, 1;" | ||
60 | "sth 8, 0(%[cptr1]);" | ||
61 | "tresume.;" | ||
62 | "b .;" | ||
63 | |||
64 | "tend.;" | ||
65 | "li 0, 0;" | ||
66 | "ori %[res], 0, 0;" | ||
67 | "b 3f;" | ||
68 | |||
69 | "2: ;" | ||
70 | |||
71 | "li 0, 1;" | ||
72 | "ori %[res], 0, 0;" | ||
73 | "mfspr %[texasr], %[sprn_texasr];" | ||
74 | |||
75 | "3: ;" | ||
76 | : [tfhar] "=r" (tfhar), [res] "=r" (result), | ||
77 | [texasr] "=r" (texasr), [cptr1] "=r" (cptr1) | ||
78 | : [sprn_texasr] "i" (SPRN_TEXASR) | ||
79 | : "memory", "r0", "r1", "r2", "r3", "r4", | ||
80 | "r8", "r9", "r10", "r11", "r31" | ||
81 | ); | ||
82 | |||
83 | /* There are 2 32bit instructions before tbegin. */ | ||
84 | tfhar += 12; | ||
85 | |||
86 | if (result) { | ||
87 | if (!cptr->flag) | ||
88 | goto trans; | ||
89 | |||
90 | ret = validate_tm_spr((struct tm_spr_regs *)&cptr->regs); | ||
91 | shmdt((void *)cptr); | ||
92 | shmdt((void *)cptr1); | ||
93 | if (ret) | ||
94 | exit(1); | ||
95 | exit(0); | ||
96 | } | ||
97 | shmdt((void *)cptr); | ||
98 | shmdt((void *)cptr1); | ||
99 | exit(1); | ||
100 | } | ||
101 | |||
102 | int trace_tm_spr(pid_t child) | ||
103 | { | ||
104 | FAIL_IF(start_trace(child)); | ||
105 | FAIL_IF(show_tm_spr(child, (struct tm_spr_regs *)&pptr->regs)); | ||
106 | |||
107 | printf("TFHAR: %lx TEXASR: %lx TFIAR: %lx\n", pptr->regs.tm_tfhar, | ||
108 | pptr->regs.tm_texasr, pptr->regs.tm_tfiar); | ||
109 | |||
110 | pptr->flag = 1; | ||
111 | FAIL_IF(stop_trace(child)); | ||
112 | |||
113 | return TEST_PASS; | ||
114 | } | ||
115 | |||
116 | int ptrace_tm_spr(void) | ||
117 | { | ||
118 | pid_t pid; | ||
119 | int ret, status; | ||
120 | |||
121 | SKIP_IF(!have_htm()); | ||
122 | shm_id = shmget(IPC_PRIVATE, sizeof(struct shared), 0777|IPC_CREAT); | ||
123 | shm_id1 = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT); | ||
124 | pid = fork(); | ||
125 | if (pid < 0) { | ||
126 | perror("fork() failed"); | ||
127 | return TEST_FAIL; | ||
128 | } | ||
129 | |||
130 | if (pid == 0) | ||
131 | tm_spr(); | ||
132 | |||
133 | if (pid) { | ||
134 | pptr = (struct shared *)shmat(shm_id, NULL, 0); | ||
135 | pptr1 = (int *)shmat(shm_id1, NULL, 0); | ||
136 | |||
137 | while (!pptr1[0]) | ||
138 | asm volatile("" : : : "memory"); | ||
139 | ret = trace_tm_spr(pid); | ||
140 | if (ret) { | ||
141 | kill(pid, SIGKILL); | ||
142 | shmdt((void *)pptr); | ||
143 | shmdt((void *)pptr1); | ||
144 | shmctl(shm_id, IPC_RMID, NULL); | ||
145 | shmctl(shm_id1, IPC_RMID, NULL); | ||
146 | return TEST_FAIL; | ||
147 | } | ||
148 | |||
149 | shmdt((void *)pptr); | ||
150 | shmdt((void *)pptr1); | ||
151 | ret = wait(&status); | ||
152 | shmctl(shm_id, IPC_RMID, NULL); | ||
153 | shmctl(shm_id1, IPC_RMID, NULL); | ||
154 | if (ret != pid) { | ||
155 | printf("Child's exit status not captured\n"); | ||
156 | return TEST_FAIL; | ||
157 | } | ||
158 | |||
159 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
160 | TEST_PASS; | ||
161 | } | ||
162 | return TEST_PASS; | ||
163 | } | ||
164 | |||
165 | int main(int argc, char *argv[]) | ||
166 | { | ||
167 | return test_harness(ptrace_tm_spr, "ptrace_tm_spr"); | ||
168 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-tar.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-tar.c new file mode 100644 index 000000000000..48b462f75023 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-tar.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Ptrace test for TAR, PPR, DSCR registers in the TM context | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "tm.h" | ||
13 | #include "ptrace-tar.h" | ||
14 | |||
15 | int shm_id; | ||
16 | unsigned long *cptr, *pptr; | ||
17 | |||
18 | |||
19 | void tm_tar(void) | ||
20 | { | ||
21 | unsigned long result, texasr; | ||
22 | unsigned long regs[3]; | ||
23 | int ret; | ||
24 | |||
25 | cptr = (unsigned long *)shmat(shm_id, NULL, 0); | ||
26 | |||
27 | trans: | ||
28 | cptr[1] = 0; | ||
29 | asm __volatile__( | ||
30 | "li 4, %[tar_1];" | ||
31 | "mtspr %[sprn_tar], 4;" /* TAR_1 */ | ||
32 | "li 4, %[dscr_1];" | ||
33 | "mtspr %[sprn_dscr], 4;" /* DSCR_1 */ | ||
34 | "or 31,31,31;" /* PPR_1*/ | ||
35 | |||
36 | "1: ;" | ||
37 | "tbegin.;" | ||
38 | "beq 2f;" | ||
39 | |||
40 | "li 4, %[tar_2];" | ||
41 | "mtspr %[sprn_tar], 4;" /* TAR_2 */ | ||
42 | "li 4, %[dscr_2];" | ||
43 | "mtspr %[sprn_dscr], 4;" /* DSCR_2 */ | ||
44 | "or 1,1,1;" /* PPR_2 */ | ||
45 | "tsuspend.;" | ||
46 | "li 0, 1;" | ||
47 | "stw 0, 0(%[cptr1]);" | ||
48 | "tresume.;" | ||
49 | "b .;" | ||
50 | |||
51 | "tend.;" | ||
52 | "li 0, 0;" | ||
53 | "ori %[res], 0, 0;" | ||
54 | "b 3f;" | ||
55 | |||
56 | /* Transaction abort handler */ | ||
57 | "2: ;" | ||
58 | "li 0, 1;" | ||
59 | "ori %[res], 0, 0;" | ||
60 | "mfspr %[texasr], %[sprn_texasr];" | ||
61 | |||
62 | "3: ;" | ||
63 | |||
64 | : [res] "=r" (result), [texasr] "=r" (texasr) | ||
65 | : [sprn_dscr]"i"(SPRN_DSCR), [sprn_tar]"i"(SPRN_TAR), | ||
66 | [sprn_ppr]"i"(SPRN_PPR), [sprn_texasr]"i"(SPRN_TEXASR), | ||
67 | [tar_1]"i"(TAR_1), [dscr_1]"i"(DSCR_1), [tar_2]"i"(TAR_2), | ||
68 | [dscr_2]"i"(DSCR_2), [cptr1] "r" (&cptr[1]) | ||
69 | : "memory", "r0", "r1", "r3", "r4", "r5", "r6" | ||
70 | ); | ||
71 | |||
72 | /* TM failed, analyse */ | ||
73 | if (result) { | ||
74 | if (!cptr[0]) | ||
75 | goto trans; | ||
76 | |||
77 | regs[0] = mfspr(SPRN_TAR); | ||
78 | regs[1] = mfspr(SPRN_PPR); | ||
79 | regs[2] = mfspr(SPRN_DSCR); | ||
80 | |||
81 | shmdt(&cptr); | ||
82 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n", | ||
83 | user_read, regs[0], regs[1], regs[2]); | ||
84 | |||
85 | ret = validate_tar_registers(regs, TAR_4, PPR_4, DSCR_4); | ||
86 | if (ret) | ||
87 | exit(1); | ||
88 | exit(0); | ||
89 | } | ||
90 | shmdt(&cptr); | ||
91 | exit(1); | ||
92 | } | ||
93 | |||
94 | int trace_tm_tar(pid_t child) | ||
95 | { | ||
96 | unsigned long regs[3]; | ||
97 | |||
98 | FAIL_IF(start_trace(child)); | ||
99 | FAIL_IF(show_tar_registers(child, regs)); | ||
100 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n", | ||
101 | ptrace_read_running, regs[0], regs[1], regs[2]); | ||
102 | |||
103 | FAIL_IF(validate_tar_registers(regs, TAR_2, PPR_2, DSCR_2)); | ||
104 | FAIL_IF(show_tm_checkpointed_state(child, regs)); | ||
105 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n", | ||
106 | ptrace_read_ckpt, regs[0], regs[1], regs[2]); | ||
107 | |||
108 | FAIL_IF(validate_tar_registers(regs, TAR_1, PPR_1, DSCR_1)); | ||
109 | FAIL_IF(write_ckpt_tar_registers(child, TAR_4, PPR_4, DSCR_4)); | ||
110 | printf("%-30s TAR: %u PPR: %lx DSCR: %u\n", | ||
111 | ptrace_write_ckpt, TAR_4, PPR_4, DSCR_4); | ||
112 | |||
113 | pptr[0] = 1; | ||
114 | FAIL_IF(stop_trace(child)); | ||
115 | return TEST_PASS; | ||
116 | } | ||
117 | |||
118 | int ptrace_tm_tar(void) | ||
119 | { | ||
120 | pid_t pid; | ||
121 | int ret, status; | ||
122 | |||
123 | SKIP_IF(!have_htm()); | ||
124 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); | ||
125 | pid = fork(); | ||
126 | if (pid == 0) | ||
127 | tm_tar(); | ||
128 | |||
129 | pptr = (unsigned long *)shmat(shm_id, NULL, 0); | ||
130 | pptr[0] = 0; | ||
131 | |||
132 | if (pid) { | ||
133 | while (!pptr[1]) | ||
134 | asm volatile("" : : : "memory"); | ||
135 | ret = trace_tm_tar(pid); | ||
136 | if (ret) { | ||
137 | kill(pid, SIGTERM); | ||
138 | shmdt(&pptr); | ||
139 | shmctl(shm_id, IPC_RMID, NULL); | ||
140 | return TEST_FAIL; | ||
141 | } | ||
142 | shmdt(&pptr); | ||
143 | |||
144 | ret = wait(&status); | ||
145 | shmctl(shm_id, IPC_RMID, NULL); | ||
146 | if (ret != pid) { | ||
147 | printf("Child's exit status not captured\n"); | ||
148 | return TEST_FAIL; | ||
149 | } | ||
150 | |||
151 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
152 | TEST_PASS; | ||
153 | } | ||
154 | return TEST_PASS; | ||
155 | } | ||
156 | |||
157 | int main(int argc, char *argv[]) | ||
158 | { | ||
159 | return test_harness(ptrace_tm_tar, "ptrace_tm_tar"); | ||
160 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-vsx.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-vsx.c new file mode 100644 index 000000000000..b4081e2b22d5 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-vsx.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * Ptrace test for VMX/VSX registers in the TM context | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "tm.h" | ||
13 | #include "ptrace-vsx.h" | ||
14 | |||
15 | int shm_id; | ||
16 | unsigned long *cptr, *pptr; | ||
17 | |||
18 | unsigned long fp_load[VEC_MAX]; | ||
19 | unsigned long fp_store[VEC_MAX]; | ||
20 | unsigned long fp_load_ckpt[VEC_MAX]; | ||
21 | unsigned long fp_load_ckpt_new[VEC_MAX]; | ||
22 | |||
23 | __attribute__((used)) void load_vsx(void) | ||
24 | { | ||
25 | loadvsx(fp_load, 0); | ||
26 | } | ||
27 | |||
28 | __attribute__((used)) void load_vsx_ckpt(void) | ||
29 | { | ||
30 | loadvsx(fp_load_ckpt, 0); | ||
31 | } | ||
32 | |||
33 | void tm_vsx(void) | ||
34 | { | ||
35 | unsigned long result, texasr; | ||
36 | int ret; | ||
37 | |||
38 | cptr = (unsigned long *)shmat(shm_id, NULL, 0); | ||
39 | |||
40 | trans: | ||
41 | cptr[1] = 0; | ||
42 | asm __volatile__( | ||
43 | "bl load_vsx_ckpt;" | ||
44 | |||
45 | "1: ;" | ||
46 | "tbegin.;" | ||
47 | "beq 2f;" | ||
48 | |||
49 | "bl load_vsx;" | ||
50 | "tsuspend.;" | ||
51 | "li 7, 1;" | ||
52 | "stw 7, 0(%[cptr1]);" | ||
53 | "tresume.;" | ||
54 | "b .;" | ||
55 | |||
56 | "tend.;" | ||
57 | "li 0, 0;" | ||
58 | "ori %[res], 0, 0;" | ||
59 | "b 3f;" | ||
60 | |||
61 | "2: ;" | ||
62 | "li 0, 1;" | ||
63 | "ori %[res], 0, 0;" | ||
64 | "mfspr %[texasr], %[sprn_texasr];" | ||
65 | |||
66 | "3: ;" | ||
67 | : [res] "=r" (result), [texasr] "=r" (texasr) | ||
68 | : [fp_load] "r" (fp_load), [fp_load_ckpt] "r" (fp_load_ckpt), | ||
69 | [sprn_texasr] "i" (SPRN_TEXASR), [cptr1] "r" (&cptr[1]) | ||
70 | : "memory", "r0", "r1", "r2", "r3", "r4", | ||
71 | "r7", "r8", "r9", "r10", "r11" | ||
72 | ); | ||
73 | |||
74 | if (result) { | ||
75 | if (!cptr[0]) | ||
76 | goto trans; | ||
77 | |||
78 | shmdt((void *)cptr); | ||
79 | storevsx(fp_store, 0); | ||
80 | ret = compare_vsx_vmx(fp_store, fp_load_ckpt_new); | ||
81 | if (ret) | ||
82 | exit(1); | ||
83 | exit(0); | ||
84 | } | ||
85 | shmdt((void *)cptr); | ||
86 | exit(1); | ||
87 | } | ||
88 | |||
89 | int trace_tm_vsx(pid_t child) | ||
90 | { | ||
91 | unsigned long vsx[VSX_MAX]; | ||
92 | unsigned long vmx[VMX_MAX + 2][2]; | ||
93 | |||
94 | FAIL_IF(start_trace(child)); | ||
95 | FAIL_IF(show_vsx(child, vsx)); | ||
96 | FAIL_IF(validate_vsx(vsx, fp_load)); | ||
97 | FAIL_IF(show_vmx(child, vmx)); | ||
98 | FAIL_IF(validate_vmx(vmx, fp_load)); | ||
99 | FAIL_IF(show_vsx_ckpt(child, vsx)); | ||
100 | FAIL_IF(validate_vsx(vsx, fp_load_ckpt)); | ||
101 | FAIL_IF(show_vmx_ckpt(child, vmx)); | ||
102 | FAIL_IF(validate_vmx(vmx, fp_load_ckpt)); | ||
103 | memset(vsx, 0, sizeof(vsx)); | ||
104 | memset(vmx, 0, sizeof(vmx)); | ||
105 | |||
106 | load_vsx_vmx(fp_load_ckpt_new, vsx, vmx); | ||
107 | |||
108 | FAIL_IF(write_vsx_ckpt(child, vsx)); | ||
109 | FAIL_IF(write_vmx_ckpt(child, vmx)); | ||
110 | pptr[0] = 1; | ||
111 | FAIL_IF(stop_trace(child)); | ||
112 | return TEST_PASS; | ||
113 | } | ||
114 | |||
115 | int ptrace_tm_vsx(void) | ||
116 | { | ||
117 | pid_t pid; | ||
118 | int ret, status, i; | ||
119 | |||
120 | SKIP_IF(!have_htm()); | ||
121 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); | ||
122 | |||
123 | for (i = 0; i < 128; i++) { | ||
124 | fp_load[i] = 1 + rand(); | ||
125 | fp_load_ckpt[i] = 1 + 2 * rand(); | ||
126 | fp_load_ckpt_new[i] = 1 + 3 * rand(); | ||
127 | } | ||
128 | |||
129 | pid = fork(); | ||
130 | if (pid < 0) { | ||
131 | perror("fork() failed"); | ||
132 | return TEST_FAIL; | ||
133 | } | ||
134 | |||
135 | if (pid == 0) | ||
136 | tm_vsx(); | ||
137 | |||
138 | if (pid) { | ||
139 | pptr = (unsigned long *)shmat(shm_id, NULL, 0); | ||
140 | while (!pptr[1]) | ||
141 | asm volatile("" : : : "memory"); | ||
142 | |||
143 | ret = trace_tm_vsx(pid); | ||
144 | if (ret) { | ||
145 | kill(pid, SIGKILL); | ||
146 | shmdt((void *)pptr); | ||
147 | shmctl(shm_id, IPC_RMID, NULL); | ||
148 | return TEST_FAIL; | ||
149 | } | ||
150 | |||
151 | shmdt((void *)pptr); | ||
152 | ret = wait(&status); | ||
153 | shmctl(shm_id, IPC_RMID, NULL); | ||
154 | if (ret != pid) { | ||
155 | printf("Child's exit status not captured\n"); | ||
156 | return TEST_FAIL; | ||
157 | } | ||
158 | |||
159 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
160 | TEST_PASS; | ||
161 | } | ||
162 | return TEST_PASS; | ||
163 | } | ||
164 | |||
165 | int main(int argc, char *argv[]) | ||
166 | { | ||
167 | return test_harness(ptrace_tm_vsx, "ptrace_tm_vsx"); | ||
168 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.c b/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.c new file mode 100644 index 000000000000..04084ee7d27b --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * Ptrace test for VMX/VSX registers | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include "ptrace.h" | ||
12 | #include "ptrace-vsx.h" | ||
13 | |||
14 | /* Tracer and Tracee Shared Data */ | ||
15 | int shm_id; | ||
16 | int *cptr, *pptr; | ||
17 | |||
18 | unsigned long fp_load[VEC_MAX]; | ||
19 | unsigned long fp_load_new[VEC_MAX]; | ||
20 | unsigned long fp_store[VEC_MAX]; | ||
21 | |||
22 | void vsx(void) | ||
23 | { | ||
24 | int ret; | ||
25 | |||
26 | cptr = (int *)shmat(shm_id, NULL, 0); | ||
27 | loadvsx(fp_load, 0); | ||
28 | cptr[1] = 1; | ||
29 | |||
30 | while (!cptr[0]) | ||
31 | asm volatile("" : : : "memory"); | ||
32 | shmdt((void *) cptr); | ||
33 | |||
34 | storevsx(fp_store, 0); | ||
35 | ret = compare_vsx_vmx(fp_store, fp_load_new); | ||
36 | if (ret) | ||
37 | exit(1); | ||
38 | exit(0); | ||
39 | } | ||
40 | |||
41 | int trace_vsx(pid_t child) | ||
42 | { | ||
43 | unsigned long vsx[VSX_MAX]; | ||
44 | unsigned long vmx[VMX_MAX + 2][2]; | ||
45 | |||
46 | FAIL_IF(start_trace(child)); | ||
47 | FAIL_IF(show_vsx(child, vsx)); | ||
48 | FAIL_IF(validate_vsx(vsx, fp_load)); | ||
49 | FAIL_IF(show_vmx(child, vmx)); | ||
50 | FAIL_IF(validate_vmx(vmx, fp_load)); | ||
51 | |||
52 | memset(vsx, 0, sizeof(vsx)); | ||
53 | memset(vmx, 0, sizeof(vmx)); | ||
54 | load_vsx_vmx(fp_load_new, vsx, vmx); | ||
55 | |||
56 | FAIL_IF(write_vsx(child, vsx)); | ||
57 | FAIL_IF(write_vmx(child, vmx)); | ||
58 | FAIL_IF(stop_trace(child)); | ||
59 | |||
60 | return TEST_PASS; | ||
61 | } | ||
62 | |||
63 | int ptrace_vsx(void) | ||
64 | { | ||
65 | pid_t pid; | ||
66 | int ret, status, i; | ||
67 | |||
68 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); | ||
69 | |||
70 | for (i = 0; i < VEC_MAX; i++) | ||
71 | fp_load[i] = i + rand(); | ||
72 | |||
73 | for (i = 0; i < VEC_MAX; i++) | ||
74 | fp_load_new[i] = i + 2 * rand(); | ||
75 | |||
76 | pid = fork(); | ||
77 | if (pid < 0) { | ||
78 | perror("fork() failed"); | ||
79 | return TEST_FAIL; | ||
80 | } | ||
81 | |||
82 | if (pid == 0) | ||
83 | vsx(); | ||
84 | |||
85 | if (pid) { | ||
86 | pptr = (int *)shmat(shm_id, NULL, 0); | ||
87 | while (!pptr[1]) | ||
88 | asm volatile("" : : : "memory"); | ||
89 | |||
90 | ret = trace_vsx(pid); | ||
91 | if (ret) { | ||
92 | kill(pid, SIGTERM); | ||
93 | shmdt((void *)pptr); | ||
94 | shmctl(shm_id, IPC_RMID, NULL); | ||
95 | return TEST_FAIL; | ||
96 | } | ||
97 | |||
98 | pptr[0] = 1; | ||
99 | shmdt((void *)pptr); | ||
100 | |||
101 | ret = wait(&status); | ||
102 | shmctl(shm_id, IPC_RMID, NULL); | ||
103 | if (ret != pid) { | ||
104 | printf("Child's exit status not captured\n"); | ||
105 | return TEST_FAIL; | ||
106 | } | ||
107 | |||
108 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : | ||
109 | TEST_PASS; | ||
110 | } | ||
111 | return TEST_PASS; | ||
112 | } | ||
113 | |||
114 | int main(int argc, char *argv[]) | ||
115 | { | ||
116 | return test_harness(ptrace_vsx, "ptrace_vsx"); | ||
117 | } | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.h b/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.h new file mode 100644 index 000000000000..f4e4b427c9d9 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #define VEC_MAX 128 | ||
10 | #define VSX_MAX 32 | ||
11 | #define VMX_MAX 32 | ||
12 | |||
13 | /* | ||
14 | * unsigned long vsx[32] | ||
15 | * unsigned long load[128] | ||
16 | */ | ||
17 | int validate_vsx(unsigned long *vsx, unsigned long *load) | ||
18 | { | ||
19 | int i; | ||
20 | |||
21 | for (i = 0; i < VSX_MAX; i++) { | ||
22 | if (vsx[i] != load[2 * i + 1]) { | ||
23 | printf("vsx[%d]: %lx load[%d] %lx\n", | ||
24 | i, vsx[i], 2 * i + 1, load[2 * i + 1]); | ||
25 | return TEST_FAIL; | ||
26 | } | ||
27 | } | ||
28 | return TEST_PASS; | ||
29 | } | ||
30 | |||
31 | /* | ||
32 | * unsigned long vmx[32][2] | ||
33 | * unsigned long load[128] | ||
34 | */ | ||
35 | int validate_vmx(unsigned long vmx[][2], unsigned long *load) | ||
36 | { | ||
37 | int i; | ||
38 | |||
39 | for (i = 0; i < VMX_MAX; i++) { | ||
40 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | ||
41 | if ((vmx[i][0] != load[64 + 2 * i]) || | ||
42 | (vmx[i][1] != load[65 + 2 * i])) { | ||
43 | printf("vmx[%d][0]: %lx load[%d] %lx\n", | ||
44 | i, vmx[i][0], 64 + 2 * i, | ||
45 | load[64 + 2 * i]); | ||
46 | printf("vmx[%d][1]: %lx load[%d] %lx\n", | ||
47 | i, vmx[i][1], 65 + 2 * i, | ||
48 | load[65 + 2 * i]); | ||
49 | return TEST_FAIL; | ||
50 | } | ||
51 | #else /* | ||
52 | * In LE each value pair is stored in an | ||
53 | * alternate manner. | ||
54 | */ | ||
55 | if ((vmx[i][0] != load[65 + 2 * i]) || | ||
56 | (vmx[i][1] != load[64 + 2 * i])) { | ||
57 | printf("vmx[%d][0]: %lx load[%d] %lx\n", | ||
58 | i, vmx[i][0], 65 + 2 * i, | ||
59 | load[65 + 2 * i]); | ||
60 | printf("vmx[%d][1]: %lx load[%d] %lx\n", | ||
61 | i, vmx[i][1], 64 + 2 * i, | ||
62 | load[64 + 2 * i]); | ||
63 | return TEST_FAIL; | ||
64 | } | ||
65 | #endif | ||
66 | } | ||
67 | return TEST_PASS; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * unsigned long store[128] | ||
72 | * unsigned long load[128] | ||
73 | */ | ||
74 | int compare_vsx_vmx(unsigned long *store, unsigned long *load) | ||
75 | { | ||
76 | int i; | ||
77 | |||
78 | for (i = 0; i < VSX_MAX; i++) { | ||
79 | if (store[1 + 2 * i] != load[1 + 2 * i]) { | ||
80 | printf("store[%d]: %lx load[%d] %lx\n", | ||
81 | 1 + 2 * i, store[i], | ||
82 | 1 + 2 * i, load[i]); | ||
83 | return TEST_FAIL; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | ||
88 | for (i = 64; i < VEC_MAX; i++) { | ||
89 | if (store[i] != load[i]) { | ||
90 | printf("store[%d]: %lx load[%d] %lx\n", | ||
91 | i, store[i], i, load[i]); | ||
92 | return TEST_FAIL; | ||
93 | } | ||
94 | } | ||
95 | #else /* In LE each value pair is stored in an alternate manner */ | ||
96 | for (i = 64; i < VEC_MAX; i++) { | ||
97 | if (!(i % 2) && (store[i] != load[i+1])) { | ||
98 | printf("store[%d]: %lx load[%d] %lx\n", | ||
99 | i, store[i], i+1, load[i+1]); | ||
100 | return TEST_FAIL; | ||
101 | } | ||
102 | if ((i % 2) && (store[i] != load[i-1])) { | ||
103 | printf("here store[%d]: %lx load[%d] %lx\n", | ||
104 | i, store[i], i-1, load[i-1]); | ||
105 | return TEST_FAIL; | ||
106 | } | ||
107 | } | ||
108 | #endif | ||
109 | return TEST_PASS; | ||
110 | } | ||
111 | |||
112 | void load_vsx_vmx(unsigned long *load, unsigned long *vsx, | ||
113 | unsigned long vmx[][2]) | ||
114 | { | ||
115 | int i; | ||
116 | |||
117 | for (i = 0; i < VSX_MAX; i++) | ||
118 | vsx[i] = load[1 + 2 * i]; | ||
119 | |||
120 | for (i = 0; i < VMX_MAX; i++) { | ||
121 | vmx[i][0] = load[64 + 2 * i]; | ||
122 | vmx[i][1] = load[65 + 2 * i]; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | void loadvsx(void *p, int tmp); | ||
127 | void storevsx(void *p, int tmp); | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace.h b/tools/testing/selftests/powerpc/ptrace/ptrace.h new file mode 100644 index 000000000000..19fb825270a1 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace.h | |||
@@ -0,0 +1,711 @@ | |||
1 | /* | ||
2 | * Ptrace interface test helper functions | ||
3 | * | ||
4 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. | ||
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 | #include <inttypes.h> | ||
12 | #include <unistd.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #include <malloc.h> | ||
16 | #include <errno.h> | ||
17 | #include <time.h> | ||
18 | #include <sys/ptrace.h> | ||
19 | #include <sys/ioctl.h> | ||
20 | #include <sys/uio.h> | ||
21 | #include <sys/types.h> | ||
22 | #include <sys/wait.h> | ||
23 | #include <sys/signal.h> | ||
24 | #include <sys/ipc.h> | ||
25 | #include <sys/shm.h> | ||
26 | #include <sys/user.h> | ||
27 | #include <linux/elf.h> | ||
28 | #include <linux/types.h> | ||
29 | #include <linux/auxvec.h> | ||
30 | #include "reg.h" | ||
31 | #include "utils.h" | ||
32 | |||
33 | #define TEST_PASS 0 | ||
34 | #define TEST_FAIL 1 | ||
35 | |||
36 | struct fpr_regs { | ||
37 | unsigned long fpr[32]; | ||
38 | unsigned long fpscr; | ||
39 | }; | ||
40 | |||
41 | struct tm_spr_regs { | ||
42 | unsigned long tm_tfhar; | ||
43 | unsigned long tm_texasr; | ||
44 | unsigned long tm_tfiar; | ||
45 | }; | ||
46 | |||
47 | #ifndef NT_PPC_TAR | ||
48 | #define NT_PPC_TAR 0x103 | ||
49 | #define NT_PPC_PPR 0x104 | ||
50 | #define NT_PPC_DSCR 0x105 | ||
51 | #define NT_PPC_EBB 0x106 | ||
52 | #define NT_PPC_PMU 0x107 | ||
53 | #define NT_PPC_TM_CGPR 0x108 | ||
54 | #define NT_PPC_TM_CFPR 0x109 | ||
55 | #define NT_PPC_TM_CVMX 0x10a | ||
56 | #define NT_PPC_TM_CVSX 0x10b | ||
57 | #define NT_PPC_TM_SPR 0x10c | ||
58 | #define NT_PPC_TM_CTAR 0x10d | ||
59 | #define NT_PPC_TM_CPPR 0x10e | ||
60 | #define NT_PPC_TM_CDSCR 0x10f | ||
61 | #endif | ||
62 | |||
63 | /* Basic ptrace operations */ | ||
64 | int start_trace(pid_t child) | ||
65 | { | ||
66 | int ret; | ||
67 | |||
68 | ret = ptrace(PTRACE_ATTACH, child, NULL, NULL); | ||
69 | if (ret) { | ||
70 | perror("ptrace(PTRACE_ATTACH) failed"); | ||
71 | return TEST_FAIL; | ||
72 | } | ||
73 | ret = waitpid(child, NULL, 0); | ||
74 | if (ret != child) { | ||
75 | perror("waitpid() failed"); | ||
76 | return TEST_FAIL; | ||
77 | } | ||
78 | return TEST_PASS; | ||
79 | } | ||
80 | |||
81 | int stop_trace(pid_t child) | ||
82 | { | ||
83 | int ret; | ||
84 | |||
85 | ret = ptrace(PTRACE_DETACH, child, NULL, NULL); | ||
86 | if (ret) { | ||
87 | perror("ptrace(PTRACE_DETACH) failed"); | ||
88 | return TEST_FAIL; | ||
89 | } | ||
90 | return TEST_PASS; | ||
91 | } | ||
92 | |||
93 | int cont_trace(pid_t child) | ||
94 | { | ||
95 | int ret; | ||
96 | |||
97 | ret = ptrace(PTRACE_CONT, child, NULL, NULL); | ||
98 | if (ret) { | ||
99 | perror("ptrace(PTRACE_CONT) failed"); | ||
100 | return TEST_FAIL; | ||
101 | } | ||
102 | return TEST_PASS; | ||
103 | } | ||
104 | |||
105 | /* TAR, PPR, DSCR */ | ||
106 | int show_tar_registers(pid_t child, unsigned long *out) | ||
107 | { | ||
108 | struct iovec iov; | ||
109 | unsigned long *reg; | ||
110 | int ret; | ||
111 | |||
112 | reg = malloc(sizeof(unsigned long)); | ||
113 | if (!reg) { | ||
114 | perror("malloc() failed"); | ||
115 | return TEST_FAIL; | ||
116 | } | ||
117 | iov.iov_base = (u64 *) reg; | ||
118 | iov.iov_len = sizeof(unsigned long); | ||
119 | |||
120 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TAR, &iov); | ||
121 | if (ret) { | ||
122 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
123 | goto fail; | ||
124 | } | ||
125 | if (out) | ||
126 | out[0] = *reg; | ||
127 | |||
128 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_PPR, &iov); | ||
129 | if (ret) { | ||
130 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
131 | goto fail; | ||
132 | } | ||
133 | if (out) | ||
134 | out[1] = *reg; | ||
135 | |||
136 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_DSCR, &iov); | ||
137 | if (ret) { | ||
138 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
139 | goto fail; | ||
140 | } | ||
141 | if (out) | ||
142 | out[2] = *reg; | ||
143 | |||
144 | free(reg); | ||
145 | return TEST_PASS; | ||
146 | fail: | ||
147 | free(reg); | ||
148 | return TEST_FAIL; | ||
149 | } | ||
150 | |||
151 | int write_tar_registers(pid_t child, unsigned long tar, | ||
152 | unsigned long ppr, unsigned long dscr) | ||
153 | { | ||
154 | struct iovec iov; | ||
155 | unsigned long *reg; | ||
156 | int ret; | ||
157 | |||
158 | reg = malloc(sizeof(unsigned long)); | ||
159 | if (!reg) { | ||
160 | perror("malloc() failed"); | ||
161 | return TEST_FAIL; | ||
162 | } | ||
163 | |||
164 | iov.iov_base = (u64 *) reg; | ||
165 | iov.iov_len = sizeof(unsigned long); | ||
166 | |||
167 | *reg = tar; | ||
168 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TAR, &iov); | ||
169 | if (ret) { | ||
170 | perror("ptrace(PTRACE_SETREGSET) failed"); | ||
171 | goto fail; | ||
172 | } | ||
173 | |||
174 | *reg = ppr; | ||
175 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_PPR, &iov); | ||
176 | if (ret) { | ||
177 | perror("ptrace(PTRACE_SETREGSET) failed"); | ||
178 | goto fail; | ||
179 | } | ||
180 | |||
181 | *reg = dscr; | ||
182 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_DSCR, &iov); | ||
183 | if (ret) { | ||
184 | perror("ptrace(PTRACE_SETREGSET) failed"); | ||
185 | goto fail; | ||
186 | } | ||
187 | |||
188 | free(reg); | ||
189 | return TEST_PASS; | ||
190 | fail: | ||
191 | free(reg); | ||
192 | return TEST_FAIL; | ||
193 | } | ||
194 | |||
195 | int show_tm_checkpointed_state(pid_t child, unsigned long *out) | ||
196 | { | ||
197 | struct iovec iov; | ||
198 | unsigned long *reg; | ||
199 | int ret; | ||
200 | |||
201 | reg = malloc(sizeof(unsigned long)); | ||
202 | if (!reg) { | ||
203 | perror("malloc() failed"); | ||
204 | return TEST_FAIL; | ||
205 | } | ||
206 | |||
207 | iov.iov_base = (u64 *) reg; | ||
208 | iov.iov_len = sizeof(unsigned long); | ||
209 | |||
210 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CTAR, &iov); | ||
211 | if (ret) { | ||
212 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
213 | goto fail; | ||
214 | } | ||
215 | if (out) | ||
216 | out[0] = *reg; | ||
217 | |||
218 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CPPR, &iov); | ||
219 | if (ret) { | ||
220 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
221 | goto fail; | ||
222 | } | ||
223 | if (out) | ||
224 | out[1] = *reg; | ||
225 | |||
226 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CDSCR, &iov); | ||
227 | if (ret) { | ||
228 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
229 | goto fail; | ||
230 | } | ||
231 | if (out) | ||
232 | out[2] = *reg; | ||
233 | |||
234 | free(reg); | ||
235 | return TEST_PASS; | ||
236 | |||
237 | fail: | ||
238 | free(reg); | ||
239 | return TEST_FAIL; | ||
240 | } | ||
241 | |||
242 | int write_ckpt_tar_registers(pid_t child, unsigned long tar, | ||
243 | unsigned long ppr, unsigned long dscr) | ||
244 | { | ||
245 | struct iovec iov; | ||
246 | unsigned long *reg; | ||
247 | int ret; | ||
248 | |||
249 | reg = malloc(sizeof(unsigned long)); | ||
250 | if (!reg) { | ||
251 | perror("malloc() failed"); | ||
252 | return TEST_FAIL; | ||
253 | } | ||
254 | |||
255 | iov.iov_base = (u64 *) reg; | ||
256 | iov.iov_len = sizeof(unsigned long); | ||
257 | |||
258 | *reg = tar; | ||
259 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CTAR, &iov); | ||
260 | if (ret) { | ||
261 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
262 | goto fail; | ||
263 | } | ||
264 | |||
265 | *reg = ppr; | ||
266 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CPPR, &iov); | ||
267 | if (ret) { | ||
268 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
269 | goto fail; | ||
270 | } | ||
271 | |||
272 | *reg = dscr; | ||
273 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CDSCR, &iov); | ||
274 | if (ret) { | ||
275 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
276 | goto fail; | ||
277 | } | ||
278 | |||
279 | free(reg); | ||
280 | return TEST_PASS; | ||
281 | fail: | ||
282 | free(reg); | ||
283 | return TEST_FAIL; | ||
284 | } | ||
285 | |||
286 | /* FPR */ | ||
287 | int show_fpr(pid_t child, unsigned long *fpr) | ||
288 | { | ||
289 | struct fpr_regs *regs; | ||
290 | int ret, i; | ||
291 | |||
292 | regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs)); | ||
293 | ret = ptrace(PTRACE_GETFPREGS, child, NULL, regs); | ||
294 | if (ret) { | ||
295 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
296 | return TEST_FAIL; | ||
297 | } | ||
298 | |||
299 | if (fpr) { | ||
300 | for (i = 0; i < 32; i++) | ||
301 | fpr[i] = regs->fpr[i]; | ||
302 | } | ||
303 | return TEST_PASS; | ||
304 | } | ||
305 | |||
306 | int write_fpr(pid_t child, unsigned long val) | ||
307 | { | ||
308 | struct fpr_regs *regs; | ||
309 | int ret, i; | ||
310 | |||
311 | regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs)); | ||
312 | ret = ptrace(PTRACE_GETFPREGS, child, NULL, regs); | ||
313 | if (ret) { | ||
314 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
315 | return TEST_FAIL; | ||
316 | } | ||
317 | |||
318 | for (i = 0; i < 32; i++) | ||
319 | regs->fpr[i] = val; | ||
320 | |||
321 | ret = ptrace(PTRACE_SETFPREGS, child, NULL, regs); | ||
322 | if (ret) { | ||
323 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
324 | return TEST_FAIL; | ||
325 | } | ||
326 | return TEST_PASS; | ||
327 | } | ||
328 | |||
329 | int show_ckpt_fpr(pid_t child, unsigned long *fpr) | ||
330 | { | ||
331 | struct fpr_regs *regs; | ||
332 | struct iovec iov; | ||
333 | int ret, i; | ||
334 | |||
335 | regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs)); | ||
336 | iov.iov_base = regs; | ||
337 | iov.iov_len = sizeof(struct fpr_regs); | ||
338 | |||
339 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov); | ||
340 | if (ret) { | ||
341 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
342 | return TEST_FAIL; | ||
343 | } | ||
344 | |||
345 | if (fpr) { | ||
346 | for (i = 0; i < 32; i++) | ||
347 | fpr[i] = regs->fpr[i]; | ||
348 | } | ||
349 | |||
350 | return TEST_PASS; | ||
351 | } | ||
352 | |||
353 | int write_ckpt_fpr(pid_t child, unsigned long val) | ||
354 | { | ||
355 | struct fpr_regs *regs; | ||
356 | struct iovec iov; | ||
357 | int ret, i; | ||
358 | |||
359 | regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs)); | ||
360 | iov.iov_base = regs; | ||
361 | iov.iov_len = sizeof(struct fpr_regs); | ||
362 | |||
363 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov); | ||
364 | if (ret) { | ||
365 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
366 | return TEST_FAIL; | ||
367 | } | ||
368 | |||
369 | for (i = 0; i < 32; i++) | ||
370 | regs->fpr[i] = val; | ||
371 | |||
372 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CFPR, &iov); | ||
373 | if (ret) { | ||
374 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
375 | return TEST_FAIL; | ||
376 | } | ||
377 | return TEST_PASS; | ||
378 | } | ||
379 | |||
380 | /* GPR */ | ||
381 | int show_gpr(pid_t child, unsigned long *gpr) | ||
382 | { | ||
383 | struct pt_regs *regs; | ||
384 | int ret, i; | ||
385 | |||
386 | regs = (struct pt_regs *) malloc(sizeof(struct pt_regs)); | ||
387 | if (!regs) { | ||
388 | perror("malloc() failed"); | ||
389 | return TEST_FAIL; | ||
390 | } | ||
391 | |||
392 | ret = ptrace(PTRACE_GETREGS, child, NULL, regs); | ||
393 | if (ret) { | ||
394 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
395 | return TEST_FAIL; | ||
396 | } | ||
397 | |||
398 | if (gpr) { | ||
399 | for (i = 14; i < 32; i++) | ||
400 | gpr[i-14] = regs->gpr[i]; | ||
401 | } | ||
402 | |||
403 | return TEST_PASS; | ||
404 | } | ||
405 | |||
406 | int write_gpr(pid_t child, unsigned long val) | ||
407 | { | ||
408 | struct pt_regs *regs; | ||
409 | int i, ret; | ||
410 | |||
411 | regs = (struct pt_regs *) malloc(sizeof(struct pt_regs)); | ||
412 | if (!regs) { | ||
413 | perror("malloc() failed"); | ||
414 | return TEST_FAIL; | ||
415 | } | ||
416 | |||
417 | ret = ptrace(PTRACE_GETREGS, child, NULL, regs); | ||
418 | if (ret) { | ||
419 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
420 | return TEST_FAIL; | ||
421 | } | ||
422 | |||
423 | for (i = 14; i < 32; i++) | ||
424 | regs->gpr[i] = val; | ||
425 | |||
426 | ret = ptrace(PTRACE_SETREGS, child, NULL, regs); | ||
427 | if (ret) { | ||
428 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
429 | return TEST_FAIL; | ||
430 | } | ||
431 | return TEST_PASS; | ||
432 | } | ||
433 | |||
434 | int show_ckpt_gpr(pid_t child, unsigned long *gpr) | ||
435 | { | ||
436 | struct pt_regs *regs; | ||
437 | struct iovec iov; | ||
438 | int ret, i; | ||
439 | |||
440 | regs = (struct pt_regs *) malloc(sizeof(struct pt_regs)); | ||
441 | if (!regs) { | ||
442 | perror("malloc() failed"); | ||
443 | return TEST_FAIL; | ||
444 | } | ||
445 | |||
446 | iov.iov_base = (u64 *) regs; | ||
447 | iov.iov_len = sizeof(struct pt_regs); | ||
448 | |||
449 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov); | ||
450 | if (ret) { | ||
451 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
452 | return TEST_FAIL; | ||
453 | } | ||
454 | |||
455 | if (gpr) { | ||
456 | for (i = 14; i < 32; i++) | ||
457 | gpr[i-14] = regs->gpr[i]; | ||
458 | } | ||
459 | |||
460 | return TEST_PASS; | ||
461 | } | ||
462 | |||
463 | int write_ckpt_gpr(pid_t child, unsigned long val) | ||
464 | { | ||
465 | struct pt_regs *regs; | ||
466 | struct iovec iov; | ||
467 | int ret, i; | ||
468 | |||
469 | regs = (struct pt_regs *) malloc(sizeof(struct pt_regs)); | ||
470 | if (!regs) { | ||
471 | perror("malloc() failed\n"); | ||
472 | return TEST_FAIL; | ||
473 | } | ||
474 | iov.iov_base = (u64 *) regs; | ||
475 | iov.iov_len = sizeof(struct pt_regs); | ||
476 | |||
477 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov); | ||
478 | if (ret) { | ||
479 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
480 | return TEST_FAIL; | ||
481 | } | ||
482 | |||
483 | for (i = 14; i < 32; i++) | ||
484 | regs->gpr[i] = val; | ||
485 | |||
486 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CGPR, &iov); | ||
487 | if (ret) { | ||
488 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
489 | return TEST_FAIL; | ||
490 | } | ||
491 | return TEST_PASS; | ||
492 | } | ||
493 | |||
494 | /* VMX */ | ||
495 | int show_vmx(pid_t child, unsigned long vmx[][2]) | ||
496 | { | ||
497 | int ret; | ||
498 | |||
499 | ret = ptrace(PTRACE_GETVRREGS, child, 0, vmx); | ||
500 | if (ret) { | ||
501 | perror("ptrace(PTRACE_GETVRREGS) failed"); | ||
502 | return TEST_FAIL; | ||
503 | } | ||
504 | return TEST_PASS; | ||
505 | } | ||
506 | |||
507 | int show_vmx_ckpt(pid_t child, unsigned long vmx[][2]) | ||
508 | { | ||
509 | unsigned long regs[34][2]; | ||
510 | struct iovec iov; | ||
511 | int ret; | ||
512 | |||
513 | iov.iov_base = (u64 *) regs; | ||
514 | iov.iov_len = sizeof(regs); | ||
515 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CVMX, &iov); | ||
516 | if (ret) { | ||
517 | perror("ptrace(PTRACE_GETREGSET, NT_PPC_TM_CVMX) failed"); | ||
518 | return TEST_FAIL; | ||
519 | } | ||
520 | memcpy(vmx, regs, sizeof(regs)); | ||
521 | return TEST_PASS; | ||
522 | } | ||
523 | |||
524 | |||
525 | int write_vmx(pid_t child, unsigned long vmx[][2]) | ||
526 | { | ||
527 | int ret; | ||
528 | |||
529 | ret = ptrace(PTRACE_SETVRREGS, child, 0, vmx); | ||
530 | if (ret) { | ||
531 | perror("ptrace(PTRACE_SETVRREGS) failed"); | ||
532 | return TEST_FAIL; | ||
533 | } | ||
534 | return TEST_PASS; | ||
535 | } | ||
536 | |||
537 | int write_vmx_ckpt(pid_t child, unsigned long vmx[][2]) | ||
538 | { | ||
539 | unsigned long regs[34][2]; | ||
540 | struct iovec iov; | ||
541 | int ret; | ||
542 | |||
543 | memcpy(regs, vmx, sizeof(regs)); | ||
544 | iov.iov_base = (u64 *) regs; | ||
545 | iov.iov_len = sizeof(regs); | ||
546 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CVMX, &iov); | ||
547 | if (ret) { | ||
548 | perror("ptrace(PTRACE_SETREGSET, NT_PPC_TM_CVMX) failed"); | ||
549 | return TEST_FAIL; | ||
550 | } | ||
551 | return TEST_PASS; | ||
552 | } | ||
553 | |||
554 | /* VSX */ | ||
555 | int show_vsx(pid_t child, unsigned long *vsx) | ||
556 | { | ||
557 | int ret; | ||
558 | |||
559 | ret = ptrace(PTRACE_GETVSRREGS, child, 0, vsx); | ||
560 | if (ret) { | ||
561 | perror("ptrace(PTRACE_GETVSRREGS) failed"); | ||
562 | return TEST_FAIL; | ||
563 | } | ||
564 | return TEST_PASS; | ||
565 | } | ||
566 | |||
567 | int show_vsx_ckpt(pid_t child, unsigned long *vsx) | ||
568 | { | ||
569 | unsigned long regs[32]; | ||
570 | struct iovec iov; | ||
571 | int ret; | ||
572 | |||
573 | iov.iov_base = (u64 *) regs; | ||
574 | iov.iov_len = sizeof(regs); | ||
575 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CVSX, &iov); | ||
576 | if (ret) { | ||
577 | perror("ptrace(PTRACE_GETREGSET, NT_PPC_TM_CVSX) failed"); | ||
578 | return TEST_FAIL; | ||
579 | } | ||
580 | memcpy(vsx, regs, sizeof(regs)); | ||
581 | return TEST_PASS; | ||
582 | } | ||
583 | |||
584 | int write_vsx(pid_t child, unsigned long *vsx) | ||
585 | { | ||
586 | int ret; | ||
587 | |||
588 | ret = ptrace(PTRACE_SETVSRREGS, child, 0, vsx); | ||
589 | if (ret) { | ||
590 | perror("ptrace(PTRACE_SETVSRREGS) failed"); | ||
591 | return TEST_FAIL; | ||
592 | } | ||
593 | return TEST_PASS; | ||
594 | } | ||
595 | |||
596 | int write_vsx_ckpt(pid_t child, unsigned long *vsx) | ||
597 | { | ||
598 | unsigned long regs[32]; | ||
599 | struct iovec iov; | ||
600 | int ret; | ||
601 | |||
602 | memcpy(regs, vsx, sizeof(regs)); | ||
603 | iov.iov_base = (u64 *) regs; | ||
604 | iov.iov_len = sizeof(regs); | ||
605 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CVSX, &iov); | ||
606 | if (ret) { | ||
607 | perror("ptrace(PTRACE_SETREGSET, NT_PPC_TM_CVSX) failed"); | ||
608 | return TEST_FAIL; | ||
609 | } | ||
610 | return TEST_PASS; | ||
611 | } | ||
612 | |||
613 | /* TM SPR */ | ||
614 | int show_tm_spr(pid_t child, struct tm_spr_regs *out) | ||
615 | { | ||
616 | struct tm_spr_regs *regs; | ||
617 | struct iovec iov; | ||
618 | int ret; | ||
619 | |||
620 | regs = (struct tm_spr_regs *) malloc(sizeof(struct tm_spr_regs)); | ||
621 | if (!regs) { | ||
622 | perror("malloc() failed"); | ||
623 | return TEST_FAIL; | ||
624 | } | ||
625 | |||
626 | iov.iov_base = (u64 *) regs; | ||
627 | iov.iov_len = sizeof(struct tm_spr_regs); | ||
628 | |||
629 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_SPR, &iov); | ||
630 | if (ret) { | ||
631 | perror("ptrace(PTRACE_GETREGSET) failed"); | ||
632 | return TEST_FAIL; | ||
633 | } | ||
634 | |||
635 | if (out) | ||
636 | memcpy(out, regs, sizeof(struct tm_spr_regs)); | ||
637 | |||
638 | return TEST_PASS; | ||
639 | } | ||
640 | |||
641 | |||
642 | |||
643 | /* Analyse TEXASR after TM failure */ | ||
644 | inline unsigned long get_tfiar(void) | ||
645 | { | ||
646 | unsigned long ret; | ||
647 | |||
648 | asm volatile("mfspr %0,%1" : "=r" (ret) : "i" (SPRN_TFIAR)); | ||
649 | return ret; | ||
650 | } | ||
651 | |||
652 | void analyse_texasr(unsigned long texasr) | ||
653 | { | ||
654 | printf("TEXASR: %16lx\t", texasr); | ||
655 | |||
656 | if (texasr & TEXASR_FP) | ||
657 | printf("TEXASR_FP "); | ||
658 | |||
659 | if (texasr & TEXASR_DA) | ||
660 | printf("TEXASR_DA "); | ||
661 | |||
662 | if (texasr & TEXASR_NO) | ||
663 | printf("TEXASR_NO "); | ||
664 | |||
665 | if (texasr & TEXASR_FO) | ||
666 | printf("TEXASR_FO "); | ||
667 | |||
668 | if (texasr & TEXASR_SIC) | ||
669 | printf("TEXASR_SIC "); | ||
670 | |||
671 | if (texasr & TEXASR_NTC) | ||
672 | printf("TEXASR_NTC "); | ||
673 | |||
674 | if (texasr & TEXASR_TC) | ||
675 | printf("TEXASR_TC "); | ||
676 | |||
677 | if (texasr & TEXASR_TIC) | ||
678 | printf("TEXASR_TIC "); | ||
679 | |||
680 | if (texasr & TEXASR_IC) | ||
681 | printf("TEXASR_IC "); | ||
682 | |||
683 | if (texasr & TEXASR_IFC) | ||
684 | printf("TEXASR_IFC "); | ||
685 | |||
686 | if (texasr & TEXASR_ABT) | ||
687 | printf("TEXASR_ABT "); | ||
688 | |||
689 | if (texasr & TEXASR_SPD) | ||
690 | printf("TEXASR_SPD "); | ||
691 | |||
692 | if (texasr & TEXASR_HV) | ||
693 | printf("TEXASR_HV "); | ||
694 | |||
695 | if (texasr & TEXASR_PR) | ||
696 | printf("TEXASR_PR "); | ||
697 | |||
698 | if (texasr & TEXASR_FS) | ||
699 | printf("TEXASR_FS "); | ||
700 | |||
701 | if (texasr & TEXASR_TE) | ||
702 | printf("TEXASR_TE "); | ||
703 | |||
704 | if (texasr & TEXASR_ROT) | ||
705 | printf("TEXASR_ROT "); | ||
706 | |||
707 | printf("TFIAR :%lx\n", get_tfiar()); | ||
708 | } | ||
709 | |||
710 | void store_gpr(unsigned long *addr); | ||
711 | void store_fpr(float *addr); | ||
diff --git a/tools/testing/selftests/powerpc/reg.h b/tools/testing/selftests/powerpc/reg.h deleted file mode 100644 index fddf368ed82f..000000000000 --- a/tools/testing/selftests/powerpc/reg.h +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014, Michael Ellerman, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | */ | ||
5 | |||
6 | #ifndef _SELFTESTS_POWERPC_REG_H | ||
7 | #define _SELFTESTS_POWERPC_REG_H | ||
8 | |||
9 | #define __stringify_1(x) #x | ||
10 | #define __stringify(x) __stringify_1(x) | ||
11 | |||
12 | #define mfspr(rn) ({unsigned long rval; \ | ||
13 | asm volatile("mfspr %0," _str(rn) \ | ||
14 | : "=r" (rval)); rval; }) | ||
15 | #define mtspr(rn, v) asm volatile("mtspr " _str(rn) ",%0" : \ | ||
16 | : "r" ((unsigned long)(v)) \ | ||
17 | : "memory") | ||
18 | |||
19 | #define mb() asm volatile("sync" : : : "memory"); | ||
20 | |||
21 | #define SPRN_MMCR2 769 | ||
22 | #define SPRN_MMCRA 770 | ||
23 | #define SPRN_MMCR0 779 | ||
24 | #define MMCR0_PMAO 0x00000080 | ||
25 | #define MMCR0_PMAE 0x04000000 | ||
26 | #define MMCR0_FC 0x80000000 | ||
27 | #define SPRN_EBBHR 804 | ||
28 | #define SPRN_EBBRR 805 | ||
29 | #define SPRN_BESCR 806 /* Branch event status & control register */ | ||
30 | #define SPRN_BESCRS 800 /* Branch event status & control set (1 bits set to 1) */ | ||
31 | #define SPRN_BESCRSU 801 /* Branch event status & control set upper */ | ||
32 | #define SPRN_BESCRR 802 /* Branch event status & control REset (1 bits set to 0) */ | ||
33 | #define SPRN_BESCRRU 803 /* Branch event status & control REset upper */ | ||
34 | |||
35 | #define BESCR_PMEO 0x1 /* PMU Event-based exception Occurred */ | ||
36 | #define BESCR_PME (0x1ul << 32) /* PMU Event-based exception Enable */ | ||
37 | #define BESCR_LME (0x1ul << 34) /* Load Monitor Enable */ | ||
38 | #define BESCR_LMEO (0x1ul << 2) /* Load Monitor Exception Occurred */ | ||
39 | |||
40 | #define SPRN_LMRR 813 /* Load Monitor Region Register */ | ||
41 | #define SPRN_LMSER 814 /* Load Monitor Section Enable Register */ | ||
42 | |||
43 | #define SPRN_PMC1 771 | ||
44 | #define SPRN_PMC2 772 | ||
45 | #define SPRN_PMC3 773 | ||
46 | #define SPRN_PMC4 774 | ||
47 | #define SPRN_PMC5 775 | ||
48 | #define SPRN_PMC6 776 | ||
49 | |||
50 | #define SPRN_SIAR 780 | ||
51 | #define SPRN_SDAR 781 | ||
52 | #define SPRN_SIER 768 | ||
53 | |||
54 | #define SPRN_TEXASR 0x82 | ||
55 | #define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */ | ||
56 | #define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */ | ||
57 | #define TEXASR_FS 0x08000000 | ||
58 | #define SPRN_TAR 0x32f | ||
59 | |||
60 | #endif /* _SELFTESTS_POWERPC_REG_H */ | ||
diff --git a/tools/testing/selftests/powerpc/signal/signal.S b/tools/testing/selftests/powerpc/signal/signal.S index 7043d521df0a..322f2f1fc327 100644 --- a/tools/testing/selftests/powerpc/signal/signal.S +++ b/tools/testing/selftests/powerpc/signal/signal.S | |||
@@ -7,7 +7,7 @@ | |||
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "../basic_asm.h" | 10 | #include "basic_asm.h" |
11 | 11 | ||
12 | /* long signal_self(pid_t pid, int sig); */ | 12 | /* long signal_self(pid_t pid, int sig); */ |
13 | FUNC_START(signal_self) | 13 | FUNC_START(signal_self) |
diff --git a/tools/testing/selftests/powerpc/stringloops/memcmp.c b/tools/testing/selftests/powerpc/stringloops/memcmp.c index 17417dd70708..30b1222380ca 100644 --- a/tools/testing/selftests/powerpc/stringloops/memcmp.c +++ b/tools/testing/selftests/powerpc/stringloops/memcmp.c | |||
@@ -1,7 +1,7 @@ | |||
1 | #include <malloc.h> | 1 | #include <malloc.h> |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include "../utils.h" | 4 | #include "utils.h" |
5 | 5 | ||
6 | #define SIZE 256 | 6 | #define SIZE 256 |
7 | #define ITERATIONS 10000 | 7 | #define ITERATIONS 10000 |
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal.S b/tools/testing/selftests/powerpc/tm/tm-signal.S index 4e13e8b3a96f..506a4ebaf3ae 100644 --- a/tools/testing/selftests/powerpc/tm/tm-signal.S +++ b/tools/testing/selftests/powerpc/tm/tm-signal.S | |||
@@ -7,11 +7,11 @@ | |||
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "../basic_asm.h" | 10 | #include "basic_asm.h" |
11 | #include "../gpr_asm.h" | 11 | #include "gpr_asm.h" |
12 | #include "../fpu_asm.h" | 12 | #include "fpu_asm.h" |
13 | #include "../vmx_asm.h" | 13 | #include "vmx_asm.h" |
14 | #include "../vsx_asm.h" | 14 | #include "vsx_asm.h" |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * Large caveat here being that the caller cannot expect the | 17 | * Large caveat here being that the caller cannot expect the |
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h index 2c8da74304e7..0ffff04433c5 100644 --- a/tools/testing/selftests/powerpc/tm/tm.h +++ b/tools/testing/selftests/powerpc/tm/tm.h | |||
@@ -10,7 +10,7 @@ | |||
10 | #include <asm/cputable.h> | 10 | #include <asm/cputable.h> |
11 | #include <stdbool.h> | 11 | #include <stdbool.h> |
12 | 12 | ||
13 | #include "../utils.h" | 13 | #include "utils.h" |
14 | 14 | ||
15 | static inline bool have_htm(void) | 15 | static inline bool have_htm(void) |
16 | { | 16 | { |
diff --git a/tools/testing/selftests/sigaltstack/.gitignore b/tools/testing/selftests/sigaltstack/.gitignore new file mode 100644 index 000000000000..35897b0a3f44 --- /dev/null +++ b/tools/testing/selftests/sigaltstack/.gitignore | |||
@@ -0,0 +1 @@ | |||
sas | |||
diff --git a/tools/testing/selftests/sync/.gitignore b/tools/testing/selftests/sync/.gitignore new file mode 100644 index 000000000000..f5091e7792f2 --- /dev/null +++ b/tools/testing/selftests/sync/.gitignore | |||
@@ -0,0 +1 @@ | |||
sync_test | |||
diff --git a/tools/testing/selftests/sync/Makefile b/tools/testing/selftests/sync/Makefile new file mode 100644 index 000000000000..87ac400507c0 --- /dev/null +++ b/tools/testing/selftests/sync/Makefile | |||
@@ -0,0 +1,24 @@ | |||
1 | CFLAGS += -O2 -g -std=gnu89 -pthread -Wall -Wextra | ||
2 | CFLAGS += -I../../../../usr/include/ | ||
3 | LDFLAGS += -pthread | ||
4 | |||
5 | TEST_PROGS = sync_test | ||
6 | |||
7 | all: $(TEST_PROGS) | ||
8 | |||
9 | include ../lib.mk | ||
10 | |||
11 | OBJS = sync_test.o sync.o | ||
12 | |||
13 | TESTS += sync_alloc.o | ||
14 | TESTS += sync_fence.o | ||
15 | TESTS += sync_merge.o | ||
16 | TESTS += sync_wait.o | ||
17 | TESTS += sync_stress_parallelism.o | ||
18 | TESTS += sync_stress_consumer.o | ||
19 | TESTS += sync_stress_merge.o | ||
20 | |||
21 | sync_test: $(OBJS) $(TESTS) | ||
22 | |||
23 | clean: | ||
24 | $(RM) sync_test $(OBJS) $(TESTS) | ||
diff --git a/tools/testing/selftests/sync/sw_sync.h b/tools/testing/selftests/sync/sw_sync.h new file mode 100644 index 000000000000..e2cfc6bad83e --- /dev/null +++ b/tools/testing/selftests/sync/sw_sync.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * sw_sync abstraction | ||
3 | * | ||
4 | * Copyright 2015-2016 Collabora Ltd. | ||
5 | * | ||
6 | * Based on the implementation from the Android Open Source Project, | ||
7 | * | ||
8 | * Copyright 2013 Google, Inc | ||
9 | * | ||
10 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
11 | * copy of this software and associated documentation files (the "Software"), | ||
12 | * to deal in the Software without restriction, including without limitation | ||
13 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
14 | * and/or sell copies of the Software, and to permit persons to whom the | ||
15 | * Software is furnished to do so, subject to the following conditions: | ||
16 | * | ||
17 | * The above copyright notice and this permission notice shall be included in | ||
18 | * all copies or substantial portions of the Software. | ||
19 | * | ||
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
23 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
24 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
25 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
26 | * OTHER DEALINGS IN THE SOFTWARE. | ||
27 | */ | ||
28 | |||
29 | #ifndef SELFTESTS_SW_SYNC_H | ||
30 | #define SELFTESTS_SW_SYNC_H | ||
31 | |||
32 | /* | ||
33 | * sw_sync is mainly intended for testing and should not be compiled into | ||
34 | * production kernels | ||
35 | */ | ||
36 | |||
37 | int sw_sync_timeline_create(void); | ||
38 | int sw_sync_timeline_is_valid(int fd); | ||
39 | int sw_sync_timeline_inc(int fd, unsigned int count); | ||
40 | void sw_sync_timeline_destroy(int fd); | ||
41 | |||
42 | int sw_sync_fence_create(int fd, const char *name, unsigned int value); | ||
43 | int sw_sync_fence_is_valid(int fd); | ||
44 | void sw_sync_fence_destroy(int fd); | ||
45 | |||
46 | #endif | ||
diff --git a/tools/testing/selftests/sync/sync.c b/tools/testing/selftests/sync/sync.c new file mode 100644 index 000000000000..f3d599f249b9 --- /dev/null +++ b/tools/testing/selftests/sync/sync.c | |||
@@ -0,0 +1,221 @@ | |||
1 | /* | ||
2 | * sync / sw_sync abstraction | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include <fcntl.h> | ||
29 | #include <malloc.h> | ||
30 | #include <poll.h> | ||
31 | #include <stdint.h> | ||
32 | #include <string.h> | ||
33 | #include <unistd.h> | ||
34 | |||
35 | #include <sys/ioctl.h> | ||
36 | #include <sys/stat.h> | ||
37 | #include <sys/types.h> | ||
38 | |||
39 | #include "sync.h" | ||
40 | #include "sw_sync.h" | ||
41 | |||
42 | #include <linux/sync_file.h> | ||
43 | |||
44 | |||
45 | /* SW_SYNC ioctls */ | ||
46 | struct sw_sync_create_fence_data { | ||
47 | __u32 value; | ||
48 | char name[32]; | ||
49 | __s32 fence; | ||
50 | }; | ||
51 | |||
52 | #define SW_SYNC_IOC_MAGIC 'W' | ||
53 | #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ | ||
54 | struct sw_sync_create_fence_data) | ||
55 | #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) | ||
56 | |||
57 | |||
58 | int sync_wait(int fd, int timeout) | ||
59 | { | ||
60 | struct pollfd fds; | ||
61 | |||
62 | fds.fd = fd; | ||
63 | fds.events = POLLIN | POLLERR; | ||
64 | |||
65 | return poll(&fds, 1, timeout); | ||
66 | } | ||
67 | |||
68 | int sync_merge(const char *name, int fd1, int fd2) | ||
69 | { | ||
70 | struct sync_merge_data data = {}; | ||
71 | int err; | ||
72 | |||
73 | data.fd2 = fd2; | ||
74 | strncpy(data.name, name, sizeof(data.name) - 1); | ||
75 | data.name[sizeof(data.name) - 1] = '\0'; | ||
76 | |||
77 | err = ioctl(fd1, SYNC_IOC_MERGE, &data); | ||
78 | if (err < 0) | ||
79 | return err; | ||
80 | |||
81 | return data.fence; | ||
82 | } | ||
83 | |||
84 | static struct sync_file_info *sync_file_info(int fd) | ||
85 | { | ||
86 | struct sync_file_info *info; | ||
87 | struct sync_fence_info *fence_info; | ||
88 | int err, num_fences; | ||
89 | |||
90 | info = calloc(1, sizeof(*info)); | ||
91 | if (info == NULL) | ||
92 | return NULL; | ||
93 | |||
94 | err = ioctl(fd, SYNC_IOC_FILE_INFO, info); | ||
95 | if (err < 0) { | ||
96 | free(info); | ||
97 | return NULL; | ||
98 | } | ||
99 | |||
100 | num_fences = info->num_fences; | ||
101 | |||
102 | if (num_fences) { | ||
103 | info->flags = 0; | ||
104 | info->num_fences = num_fences; | ||
105 | |||
106 | fence_info = calloc(num_fences, sizeof(*fence_info)); | ||
107 | if (!fence_info) { | ||
108 | free(info); | ||
109 | return NULL; | ||
110 | } | ||
111 | |||
112 | info->sync_fence_info = (uint64_t)fence_info; | ||
113 | |||
114 | err = ioctl(fd, SYNC_IOC_FILE_INFO, info); | ||
115 | if (err < 0) { | ||
116 | free(fence_info); | ||
117 | free(info); | ||
118 | return NULL; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | return info; | ||
123 | } | ||
124 | |||
125 | static void sync_file_info_free(struct sync_file_info *info) | ||
126 | { | ||
127 | free((void *)info->sync_fence_info); | ||
128 | free(info); | ||
129 | } | ||
130 | |||
131 | int sync_fence_size(int fd) | ||
132 | { | ||
133 | int count; | ||
134 | struct sync_file_info *info = sync_file_info(fd); | ||
135 | |||
136 | if (!info) | ||
137 | return 0; | ||
138 | |||
139 | count = info->num_fences; | ||
140 | |||
141 | sync_file_info_free(info); | ||
142 | |||
143 | return count; | ||
144 | } | ||
145 | |||
146 | int sync_fence_count_with_status(int fd, int status) | ||
147 | { | ||
148 | unsigned int i, count = 0; | ||
149 | struct sync_fence_info *fence_info = NULL; | ||
150 | struct sync_file_info *info = sync_file_info(fd); | ||
151 | |||
152 | if (!info) | ||
153 | return -1; | ||
154 | |||
155 | fence_info = (struct sync_fence_info *)info->sync_fence_info; | ||
156 | for (i = 0 ; i < info->num_fences ; i++) { | ||
157 | if (fence_info[i].status == status) | ||
158 | count++; | ||
159 | } | ||
160 | |||
161 | sync_file_info_free(info); | ||
162 | |||
163 | return count; | ||
164 | } | ||
165 | |||
166 | int sw_sync_timeline_create(void) | ||
167 | { | ||
168 | return open("/sys/kernel/debug/sync/sw_sync", O_RDWR); | ||
169 | } | ||
170 | |||
171 | int sw_sync_timeline_inc(int fd, unsigned int count) | ||
172 | { | ||
173 | __u32 arg = count; | ||
174 | |||
175 | return ioctl(fd, SW_SYNC_IOC_INC, &arg); | ||
176 | } | ||
177 | |||
178 | int sw_sync_timeline_is_valid(int fd) | ||
179 | { | ||
180 | int status; | ||
181 | |||
182 | if (fd == -1) | ||
183 | return 0; | ||
184 | |||
185 | status = fcntl(fd, F_GETFD, 0); | ||
186 | return (status >= 0); | ||
187 | } | ||
188 | |||
189 | void sw_sync_timeline_destroy(int fd) | ||
190 | { | ||
191 | if (sw_sync_timeline_is_valid(fd)) | ||
192 | close(fd); | ||
193 | } | ||
194 | |||
195 | int sw_sync_fence_create(int fd, const char *name, unsigned int value) | ||
196 | { | ||
197 | struct sw_sync_create_fence_data data = {}; | ||
198 | int err; | ||
199 | |||
200 | data.value = value; | ||
201 | strncpy(data.name, name, sizeof(data.name) - 1); | ||
202 | data.name[sizeof(data.name) - 1] = '\0'; | ||
203 | |||
204 | err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data); | ||
205 | if (err < 0) | ||
206 | return err; | ||
207 | |||
208 | return data.fence; | ||
209 | } | ||
210 | |||
211 | int sw_sync_fence_is_valid(int fd) | ||
212 | { | ||
213 | /* Same code! */ | ||
214 | return sw_sync_timeline_is_valid(fd); | ||
215 | } | ||
216 | |||
217 | void sw_sync_fence_destroy(int fd) | ||
218 | { | ||
219 | if (sw_sync_fence_is_valid(fd)) | ||
220 | close(fd); | ||
221 | } | ||
diff --git a/tools/testing/selftests/sync/sync.h b/tools/testing/selftests/sync/sync.h new file mode 100644 index 000000000000..fb7156148350 --- /dev/null +++ b/tools/testing/selftests/sync/sync.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * sync abstraction | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #ifndef SELFTESTS_SYNC_H | ||
29 | #define SELFTESTS_SYNC_H | ||
30 | |||
31 | #define FENCE_STATUS_ERROR (-1) | ||
32 | #define FENCE_STATUS_ACTIVE (0) | ||
33 | #define FENCE_STATUS_SIGNALED (1) | ||
34 | |||
35 | int sync_wait(int fd, int timeout); | ||
36 | int sync_merge(const char *name, int fd1, int fd2); | ||
37 | int sync_fence_size(int fd); | ||
38 | int sync_fence_count_with_status(int fd, int status); | ||
39 | |||
40 | #endif | ||
diff --git a/tools/testing/selftests/sync/sync_alloc.c b/tools/testing/selftests/sync/sync_alloc.c new file mode 100644 index 000000000000..66a28afc05dc --- /dev/null +++ b/tools/testing/selftests/sync/sync_alloc.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * sync allocation tests | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include "sync.h" | ||
29 | #include "sw_sync.h" | ||
30 | #include "synctest.h" | ||
31 | |||
32 | int test_alloc_timeline(void) | ||
33 | { | ||
34 | int timeline, valid; | ||
35 | |||
36 | timeline = sw_sync_timeline_create(); | ||
37 | valid = sw_sync_timeline_is_valid(timeline); | ||
38 | ASSERT(valid, "Failure allocating timeline\n"); | ||
39 | |||
40 | sw_sync_timeline_destroy(timeline); | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | int test_alloc_fence(void) | ||
45 | { | ||
46 | int timeline, fence, valid; | ||
47 | |||
48 | timeline = sw_sync_timeline_create(); | ||
49 | valid = sw_sync_timeline_is_valid(timeline); | ||
50 | ASSERT(valid, "Failure allocating timeline\n"); | ||
51 | |||
52 | fence = sw_sync_fence_create(timeline, "allocFence", 1); | ||
53 | valid = sw_sync_fence_is_valid(fence); | ||
54 | ASSERT(valid, "Failure allocating fence\n"); | ||
55 | |||
56 | sw_sync_fence_destroy(fence); | ||
57 | sw_sync_timeline_destroy(timeline); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | int test_alloc_fence_negative(void) | ||
62 | { | ||
63 | int fence, timeline; | ||
64 | |||
65 | timeline = sw_sync_timeline_create(); | ||
66 | ASSERT(timeline > 0, "Failure allocating timeline\n"); | ||
67 | |||
68 | fence = sw_sync_fence_create(-1, "fence", 1); | ||
69 | ASSERT(fence < 0, "Success allocating negative fence\n"); | ||
70 | |||
71 | sw_sync_fence_destroy(fence); | ||
72 | sw_sync_timeline_destroy(timeline); | ||
73 | return 0; | ||
74 | } | ||
diff --git a/tools/testing/selftests/sync/sync_fence.c b/tools/testing/selftests/sync/sync_fence.c new file mode 100644 index 000000000000..13f175287da3 --- /dev/null +++ b/tools/testing/selftests/sync/sync_fence.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * sync fence tests with one timeline | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include "sync.h" | ||
29 | #include "sw_sync.h" | ||
30 | #include "synctest.h" | ||
31 | |||
32 | int test_fence_one_timeline_wait(void) | ||
33 | { | ||
34 | int fence, valid, ret; | ||
35 | int timeline = sw_sync_timeline_create(); | ||
36 | |||
37 | valid = sw_sync_timeline_is_valid(timeline); | ||
38 | ASSERT(valid, "Failure allocating timeline\n"); | ||
39 | |||
40 | fence = sw_sync_fence_create(timeline, "allocFence", 5); | ||
41 | valid = sw_sync_fence_is_valid(fence); | ||
42 | ASSERT(valid, "Failure allocating fence\n"); | ||
43 | |||
44 | /* Wait on fence until timeout */ | ||
45 | ret = sync_wait(fence, 0); | ||
46 | ASSERT(ret == 0, "Failure waiting on fence until timeout\n"); | ||
47 | |||
48 | /* Advance timeline from 0 -> 1 */ | ||
49 | ret = sw_sync_timeline_inc(timeline, 1); | ||
50 | ASSERT(ret == 0, "Failure advancing timeline\n"); | ||
51 | |||
52 | /* Wait on fence until timeout */ | ||
53 | ret = sync_wait(fence, 0); | ||
54 | ASSERT(ret == 0, "Failure waiting on fence until timeout\n"); | ||
55 | |||
56 | /* Signal the fence */ | ||
57 | ret = sw_sync_timeline_inc(timeline, 4); | ||
58 | ASSERT(ret == 0, "Failure signaling the fence\n"); | ||
59 | |||
60 | /* Wait successfully */ | ||
61 | ret = sync_wait(fence, 0); | ||
62 | ASSERT(ret > 0, "Failure waiting on fence\n"); | ||
63 | |||
64 | /* Go even further, and confirm wait still succeeds */ | ||
65 | ret = sw_sync_timeline_inc(timeline, 10); | ||
66 | ASSERT(ret == 0, "Failure going further\n"); | ||
67 | ret = sync_wait(fence, 0); | ||
68 | ASSERT(ret > 0, "Failure waiting ahead\n"); | ||
69 | |||
70 | sw_sync_fence_destroy(fence); | ||
71 | sw_sync_timeline_destroy(timeline); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | int test_fence_one_timeline_merge(void) | ||
77 | { | ||
78 | int a, b, c, d, valid; | ||
79 | int timeline = sw_sync_timeline_create(); | ||
80 | |||
81 | /* create fence a,b,c and then merge them all into fence d */ | ||
82 | a = sw_sync_fence_create(timeline, "allocFence", 1); | ||
83 | b = sw_sync_fence_create(timeline, "allocFence", 2); | ||
84 | c = sw_sync_fence_create(timeline, "allocFence", 3); | ||
85 | |||
86 | valid = sw_sync_fence_is_valid(a) && | ||
87 | sw_sync_fence_is_valid(b) && | ||
88 | sw_sync_fence_is_valid(c); | ||
89 | ASSERT(valid, "Failure allocating fences\n"); | ||
90 | |||
91 | d = sync_merge("mergeFence", b, a); | ||
92 | d = sync_merge("mergeFence", c, d); | ||
93 | valid = sw_sync_fence_is_valid(d); | ||
94 | ASSERT(valid, "Failure merging fences\n"); | ||
95 | |||
96 | /* confirm all fences have one active point (even d) */ | ||
97 | ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1, | ||
98 | "a has too many active fences!\n"); | ||
99 | ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1, | ||
100 | "b has too many active fences!\n"); | ||
101 | ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1, | ||
102 | "c has too many active fences!\n"); | ||
103 | ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1, | ||
104 | "d has too many active fences!\n"); | ||
105 | |||
106 | /* confirm that d is not signaled until the max of a,b,c */ | ||
107 | sw_sync_timeline_inc(timeline, 1); | ||
108 | ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_SIGNALED) == 1, | ||
109 | "a did not signal!\n"); | ||
110 | ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 1, | ||
111 | "d signaled too early!\n"); | ||
112 | |||
113 | sw_sync_timeline_inc(timeline, 1); | ||
114 | ASSERT(sync_fence_count_with_status(b, FENCE_STATUS_SIGNALED) == 1, | ||
115 | "b did not signal!\n"); | ||
116 | ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 1, | ||
117 | "d signaled too early!\n"); | ||
118 | |||
119 | sw_sync_timeline_inc(timeline, 1); | ||
120 | ASSERT(sync_fence_count_with_status(c, FENCE_STATUS_SIGNALED) == 1, | ||
121 | "c did not signal!\n"); | ||
122 | ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 0 && | ||
123 | sync_fence_count_with_status(d, FENCE_STATUS_SIGNALED) == 1, | ||
124 | "d did not signal!\n"); | ||
125 | |||
126 | sw_sync_fence_destroy(d); | ||
127 | sw_sync_fence_destroy(c); | ||
128 | sw_sync_fence_destroy(b); | ||
129 | sw_sync_fence_destroy(a); | ||
130 | sw_sync_timeline_destroy(timeline); | ||
131 | return 0; | ||
132 | } | ||
diff --git a/tools/testing/selftests/sync/sync_merge.c b/tools/testing/selftests/sync/sync_merge.c new file mode 100644 index 000000000000..8914d43395c7 --- /dev/null +++ b/tools/testing/selftests/sync/sync_merge.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * sync fence merge tests | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include "sync.h" | ||
29 | #include "sw_sync.h" | ||
30 | #include "synctest.h" | ||
31 | |||
32 | int test_fence_merge_same_fence(void) | ||
33 | { | ||
34 | int fence, valid, merged; | ||
35 | int timeline = sw_sync_timeline_create(); | ||
36 | |||
37 | valid = sw_sync_timeline_is_valid(timeline); | ||
38 | ASSERT(valid, "Failure allocating timeline\n"); | ||
39 | |||
40 | fence = sw_sync_fence_create(timeline, "allocFence", 5); | ||
41 | valid = sw_sync_fence_is_valid(fence); | ||
42 | ASSERT(valid, "Failure allocating fence\n"); | ||
43 | |||
44 | merged = sync_merge("mergeFence", fence, fence); | ||
45 | valid = sw_sync_fence_is_valid(fence); | ||
46 | ASSERT(valid, "Failure merging fence\n"); | ||
47 | |||
48 | ASSERT(sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED) == 0, | ||
49 | "fence signaled too early!\n"); | ||
50 | |||
51 | sw_sync_timeline_inc(timeline, 5); | ||
52 | ASSERT(sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED) == 1, | ||
53 | "fence did not signal!\n"); | ||
54 | |||
55 | sw_sync_fence_destroy(merged); | ||
56 | sw_sync_fence_destroy(fence); | ||
57 | sw_sync_timeline_destroy(timeline); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
diff --git a/tools/testing/selftests/sync/sync_stress_consumer.c b/tools/testing/selftests/sync/sync_stress_consumer.c new file mode 100644 index 000000000000..d9eff8d524f7 --- /dev/null +++ b/tools/testing/selftests/sync/sync_stress_consumer.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * sync stress test: producer/consumer | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include <pthread.h> | ||
29 | |||
30 | #include "sync.h" | ||
31 | #include "sw_sync.h" | ||
32 | #include "synctest.h" | ||
33 | |||
34 | /* IMPORTANT NOTE: if you see this test failing on your system, it may be | ||
35 | * due to a shortage of file descriptors. Please ensure your system has | ||
36 | * a sensible limit for this test to finish correctly. | ||
37 | */ | ||
38 | |||
39 | /* Returns 1 on error, 0 on success */ | ||
40 | static int busy_wait_on_fence(int fence) | ||
41 | { | ||
42 | int error, active; | ||
43 | |||
44 | do { | ||
45 | error = sync_fence_count_with_status(fence, FENCE_STATUS_ERROR); | ||
46 | ASSERT(error == 0, "Error occurred on fence\n"); | ||
47 | active = sync_fence_count_with_status(fence, | ||
48 | FENCE_STATUS_ACTIVE); | ||
49 | } while (active); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static struct { | ||
55 | int iterations; | ||
56 | int threads; | ||
57 | int counter; | ||
58 | int consumer_timeline; | ||
59 | int *producer_timelines; | ||
60 | pthread_mutex_t lock; | ||
61 | } test_data_mpsc; | ||
62 | |||
63 | static int mpsc_producer_thread(void *d) | ||
64 | { | ||
65 | int id = (long)d; | ||
66 | int fence, valid, i; | ||
67 | int *producer_timelines = test_data_mpsc.producer_timelines; | ||
68 | int consumer_timeline = test_data_mpsc.consumer_timeline; | ||
69 | int iterations = test_data_mpsc.iterations; | ||
70 | |||
71 | for (i = 0; i < iterations; i++) { | ||
72 | fence = sw_sync_fence_create(consumer_timeline, "fence", i); | ||
73 | valid = sw_sync_fence_is_valid(fence); | ||
74 | ASSERT(valid, "Failure creating fence\n"); | ||
75 | |||
76 | /* | ||
77 | * Wait for the consumer to finish. Use alternate | ||
78 | * means of waiting on the fence | ||
79 | */ | ||
80 | |||
81 | if ((iterations + id) % 8 != 0) { | ||
82 | ASSERT(sync_wait(fence, -1) > 0, | ||
83 | "Failure waiting on fence\n"); | ||
84 | } else { | ||
85 | ASSERT(busy_wait_on_fence(fence) == 0, | ||
86 | "Failure waiting on fence\n"); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Every producer increments the counter, the consumer | ||
91 | * checks and erases it | ||
92 | */ | ||
93 | pthread_mutex_lock(&test_data_mpsc.lock); | ||
94 | test_data_mpsc.counter++; | ||
95 | pthread_mutex_unlock(&test_data_mpsc.lock); | ||
96 | |||
97 | ASSERT(sw_sync_timeline_inc(producer_timelines[id], 1) == 0, | ||
98 | "Error advancing producer timeline\n"); | ||
99 | |||
100 | sw_sync_fence_destroy(fence); | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int mpcs_consumer_thread(void) | ||
107 | { | ||
108 | int fence, merged, tmp, valid, it, i; | ||
109 | int *producer_timelines = test_data_mpsc.producer_timelines; | ||
110 | int consumer_timeline = test_data_mpsc.consumer_timeline; | ||
111 | int iterations = test_data_mpsc.iterations; | ||
112 | int n = test_data_mpsc.threads; | ||
113 | |||
114 | for (it = 1; it <= iterations; it++) { | ||
115 | fence = sw_sync_fence_create(producer_timelines[0], "name", it); | ||
116 | for (i = 1; i < n; i++) { | ||
117 | tmp = sw_sync_fence_create(producer_timelines[i], | ||
118 | "name", it); | ||
119 | merged = sync_merge("name", tmp, fence); | ||
120 | sw_sync_fence_destroy(tmp); | ||
121 | sw_sync_fence_destroy(fence); | ||
122 | fence = merged; | ||
123 | } | ||
124 | |||
125 | valid = sw_sync_fence_is_valid(fence); | ||
126 | ASSERT(valid, "Failure merging fences\n"); | ||
127 | |||
128 | /* | ||
129 | * Make sure we see an increment from every producer thread. | ||
130 | * Vary the means by which we wait. | ||
131 | */ | ||
132 | if (iterations % 8 != 0) { | ||
133 | ASSERT(sync_wait(fence, -1) > 0, | ||
134 | "Producers did not increment as expected\n"); | ||
135 | } else { | ||
136 | ASSERT(busy_wait_on_fence(fence) == 0, | ||
137 | "Producers did not increment as expected\n"); | ||
138 | } | ||
139 | |||
140 | ASSERT(test_data_mpsc.counter == n * it, | ||
141 | "Counter value mismatch!\n"); | ||
142 | |||
143 | /* Release the producer threads */ | ||
144 | ASSERT(sw_sync_timeline_inc(consumer_timeline, 1) == 0, | ||
145 | "Failure releasing producer threads\n"); | ||
146 | |||
147 | sw_sync_fence_destroy(fence); | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | int test_consumer_stress_multi_producer_single_consumer(void) | ||
154 | { | ||
155 | int iterations = 1 << 12; | ||
156 | int n = 5; | ||
157 | long i, ret; | ||
158 | int producer_timelines[n]; | ||
159 | int consumer_timeline; | ||
160 | pthread_t threads[n]; | ||
161 | |||
162 | consumer_timeline = sw_sync_timeline_create(); | ||
163 | for (i = 0; i < n; i++) | ||
164 | producer_timelines[i] = sw_sync_timeline_create(); | ||
165 | |||
166 | test_data_mpsc.producer_timelines = producer_timelines; | ||
167 | test_data_mpsc.consumer_timeline = consumer_timeline; | ||
168 | test_data_mpsc.iterations = iterations; | ||
169 | test_data_mpsc.threads = n; | ||
170 | test_data_mpsc.counter = 0; | ||
171 | pthread_mutex_init(&test_data_mpsc.lock, NULL); | ||
172 | |||
173 | for (i = 0; i < n; i++) { | ||
174 | pthread_create(&threads[i], NULL, (void * (*)(void *)) | ||
175 | mpsc_producer_thread, (void *)i); | ||
176 | } | ||
177 | |||
178 | /* Consumer thread runs here */ | ||
179 | ret = mpcs_consumer_thread(); | ||
180 | |||
181 | for (i = 0; i < n; i++) | ||
182 | pthread_join(threads[i], NULL); | ||
183 | |||
184 | return ret; | ||
185 | } | ||
diff --git a/tools/testing/selftests/sync/sync_stress_merge.c b/tools/testing/selftests/sync/sync_stress_merge.c new file mode 100644 index 000000000000..99e83ef45fbf --- /dev/null +++ b/tools/testing/selftests/sync/sync_stress_merge.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * sync stress test: merging | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <string.h> | ||
30 | #include <time.h> | ||
31 | |||
32 | #include "sync.h" | ||
33 | #include "sw_sync.h" | ||
34 | #include "synctest.h" | ||
35 | |||
36 | int test_merge_stress_random_merge(void) | ||
37 | { | ||
38 | int i, size, ret; | ||
39 | int timeline_count = 32; | ||
40 | int merge_count = 1024 * 32; | ||
41 | int timelines[timeline_count]; | ||
42 | int fence_map[timeline_count]; | ||
43 | int fence, tmpfence, merged, valid; | ||
44 | int timeline, timeline_offset, sync_point; | ||
45 | |||
46 | srand(time(NULL)); | ||
47 | |||
48 | for (i = 0; i < timeline_count; i++) | ||
49 | timelines[i] = sw_sync_timeline_create(); | ||
50 | |||
51 | fence = sw_sync_fence_create(timelines[0], "fence", 0); | ||
52 | valid = sw_sync_fence_is_valid(fence); | ||
53 | ASSERT(valid, "Failure creating fence\n"); | ||
54 | |||
55 | memset(fence_map, -1, sizeof(fence_map)); | ||
56 | fence_map[0] = 0; | ||
57 | |||
58 | /* | ||
59 | * Randomly create sync_points out of a fixed set of timelines, | ||
60 | * and merge them together | ||
61 | */ | ||
62 | for (i = 0; i < merge_count; i++) { | ||
63 | /* Generate sync_point. */ | ||
64 | timeline_offset = rand() % timeline_count; | ||
65 | timeline = timelines[timeline_offset]; | ||
66 | sync_point = rand(); | ||
67 | |||
68 | /* Keep track of the latest sync_point in each timeline. */ | ||
69 | if (fence_map[timeline_offset] == -1) | ||
70 | fence_map[timeline_offset] = sync_point; | ||
71 | else if (fence_map[timeline_offset] < sync_point) | ||
72 | fence_map[timeline_offset] = sync_point; | ||
73 | |||
74 | /* Merge */ | ||
75 | tmpfence = sw_sync_fence_create(timeline, "fence", sync_point); | ||
76 | merged = sync_merge("merge", tmpfence, fence); | ||
77 | sw_sync_fence_destroy(tmpfence); | ||
78 | sw_sync_fence_destroy(fence); | ||
79 | fence = merged; | ||
80 | |||
81 | valid = sw_sync_fence_is_valid(merged); | ||
82 | ASSERT(valid, "Failure creating fence i\n"); | ||
83 | } | ||
84 | |||
85 | size = 0; | ||
86 | for (i = 0; i < timeline_count; i++) | ||
87 | if (fence_map[i] != -1) | ||
88 | size++; | ||
89 | |||
90 | /* Confirm our map matches the fence. */ | ||
91 | ASSERT(sync_fence_size(fence) == size, | ||
92 | "Quantity of elements not matching\n"); | ||
93 | |||
94 | /* Trigger the merged fence */ | ||
95 | for (i = 0; i < timeline_count; i++) { | ||
96 | if (fence_map[i] != -1) { | ||
97 | ret = sync_wait(fence, 0); | ||
98 | ASSERT(ret == 0, | ||
99 | "Failure waiting on fence until timeout\n"); | ||
100 | /* Increment the timeline to the last sync_point */ | ||
101 | sw_sync_timeline_inc(timelines[i], fence_map[i]); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | /* Check that the fence is triggered. */ | ||
106 | ret = sync_wait(fence, 0); | ||
107 | ASSERT(ret > 0, "Failure triggering fence\n"); | ||
108 | |||
109 | sw_sync_fence_destroy(fence); | ||
110 | |||
111 | for (i = 0; i < timeline_count; i++) | ||
112 | sw_sync_timeline_destroy(timelines[i]); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
diff --git a/tools/testing/selftests/sync/sync_stress_parallelism.c b/tools/testing/selftests/sync/sync_stress_parallelism.c new file mode 100644 index 000000000000..e6c9be671dfc --- /dev/null +++ b/tools/testing/selftests/sync/sync_stress_parallelism.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * sync stress test: parallelism | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include <pthread.h> | ||
29 | |||
30 | #include "sync.h" | ||
31 | #include "sw_sync.h" | ||
32 | #include "synctest.h" | ||
33 | |||
34 | static struct { | ||
35 | int iterations; | ||
36 | int timeline; | ||
37 | int counter; | ||
38 | } test_data_two_threads; | ||
39 | |||
40 | static int test_stress_two_threads_shared_timeline_thread(void *d) | ||
41 | { | ||
42 | int thread_id = (long)d; | ||
43 | int timeline = test_data_two_threads.timeline; | ||
44 | int iterations = test_data_two_threads.iterations; | ||
45 | int fence, valid, ret, i; | ||
46 | |||
47 | for (i = 0; i < iterations; i++) { | ||
48 | fence = sw_sync_fence_create(timeline, "fence", | ||
49 | i * 2 + thread_id); | ||
50 | valid = sw_sync_fence_is_valid(fence); | ||
51 | ASSERT(valid, "Failure allocating fence\n"); | ||
52 | |||
53 | /* Wait on the prior thread to complete */ | ||
54 | ret = sync_wait(fence, -1); | ||
55 | ASSERT(ret > 0, "Problem occurred on prior thread\n"); | ||
56 | |||
57 | /* | ||
58 | * Confirm the previous thread's writes are visible | ||
59 | * and then increment | ||
60 | */ | ||
61 | ASSERT(test_data_two_threads.counter == i * 2 + thread_id, | ||
62 | "Counter got damaged!\n"); | ||
63 | test_data_two_threads.counter++; | ||
64 | |||
65 | /* Kick off the other thread */ | ||
66 | ret = sw_sync_timeline_inc(timeline, 1); | ||
67 | ASSERT(ret == 0, "Advancing timeline failed\n"); | ||
68 | |||
69 | sw_sync_fence_destroy(fence); | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | int test_stress_two_threads_shared_timeline(void) | ||
76 | { | ||
77 | pthread_t a, b; | ||
78 | int valid; | ||
79 | int timeline = sw_sync_timeline_create(); | ||
80 | |||
81 | valid = sw_sync_timeline_is_valid(timeline); | ||
82 | ASSERT(valid, "Failure allocating timeline\n"); | ||
83 | |||
84 | test_data_two_threads.iterations = 1 << 16; | ||
85 | test_data_two_threads.counter = 0; | ||
86 | test_data_two_threads.timeline = timeline; | ||
87 | |||
88 | /* | ||
89 | * Use a single timeline to synchronize two threads | ||
90 | * hammmering on the same counter. | ||
91 | */ | ||
92 | |||
93 | pthread_create(&a, NULL, (void *(*)(void *)) | ||
94 | test_stress_two_threads_shared_timeline_thread, | ||
95 | (void *)0); | ||
96 | pthread_create(&b, NULL, (void *(*)(void *)) | ||
97 | test_stress_two_threads_shared_timeline_thread, | ||
98 | (void *)1); | ||
99 | |||
100 | pthread_join(a, NULL); | ||
101 | pthread_join(b, NULL); | ||
102 | |||
103 | /* make sure the threads did not trample on one another */ | ||
104 | ASSERT(test_data_two_threads.counter == | ||
105 | test_data_two_threads.iterations * 2, | ||
106 | "Counter has unexpected value\n"); | ||
107 | |||
108 | sw_sync_timeline_destroy(timeline); | ||
109 | |||
110 | return 0; | ||
111 | } | ||
diff --git a/tools/testing/selftests/sync/sync_test.c b/tools/testing/selftests/sync/sync_test.c new file mode 100644 index 000000000000..9ea08d9f0b13 --- /dev/null +++ b/tools/testing/selftests/sync/sync_test.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * sync test runner | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include <stdio.h> | ||
29 | #include <unistd.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <sys/types.h> | ||
32 | #include <sys/wait.h> | ||
33 | |||
34 | #include "synctest.h" | ||
35 | |||
36 | static int run_test(int (*test)(void), char *name) | ||
37 | { | ||
38 | int result; | ||
39 | pid_t childpid; | ||
40 | |||
41 | fflush(stdout); | ||
42 | childpid = fork(); | ||
43 | |||
44 | if (childpid) { | ||
45 | waitpid(childpid, &result, 0); | ||
46 | if (WIFEXITED(result)) | ||
47 | return WEXITSTATUS(result); | ||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | printf("[RUN]\tExecuting %s\n", name); | ||
52 | exit(test()); | ||
53 | } | ||
54 | |||
55 | int main(void) | ||
56 | { | ||
57 | int err = 0; | ||
58 | |||
59 | printf("[RUN]\tTesting sync framework\n"); | ||
60 | |||
61 | err += RUN_TEST(test_alloc_timeline); | ||
62 | err += RUN_TEST(test_alloc_fence); | ||
63 | err += RUN_TEST(test_alloc_fence_negative); | ||
64 | |||
65 | err += RUN_TEST(test_fence_one_timeline_wait); | ||
66 | err += RUN_TEST(test_fence_one_timeline_merge); | ||
67 | err += RUN_TEST(test_fence_merge_same_fence); | ||
68 | err += RUN_TEST(test_fence_multi_timeline_wait); | ||
69 | err += RUN_TEST(test_stress_two_threads_shared_timeline); | ||
70 | err += RUN_TEST(test_consumer_stress_multi_producer_single_consumer); | ||
71 | err += RUN_TEST(test_merge_stress_random_merge); | ||
72 | |||
73 | if (err) | ||
74 | printf("[FAIL]\tsync errors: %d\n", err); | ||
75 | else | ||
76 | printf("[OK]\tsync\n"); | ||
77 | |||
78 | return !!err; | ||
79 | } | ||
diff --git a/tools/testing/selftests/sync/sync_wait.c b/tools/testing/selftests/sync/sync_wait.c new file mode 100644 index 000000000000..d69b752f6550 --- /dev/null +++ b/tools/testing/selftests/sync/sync_wait.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * sync fence wait tests | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include "sync.h" | ||
29 | #include "sw_sync.h" | ||
30 | #include "synctest.h" | ||
31 | |||
32 | int test_fence_multi_timeline_wait(void) | ||
33 | { | ||
34 | int timelineA, timelineB, timelineC; | ||
35 | int fenceA, fenceB, fenceC, merged; | ||
36 | int valid, active, signaled, ret; | ||
37 | |||
38 | timelineA = sw_sync_timeline_create(); | ||
39 | timelineB = sw_sync_timeline_create(); | ||
40 | timelineC = sw_sync_timeline_create(); | ||
41 | |||
42 | fenceA = sw_sync_fence_create(timelineA, "fenceA", 5); | ||
43 | fenceB = sw_sync_fence_create(timelineB, "fenceB", 5); | ||
44 | fenceC = sw_sync_fence_create(timelineC, "fenceC", 5); | ||
45 | |||
46 | merged = sync_merge("mergeFence", fenceB, fenceA); | ||
47 | merged = sync_merge("mergeFence", fenceC, merged); | ||
48 | |||
49 | valid = sw_sync_fence_is_valid(merged); | ||
50 | ASSERT(valid, "Failure merging fence from various timelines\n"); | ||
51 | |||
52 | /* Confirm fence isn't signaled */ | ||
53 | active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE); | ||
54 | ASSERT(active == 3, "Fence signaled too early!\n"); | ||
55 | |||
56 | ret = sync_wait(merged, 0); | ||
57 | ASSERT(ret == 0, | ||
58 | "Failure waiting on fence until timeout\n"); | ||
59 | |||
60 | ret = sw_sync_timeline_inc(timelineA, 5); | ||
61 | active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE); | ||
62 | signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED); | ||
63 | ASSERT(active == 2 && signaled == 1, | ||
64 | "Fence did not signal properly!\n"); | ||
65 | |||
66 | ret = sw_sync_timeline_inc(timelineB, 5); | ||
67 | active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE); | ||
68 | signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED); | ||
69 | ASSERT(active == 1 && signaled == 2, | ||
70 | "Fence did not signal properly!\n"); | ||
71 | |||
72 | ret = sw_sync_timeline_inc(timelineC, 5); | ||
73 | active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE); | ||
74 | signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED); | ||
75 | ASSERT(active == 0 && signaled == 3, | ||
76 | "Fence did not signal properly!\n"); | ||
77 | |||
78 | /* confirm you can successfully wait */ | ||
79 | ret = sync_wait(merged, 100); | ||
80 | ASSERT(ret > 0, "Failure waiting on signaled fence\n"); | ||
81 | |||
82 | sw_sync_fence_destroy(merged); | ||
83 | sw_sync_fence_destroy(fenceC); | ||
84 | sw_sync_fence_destroy(fenceB); | ||
85 | sw_sync_fence_destroy(fenceA); | ||
86 | sw_sync_timeline_destroy(timelineC); | ||
87 | sw_sync_timeline_destroy(timelineB); | ||
88 | sw_sync_timeline_destroy(timelineA); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
diff --git a/tools/testing/selftests/sync/synctest.h b/tools/testing/selftests/sync/synctest.h new file mode 100644 index 000000000000..e7d1d57dba7a --- /dev/null +++ b/tools/testing/selftests/sync/synctest.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * sync tests | ||
3 | * Copyright 2015-2016 Collabora Ltd. | ||
4 | * | ||
5 | * Based on the implementation from the Android Open Source Project, | ||
6 | * | ||
7 | * Copyright 2012 Google, Inc | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | * OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #ifndef SELFTESTS_SYNCTEST_H | ||
29 | #define SELFTESTS_SYNCTEST_H | ||
30 | |||
31 | #include <stdio.h> | ||
32 | |||
33 | #define ASSERT(cond, msg) do { \ | ||
34 | if (!(cond)) { \ | ||
35 | printf("[ERROR]\t%s", (msg)); \ | ||
36 | return 1; \ | ||
37 | } \ | ||
38 | } while (0) | ||
39 | |||
40 | #define RUN_TEST(x) run_test((x), #x) | ||
41 | |||
42 | /* Allocation tests */ | ||
43 | int test_alloc_timeline(void); | ||
44 | int test_alloc_fence(void); | ||
45 | int test_alloc_fence_negative(void); | ||
46 | |||
47 | /* Fence tests with one timeline */ | ||
48 | int test_fence_one_timeline_wait(void); | ||
49 | int test_fence_one_timeline_merge(void); | ||
50 | |||
51 | /* Fence merge tests */ | ||
52 | int test_fence_merge_same_fence(void); | ||
53 | |||
54 | /* Fence wait tests */ | ||
55 | int test_fence_multi_timeline_wait(void); | ||
56 | |||
57 | /* Stress test - parallelism */ | ||
58 | int test_stress_two_threads_shared_timeline(void); | ||
59 | |||
60 | /* Stress test - consumer */ | ||
61 | int test_consumer_stress_multi_producer_single_consumer(void); | ||
62 | |||
63 | /* Stress test - merging */ | ||
64 | int test_merge_stress_random_merge(void); | ||
65 | |||
66 | #endif | ||
diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore index 68f3fc71ac44..cc986621f512 100644 --- a/tools/testing/selftests/timers/.gitignore +++ b/tools/testing/selftests/timers/.gitignore | |||
@@ -17,3 +17,4 @@ skew_consistency | |||
17 | threadtest | 17 | threadtest |
18 | valid-adjtimex | 18 | valid-adjtimex |
19 | adjtick | 19 | adjtick |
20 | set-tz | ||
diff --git a/tools/usb/usbip/.gitignore b/tools/usb/usbip/.gitignore index 9aad9e30a8ba..03b892c8bd8c 100644 --- a/tools/usb/usbip/.gitignore +++ b/tools/usb/usbip/.gitignore | |||
@@ -2,6 +2,7 @@ Makefile | |||
2 | Makefile.in | 2 | Makefile.in |
3 | aclocal.m4 | 3 | aclocal.m4 |
4 | autom4te.cache/ | 4 | autom4te.cache/ |
5 | compile | ||
5 | config.guess | 6 | config.guess |
6 | config.h | 7 | config.h |
7 | config.h.in | 8 | config.h.in |
@@ -21,7 +22,10 @@ src/Makefile.in | |||
21 | stamp-h1 | 22 | stamp-h1 |
22 | libsrc/libusbip.la | 23 | libsrc/libusbip.la |
23 | libsrc/libusbip_la-names.lo | 24 | libsrc/libusbip_la-names.lo |
25 | libsrc/libusbip_la-sysfs_utils.lo | ||
24 | libsrc/libusbip_la-usbip_common.lo | 26 | libsrc/libusbip_la-usbip_common.lo |
27 | libsrc/libusbip_la-usbip_device_driver.lo | ||
28 | libsrc/libusbip_la-usbip_host_common.lo | ||
25 | libsrc/libusbip_la-usbip_host_driver.lo | 29 | libsrc/libusbip_la-usbip_host_driver.lo |
26 | libsrc/libusbip_la-vhci_driver.lo | 30 | libsrc/libusbip_la-vhci_driver.lo |
27 | src/usbip | 31 | src/usbip |
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c index a0972dea9e6c..009afb4a3aae 100644 --- a/tools/usb/usbip/src/usbipd.c +++ b/tools/usb/usbip/src/usbipd.c | |||
@@ -398,13 +398,6 @@ static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[], | |||
398 | * (see do_standalone_mode()) */ | 398 | * (see do_standalone_mode()) */ |
399 | usbip_net_set_v6only(sock); | 399 | usbip_net_set_v6only(sock); |
400 | 400 | ||
401 | if (sock >= FD_SETSIZE) { | ||
402 | err("FD_SETSIZE: %s: sock=%d, max=%d", | ||
403 | ai_buf, sock, FD_SETSIZE); | ||
404 | close(sock); | ||
405 | continue; | ||
406 | } | ||
407 | |||
408 | ret = bind(sock, ai->ai_addr, ai->ai_addrlen); | 401 | ret = bind(sock, ai->ai_addr, ai->ai_addrlen); |
409 | if (ret < 0) { | 402 | if (ret < 0) { |
410 | err("bind: %s: %d (%s)", | 403 | err("bind: %s: %d (%s)", |
diff --git a/tools/virtio/linux/compiler.h b/tools/virtio/linux/compiler.h index 845960e1cbf2..c9ccfd42ec13 100644 --- a/tools/virtio/linux/compiler.h +++ b/tools/virtio/linux/compiler.h | |||
@@ -4,6 +4,6 @@ | |||
4 | #define WRITE_ONCE(var, val) \ | 4 | #define WRITE_ONCE(var, val) \ |
5 | (*((volatile typeof(val) *)(&(var))) = (val)) | 5 | (*((volatile typeof(val) *)(&(var))) = (val)) |
6 | 6 | ||
7 | #define READ_ONCE(var) (*((volatile typeof(val) *)(&(var)))) | 7 | #define READ_ONCE(var) (*((volatile typeof(var) *)(&(var)))) |
8 | 8 | ||
9 | #endif | 9 | #endif |
diff --git a/tools/virtio/linux/uaccess.h b/tools/virtio/linux/uaccess.h index 0a578fe18653..fa05d01b2c90 100644 --- a/tools/virtio/linux/uaccess.h +++ b/tools/virtio/linux/uaccess.h | |||
@@ -1,8 +1,9 @@ | |||
1 | #ifndef UACCESS_H | 1 | #ifndef UACCESS_H |
2 | #define UACCESS_H | 2 | #define UACCESS_H |
3 | extern void *__user_addr_min, *__user_addr_max; | ||
4 | 3 | ||
5 | #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) | 4 | #include <linux/compiler.h> |
5 | |||
6 | extern void *__user_addr_min, *__user_addr_max; | ||
6 | 7 | ||
7 | static inline void __chk_user_ptr(const volatile void *p, size_t size) | 8 | static inline void __chk_user_ptr(const volatile void *p, size_t size) |
8 | { | 9 | { |
@@ -13,7 +14,7 @@ static inline void __chk_user_ptr(const volatile void *p, size_t size) | |||
13 | ({ \ | 14 | ({ \ |
14 | typeof(ptr) __pu_ptr = (ptr); \ | 15 | typeof(ptr) __pu_ptr = (ptr); \ |
15 | __chk_user_ptr(__pu_ptr, sizeof(*__pu_ptr)); \ | 16 | __chk_user_ptr(__pu_ptr, sizeof(*__pu_ptr)); \ |
16 | ACCESS_ONCE(*(__pu_ptr)) = x; \ | 17 | WRITE_ONCE(*(__pu_ptr), x); \ |
17 | 0; \ | 18 | 0; \ |
18 | }) | 19 | }) |
19 | 20 | ||
@@ -21,7 +22,7 @@ static inline void __chk_user_ptr(const volatile void *p, size_t size) | |||
21 | ({ \ | 22 | ({ \ |
22 | typeof(ptr) __pu_ptr = (ptr); \ | 23 | typeof(ptr) __pu_ptr = (ptr); \ |
23 | __chk_user_ptr(__pu_ptr, sizeof(*__pu_ptr)); \ | 24 | __chk_user_ptr(__pu_ptr, sizeof(*__pu_ptr)); \ |
24 | x = ACCESS_ONCE(*(__pu_ptr)); \ | 25 | x = READ_ONCE(*(__pu_ptr)); \ |
25 | 0; \ | 26 | 0; \ |
26 | }) | 27 | }) |
27 | 28 | ||